DePacketizerpublic class DePacketizer extends AudioCodec
Fields Summary |
---|
private static int | OUT_BUF_SIZE | private static int | MAX_SEQ | private static Format[] | defaultSupportedOutputFormats | private boolean | bufferContinued | private boolean | frameContinued | private int | frameSize | private int | frameBegin | private int | frameOffset | private long | frameTimeStamp | private long | bufTimeStamp | private long | prevSeq | private long | outSeq | private MPAParse | mpaParse | private MPAHeader | mpaHeader | private static final boolean | debug |
Constructors Summary |
---|
public DePacketizer()
inputFormats = new Format[] { new AudioFormat(AudioFormat.MPEG_RTP) };
|
Methods Summary |
---|
public void | close()
| private boolean | copyBuffer(byte[] inData, int inOff, int inLen, javax.media.Buffer outputBuffer, int outOff)
byte[] outData = (byte[])outputBuffer.getData();
if (outData == null || outOff + inLen > outData.length) {
// will overflow buffer, get a bigger buffer
if (outOff + inLen > OUT_BUF_SIZE) {
// bigger than maximum buffer, now what?
return false;
}
byte[] newData = new byte[OUT_BUF_SIZE];
if (outOff > 0) {
System.arraycopy(outData, 0, newData, 0, outData.length);
}
outData = newData;
outputBuffer.setData(outData);
}
System.arraycopy(inData, inOff, outData, outOff, inLen);
outputBuffer.setLength(outputBuffer.getLength() + inLen);
return true;
| public int | doProcess(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer)
int id; // MPEG1 or MPEG2
int layer; // Audio layer 1, 2, or 3
int crc; // CRC present = 1
int bitrate_index; // index for constant bit rate
int sampling_index; // sampling frequency indicator
int padding_bit; // padding present = 1
int channel_index; // mono = 3, otherwise stereo
String encoding;
double sampleRate;
int channels;
if (!checkInputBuffer(inputBuffer) ) {
return BUFFER_PROCESSED_FAILED;
}
if (isEOM(inputBuffer) ) {
propagateEOM(outputBuffer);
mpaParse.reset();
return BUFFER_PROCESSED_OK;
}
byte[] inData = (byte[])inputBuffer.getData();
int inOffset = inputBuffer.getOffset();
int inLength = inputBuffer.getLength();
int packetOffset = ((inData[inOffset+2]&0xff)<<8)
+ (inData[inOffset+3]&0xff);
inOffset += 4; // skip MPEG audio specific RTP header
inLength -= 4;
if (packetOffset > 0) {
// this is a continuation of a previous frame
if (!frameContinued) {
// Not expecting a continuation, just drop it
if (debug) {
System.err.println(
"DePacketizer: Not expecting continuation, frame offset "
+ packetOffset);
}
return OUTPUT_BUFFER_NOT_FILLED;
}
if (inputBuffer.getTimeStamp() != frameTimeStamp) {
// Not part of the continuation, just drop it
if (debug) {
System.err.println(
"DePacketizer: Timestamp mismatch, expecting "
+ frameTimeStamp + " got "
+ inputBuffer.getTimeStamp());
}
dropFrame(outputBuffer);
return OUTPUT_BUFFER_NOT_FILLED;
}
if (getSequenceDiff(prevSeq, inputBuffer.getSequenceNumber())
!= 1) {
// Not part of the continuation, just drop it
if (debug) {
System.err.println(
"DePacketizer: Sequence out of order, expecting "
+ (prevSeq+1) + " got "
+ inputBuffer.getSequenceNumber());
}
dropFrame(outputBuffer);
return OUTPUT_BUFFER_NOT_FILLED;
}
prevSeq = inputBuffer.getSequenceNumber();
// copy to output buffer
if (!copyBuffer(inData, inOffset, inLength,
outputBuffer, frameBegin + frameOffset)) {
// result in buffer overflow, just drop the frame
if (debug) {
System.err.println(
"DePacketizer: Buffer overflow on continuation");
}
dropFrame(outputBuffer);
return OUTPUT_BUFFER_NOT_FILLED;
}
frameOffset += inLength;
// <=== is this all of it?
if (frameOffset < frameSize) {
return OUTPUT_BUFFER_NOT_FILLED;
}
frameContinued = false;
frameOffset = 0;
if (mpaHeader.layer == 3 && frameBegin == 0) {
// need at least 2 frames of MP3
return OUTPUT_BUFFER_NOT_FILLED;
}
outputBuffer.setTimeStamp(bufTimeStamp);
outputBuffer.setFlags(outputBuffer.getFlags()
| Buffer.FLAG_NO_DROP);
bufferContinued = false;
return BUFFER_PROCESSED_OK;
} else {
if (frameContinued) {
if (debug) {
System.err.println(
"DePacketizer: expected continuation missing "
+ inputBuffer.getSequenceNumber());
}
dropFrame(outputBuffer);
}
frameContinued = false;
if (debug &&
getSequenceDiff(prevSeq, inputBuffer.getSequenceNumber())
!= 1) {
System.err.println(
"DePacketizer: Sequence number mismatch, expecting "
+ (prevSeq + 1) + " got "
+ inputBuffer.getSequenceNumber());
}
prevSeq = inputBuffer.getSequenceNumber();
frameTimeStamp = inputBuffer.getTimeStamp();
int rc = mpaParse.getHeader(mpaHeader, inData, inOffset, inLength);
if (rc != mpaParse.MPA_OK && rc != mpaParse.MPA_HDR_DOUBTED) {
return BUFFER_PROCESSED_FAILED;
}
encoding = (mpaHeader.layer == 3) ? AudioFormat.MPEGLAYER3
: AudioFormat.MPEG;
AudioFormat af = (AudioFormat)outputFormat;
if (af == null || !(encoding.equalsIgnoreCase(af.getEncoding()))
|| af.getSampleRate() != mpaHeader.samplingRate
|| af.getChannels() != mpaHeader.nChannels) {
// Change in format occurred
outputFormat = new AudioFormat(encoding,
mpaHeader.samplingRate, 16,
mpaHeader.nChannels,
AudioFormat.BIG_ENDIAN,
AudioFormat.SIGNED);
}
frameSize = mpaHeader.bitsInFrame >> 3;
if (frameSize > inLength) {
if (!bufferContinued) {
outputBuffer.setLength(0);
outputBuffer.setOffset(0);
bufTimeStamp = frameTimeStamp;
outputBuffer.setFormat(outputFormat);
outputBuffer.setSequenceNumber(outSeq++);
}
bufferContinued = true;
frameContinued = true;
frameBegin = outputBuffer.getLength();
frameOffset = inLength;
// copy to output buffer
copyBuffer(inData, inOffset, inLength,
outputBuffer, outputBuffer.getLength());
return OUTPUT_BUFFER_NOT_FILLED;
}
}
if (mpaHeader.layer == 3 && inLength < ((frameSize * 2) - 2)) {
// Buffer up more than just one frame's worth of MP3
if (!bufferContinued) {
outputBuffer.setLength(0);
outputBuffer.setOffset(0);
bufTimeStamp = frameTimeStamp;
byte[] outData = (byte[])outputBuffer.getData();
if (outData == null || outData.length < OUT_BUF_SIZE) {
outData = new byte[OUT_BUF_SIZE];
outputBuffer.setData(outData);
}
}
// copy to output buffer
if (!copyBuffer(inData, inOffset, inLength,
outputBuffer, outputBuffer.getLength())) {
// result in buffer overflow, send what's already in buffer
outputBuffer.setFormat(outputFormat);
outputBuffer.setSequenceNumber(outSeq++);
outputBuffer.setTimeStamp(bufTimeStamp);
outputBuffer.setFlags(outputBuffer.getFlags()
| Buffer.FLAG_NO_DROP);
bufferContinued = false;
return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED;
}
// see if another frame + padding will fit, if not send
// this buffer on.
if (outputBuffer.getLength() + frameSize + 4 > OUT_BUF_SIZE) {
// another packet won't fit, send what's in buffer
outputBuffer.setFormat(outputFormat);
outputBuffer.setSequenceNumber(outSeq++);
outputBuffer.setTimeStamp(bufTimeStamp);
outputBuffer.setFlags(outputBuffer.getFlags()
| Buffer.FLAG_NO_DROP);
bufferContinued = false;
return BUFFER_PROCESSED_OK;
} else {
bufferContinued = true;
return OUTPUT_BUFFER_NOT_FILLED;
}
} else {
Object outData = outputBuffer.getData();
outputBuffer.setData(inputBuffer.getData());
inputBuffer.setData(outData);
outputBuffer.setLength(inLength);
outputBuffer.setFormat(outputFormat);
outputBuffer.setOffset(inOffset);
outputBuffer.setSequenceNumber(outSeq++);
outputBuffer.setTimeStamp(frameTimeStamp);
outputBuffer.setFlags(outputBuffer.getFlags()
| Buffer.FLAG_NO_DROP);
return BUFFER_PROCESSED_OK;
}
| private void | dropFrame(javax.media.Buffer outputBuffer)
outputBuffer.setLength(frameBegin - outputBuffer.getOffset());
frameBegin = outputBuffer.getLength() + outputBuffer.getOffset();
frameSize = 0;
frameOffset = 0;
frameContinued = false;
| public java.lang.String | getName()
return "MPEG Audio DePacketizer";
| private int | getSequenceDiff(long p, long c)
if (c > p)
return (int) (c - p);
if (c == p)
return 0;
if (p > MAX_SEQ - 100 && c < 100) {
// Allow for the case where sequence number has wrapped.
return (int) ((MAX_SEQ - p) + c + 1);
}
return (int) (c - p);
| public javax.media.Format[] | getSupportedOutputFormats(javax.media.Format in)
if (in == null) {
return defaultSupportedOutputFormats;
}
if (matches(in, inputFormats) == null) {
return new Format[1];
}
if (! (in instanceof AudioFormat) ) {
return defaultSupportedOutputFormats;
}
if (outputFormat != null) {
return new Format[] { outputFormat };
}
AudioFormat af =(AudioFormat) in;
AudioFormat of = new AudioFormat(AudioFormat.MPEG,
(af.getSampleRate() == Format.NOT_SPECIFIED
? 44100. : af.getSampleRate()),
(af.getSampleSizeInBits() == Format.NOT_SPECIFIED
? 16 : af.getSampleSizeInBits()),
(af.getChannels() == Format.NOT_SPECIFIED
? 2 : af.getChannels()));
return new Format[] { of };
| public void | open()
| public int | process(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer)
try {
return doProcess(inputBuffer, outputBuffer);
} catch (Exception ex) {
ex.printStackTrace();
}
return BUFFER_PROCESSED_FAILED;
|
|