package org.jcodec.codecs.s302;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jcodec.common.AudioCodecMeta;
import org.jcodec.common.AudioDecoder;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.model.AudioBuffer;
import org.jcodec.common.tools.MathUtil;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* SMPTE 302m decoder
*
* @author The JCodec project
*
*/
public class S302MDecoder implements AudioDecoder {
public static int SAMPLE_RATE = 48000;
public AudioBuffer decodeFrame(ByteBuffer frame, ByteBuffer dst) {
frame.order(ByteOrder.BIG_ENDIAN);
ByteBuffer dup = dst.duplicate();
int h = frame.getInt();
int frameSize = (h >> 16) & 0xffff;
if (frame.remaining() != frameSize)
throw new IllegalArgumentException("Wrong s302m frame");
int channels = ((h >> 14) & 0x0003) * 2 + 2;
int sampleSizeInBits = ((h >> 4) & 0x0003) * 4 + 16;
if (sampleSizeInBits == 24) {
int nSamples = (frame.remaining() / 7) * 2;
while (frame.remaining() > 6) {
byte c = (byte) MathUtil.reverse(frame.get() & 0xff);
byte b = (byte) MathUtil.reverse(frame.get() & 0xff);
byte a = (byte) MathUtil.reverse(frame.get() & 0xff);
int g = MathUtil.reverse(frame.get() & 0x0f);
int f = MathUtil.reverse(frame.get() & 0xff);
int e = MathUtil.reverse(frame.get() & 0xff);
int d = MathUtil.reverse(frame.get() & 0xf0);
dup.put(a);
dup.put(b);
dup.put(c);
dup.put((byte) ((d << 4) | (e >> 4)));
dup.put((byte) ((e << 4) | (f >> 4)));
dup.put((byte) ((f << 4) | (g >> 4)));
}
dup.flip();
return new AudioBuffer(dup, new AudioFormat(SAMPLE_RATE, 24, channels, true, true), nSamples / channels);
} else if (sampleSizeInBits == 20) {
int nSamples = (frame.remaining() / 6) * 2;
while (frame.remaining() > 5) {
int c = MathUtil.reverse(frame.get() & 0xff);
int b = MathUtil.reverse(frame.get() & 0xff);
int a = MathUtil.reverse(frame.get() & 0xf0);
dup.put((byte) ((a << 4) | (b >> 4)));
dup.put((byte) ((b << 4) | (c >> 4)));
dup.put((byte) (c << 4));
int cc = MathUtil.reverse(frame.get() & 0xff);
int bb = MathUtil.reverse(frame.get() & 0xff);
int aa = MathUtil.reverse(frame.get() & 0xf0);
dup.put((byte) ((aa << 4) | (bb >> 4)));
dup.put((byte) ((bb << 4) | (cc >> 4)));
dup.put((byte) (cc << 4));
}
dup.flip();
return new AudioBuffer(dup, new AudioFormat(SAMPLE_RATE, 24, channels, true, true), nSamples / channels);
} else {
int nSamples = (frame.remaining() / 5) * 2;
while (frame.remaining() > 4) {
byte bb = (byte) MathUtil.reverse(frame.get() & 0xff);
byte aa = (byte) MathUtil.reverse(frame.get() & 0xff);
int c = MathUtil.reverse(frame.get() & 0xff);
int b = MathUtil.reverse(frame.get() & 0xff);
int a = MathUtil.reverse(frame.get() & 0xf0);
dst.put(aa);
dst.put(bb);
dst.put((byte) ((a << 4) | (b >> 4)));
dst.put((byte) ((b << 4) | (c >> 4)));
}
dup.flip();
return new AudioBuffer(dup, new AudioFormat(SAMPLE_RATE, 16, channels, true, true), nSamples / channels);
}
}
@Override
public AudioCodecMeta getCodecMeta(ByteBuffer _data) throws IOException {
ByteBuffer frame = _data.duplicate();
frame.order(ByteOrder.BIG_ENDIAN);
int h = frame.getInt();
int frameSize = (h >> 16) & 0xffff;
if (frame.remaining() != frameSize)
throw new IllegalArgumentException("Wrong s302m frame");
int channels = ((h >> 14) & 0x0003) * 2 + 2;
int sampleSizeInBits = ((h >> 4) & 0x0003) * 4 + 16;
return new AudioCodecMeta(new AudioFormat(SAMPLE_RATE, sampleSizeInBits, channels, true, true));
}
}