package org.jcodec.codecs.pcmdvd;
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.io.NIOUtils;
import org.jcodec.common.model.AudioBuffer;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* PCM DVD decoder
*
* @author The JCodec project
*
*/
public class PCMDVDDecoder implements AudioDecoder {
private static final int[] lpcm_freq_tab = new int[] { 48000, 96000, 44100, 32000 };
@Override
public AudioBuffer decodeFrame(ByteBuffer _frame, ByteBuffer _dst) throws IOException {
ByteBuffer dst = _dst.duplicate();
ByteBuffer frame = _frame.duplicate();
frame.order(ByteOrder.BIG_ENDIAN);
dst.order(ByteOrder.LITTLE_ENDIAN);
int dvdaudioSubstreamType = frame.get() & 0xff;
NIOUtils.skip(frame, 3);
if ((dvdaudioSubstreamType & 0xe0) == 0xa0) {
// OK CODEC_ID_PCM_DVD
} else if ((dvdaudioSubstreamType & 0xe0) == 0x80) {
if ((dvdaudioSubstreamType & 0xf8) == 0x88)
throw new RuntimeException("CODEC_ID_DTS");
else
throw new RuntimeException("CODEC_ID_AC3");
} else
throw new RuntimeException("MPEG DVD unknown coded");
// emphasis (1), muse(1), reserved(1), frame number(5)
int b0 = frame.get() & 0xff;
// quant (2), freq(2), reserved(1), channels(3)
int b1 = frame.get() & 0xff;
// dynamic range control (0x80 = off)
int b2 = frame.get() & 0xff;
int freq = (b1 >> 4) & 3;
int sampleRate = lpcm_freq_tab[freq];
int channelCount = 1 + (b1 & 7);
int sampleSizeInBits = 16 + ((b1 >> 6) & 3) * 4;
int nFrames = frame.remaining() / (channelCount * (sampleSizeInBits >> 3));
switch (sampleSizeInBits) {
case 20:
for (int n = 0; n < (nFrames >> 1); n++) {
for (int c = 0; c < channelCount; c++) {
short s0 = frame.getShort();
dst.putShort(s0);
short s1 = frame.getShort();
dst.putShort(s1);
}
NIOUtils.skip(frame, channelCount);
}
break;
case 24:
for (int n = 0; n < (nFrames >> 1); n++) {
for (int c = 0; c < channelCount; c++) {
short s0 = frame.getShort();
dst.putShort(s0);
short s1 = frame.getShort();
dst.putShort(s1);
}
NIOUtils.skip(frame, channelCount << 1);
}
break;
}
dst.flip();
return new AudioBuffer(dst, new AudioFormat(sampleRate, sampleSizeInBits, channelCount, true, false), nFrames);
}
@Override
public AudioCodecMeta getCodecMeta(ByteBuffer _frame) throws IOException {
ByteBuffer frame = _frame.duplicate();
frame.order(ByteOrder.BIG_ENDIAN);
int dvdaudioSubstreamType = frame.get() & 0xff;
NIOUtils.skip(frame, 3);
if ((dvdaudioSubstreamType & 0xe0) == 0xa0) {
// OK CODEC_ID_PCM_DVD
} else if ((dvdaudioSubstreamType & 0xe0) == 0x80) {
if ((dvdaudioSubstreamType & 0xf8) == 0x88)
throw new RuntimeException("CODEC_ID_DTS");
else
throw new RuntimeException("CODEC_ID_AC3");
} else
throw new RuntimeException("MPEG DVD unknown coded");
// emphasis (1), muse(1), reserved(1), frame number(5)
int b0 = frame.get() & 0xff;
// quant (2), freq(2), reserved(1), channels(3)
int b1 = frame.get() & 0xff;
// dynamic range control (0x80 = off)
int b2 = frame.get() & 0xff;
int freq = (b1 >> 4) & 3;
int sampleRate = lpcm_freq_tab[freq];
int channelCount = 1 + (b1 & 7);
int sampleSizeInBits = 16 + ((b1 >> 6) & 3) * 4;
return new AudioCodecMeta(new AudioFormat(sampleRate, sampleSizeInBits, channelCount, true, false));
}
}