Methods Summary |
---|
public synchronized void | close()
reset();
|
private javax.media.Buffer | copyInto(javax.media.Buffer src)
Buffer dest = new Buffer();
dest.copy(src);
dest.setFlags(dest.getFlags() | Buffer.FLAG_NO_DROP);
src.setData(null);
src.setHeader(null);
src.setLength(0);
src.setOffset(0);
return dest;
|
private int | copySequenceHeader(javax.media.Buffer outBuffer)
if (sequenceHeader == null)
return 0;
System.arraycopy(sequenceHeader, 0,
outBuffer.getData(),
outBuffer.getLength(),
sequenceHeader.length);
outBuffer.setLength(outBuffer.getLength() + sequenceHeader.length);
return sequenceHeader.length;
|
private int | doGOP(com.sun.media.codec.video.mpeg.Packetizer$MPEGSegment gop, javax.media.Buffer outBuffer)
// byte[] gb = new byte[4];
// gop.copyData(4, 4, gb, 0);
// long gtm = ((gb[0] & 0x7c) >> 2) * 60 * 60 * 1000 * 1000000;
// gtm += ((gb[0] & 0x03) << 4 | (gb[1] & 0xf0) >> 4) * 60 * 1000
// * 1000000;
// gtm += ((gb[1] & 0x07) << 3 | (gb[2] & 0xe0) >> 5) * 1000
// * 1000000;
// long gpic = (gb[2] & 0x1f) << 1 | (gb[3] & 0x80) >> 7;
// if (gpic != 0 || gtm != 0) {
// gopTime = gtm + (gpic * picNanos);
// } else if (frameCount == 0) {
// gopTime = 1; // to get past RTPSinkStream
// }
if (frameCount == 0) {
gopTime = 1 + startTime; // to get past RTPSinkStream
} else {
gopTime = frameCount * picNanos + startTime;
}
// put a sequence header before each GOP to allow RTP clients
// to connect beginning with any GOP
copySequenceHeader(outBuffer);
gop.copyData((byte[]) outBuffer.getData(), outBuffer.getLength());
outBuffer.setLength(outBuffer.getLength() + gop.getLength());
return SEGMENT_DONE;
|
private int | doPicture(com.sun.media.codec.video.mpeg.Packetizer$MPEGSegment ph, javax.media.Buffer outBuffer)
byte[] pic = new byte[ph.getLength()];
ph.copyData(pic, 0);
int cnt = (pic[4] & 0xff) << 2 | (pic[5] & 0xc0) >> 6;
int type = (pic[5] & 0x38) >> 3;
mpegHeader[0] = (byte) ((cnt >> 8) & 0x02);
mpegHeader[1] = (byte) cnt;
mpegHeader[2] = (byte) type; // ignore N, S, B, E for now
if (type == 1) {
mpegHeader[3] = 0;
} else {
int next = (pic[7] & 0x07) << 1 | (pic[8] & 0x80) >> 7;
if (type > 2)
next |= (pic[8] & 0x78) << 1;
mpegHeader[3] = (byte) next;
}
resetInProgress = false;
byte[] outData = (byte[]) outBuffer.getData();
System.arraycopy(mpegHeader, 0, outData, 0, 4);
// by the time a picture is encountered,
// sequence header & GOP should already be copied into buffer
if (outBuffer.getLength() > 8
&& outData[4] == 0
&& outData[5] == 0
&& outData[6] == 1
&& (outData[7] & 0xff) == 0xb3) {
outData[2] |= 0x20; // set S (section header present)
}
ph.copyData((byte[]) outBuffer.getData(), outBuffer.getLength());
outBuffer.setLength(outBuffer.getLength() + ph.getLength());
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_KEY_FRAME);
frameCount++;
frameTime = gopTime + (cnt * picNanos);
outBuffer.setTimeStamp(frameTime);
outBuffer.setFormat(outputFormat);
return SEGMENT_DONE;
|
private int | doProcess(javax.media.Buffer inBuffer, javax.media.Buffer outBuffer)
if (expectingNewInput) {
if (!inputEOM) {
if (inBuffer.getData() == null) {
return OUTPUT_BUFFER_NOT_FILLED;
}
if (resetTime) {
// get the new position time from a setStartTime
startTime = inBuffer.getTimeStamp();
if (debug) {
System.err.println("Packetizer(V): new synctime set: "
+ startTime);
}
if (startTime == 0)
startTime = 1; // to get past RTPSinkStream
resetTime = false;
}
inputQueue.addElement(copyInto(inBuffer));
}
expectingNewInput = false;
}
if (expectingNewOutput) {
byte[] outData = (byte[]) outBuffer.getData();
if (outData == null || outData.length < PACKET_MAX) {
outData = new byte[PACKET_MAX];
outBuffer.setData(outData);
}
System.arraycopy(mpegHeader, 0, outData, 0, 4);
outBuffer.setOffset(0);
outBuffer.setLength(4);
outBuffer.setFlags(0);
outBuffer.setHeader(null);
outBuffer.setFormat(outputFormat);
expectingNewOutput = false;
}
if (segmentQueue.isEmpty()) {
findFirstStartCode();
if (segmentQueue.isEmpty()) {
expectingNewInput = true;
return OUTPUT_BUFFER_NOT_FILLED;
}
}
MPEGSegment mseg = (MPEGSegment) segmentQueue.firstElement();
while (mseg != null) {
if (mseg.getLength() < 0) {
// need a new input buffer to calculate length for this segment
expectingNewInput = true;
return OUTPUT_BUFFER_NOT_FILLED;
}
int startCode = mseg.startCode;
int res = 0;
if (startCode == 0xb3) { // sequence header
res = doSequenceHeader(mseg, outBuffer);
} else if (startCode == 0xb7) { // sequence end
res = doSequenceEnd(mseg, outBuffer);
} else if (startCode == 0xb8) { // GOP
res = doGOP(mseg, outBuffer);
} else if (startCode == 0) { // picture header
res = doPicture(mseg, outBuffer);
} else if (startCode >= 1 && startCode <= 0xaf) { // slice
res = doSlice(mseg, outBuffer);
} else {
// unknown start code, simply skip it
res = SEGMENT_DONE;
}
if (res == SEGMENT_DONE) {
segmentQueue.removeElementAt(0);
if (segmentQueue.isEmpty()) {
expectingNewInput = true;
if (outBuffer.getLength() > 4) {
return BUFFER_PROCESSED_OK;
} else {
return OUTPUT_BUFFER_NOT_FILLED;
}
}
mseg = (MPEGSegment) segmentQueue.firstElement();
continue;
}
if (res == SEGMENT_DONE_BUFFER_FULL) {
segmentQueue.removeElementAt(0);
// output buffer has data to be sent
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_NO_DROP);
if (expectingNewInput) {
return BUFFER_PROCESSED_OK;
}
return INPUT_BUFFER_NOT_CONSUMED;
}
if (res == SEGMENT_REPEAT) {
// output buffer has data to be sent
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_NO_DROP);
if (expectingNewInput) {
return BUFFER_PROCESSED_OK;
}
return INPUT_BUFFER_NOT_CONSUMED;
}
}
return BUFFER_PROCESSED_FAILED;
|
private int | doSequenceEnd(com.sun.media.codec.video.mpeg.Packetizer$MPEGSegment se, javax.media.Buffer outBuffer)
// se.copyData((byte[]) outBuffer.getData(), outBuffer.getLength());
// outBuffer.setLength(outBuffer.getLength() + se.getLength());
return SEGMENT_DONE;
|
private int | doSequenceHeader(com.sun.media.codec.video.mpeg.Packetizer$MPEGSegment sh, javax.media.Buffer outBuffer)
sequenceHeader = new byte[sh.getLength()];
sh.copyData(sequenceHeader, 0);
frameWidth = (sequenceHeader[4] & 0xff) << 4
| (sequenceHeader[5] & 0xf0) >> 4;
frameHeight = (sequenceHeader[5] & 0x0f) << 8
| (sequenceHeader[6] & 0xff);
int frix = (sequenceHeader[7] & 0x0f);
if (frix > 0 && frix <= 8)
frameRate = RATE_TABLE[frix];
picNanos = (long)((1000 * 1000000) / frameRate);
// int bitrate = (sequenceHeader[8] & 0xff) << 10
// | (sequenceHeader[9] & 0xff) << 2
// | (sequenceHeader[6] & 0xc0) >> 6;
return SEGMENT_DONE;
|
private int | doSlice(com.sun.media.codec.video.mpeg.Packetizer$MPEGSegment slice, javax.media.Buffer outBuffer)
byte[] outData = (byte[]) outBuffer.getData();
if (slice.getLength() < PACKET_MAX - outBuffer.getLength()) {
slice.copyData(outData, outBuffer.getLength());
outBuffer.setLength(outBuffer.getLength() + slice.getLength());
outBuffer.setTimeStamp(frameTime);
outBuffer.setFormat(outputFormat);
outData[2] |= 0x18; // set B, E (begin, end slice)
if (segmentQueue.size() > 1) {
MPEGSegment mse = (MPEGSegment) segmentQueue.elementAt(1);
if (mse.startCode < 1 || mse.startCode > 0xaf) {
outBuffer.setFlags(outBuffer.getFlags()
| Buffer.FLAG_RTP_MARKER);
expectingNewOutput = true;
return SEGMENT_DONE_BUFFER_FULL;
}
} else if (inputEOM) {
outBuffer.setFlags(outBuffer.getFlags()
| Buffer.FLAG_RTP_MARKER);
expectingNewOutput = true;
return SEGMENT_DONE_BUFFER_FULL;
}
return SEGMENT_DONE;
}
if ((outData[2] & 0x18) != 0) {
// there are slices in the buffer but this one won't fit
// send the buffer as is then come back to this slice
expectingNewOutput = true;
return SEGMENT_REPEAT;
}
int len = PACKET_MAX - outBuffer.getLength();
slice.copyData(0, len, outData, outBuffer.getLength());
outBuffer.setLength(outBuffer.getLength() + len);
outBuffer.setTimeStamp(frameTime);
outBuffer.setFormat(outputFormat);
outData[2] |= 0x10; // set B (begin slice)
int off = len;
len = slice.getLength() - len;
Buffer b = null;
// Now queue up additional output buffers to complete the slice
while (len > 0) {
b = new Buffer();
outData = new byte[PACKET_MAX];
b.setData(outData);
b.setTimeStamp(frameTime);
b.setHeader(null);
b.setFormat(outputFormat);
b.setFlags(outBuffer.getFlags());
b.setOffset(0);
System.arraycopy(mpegHeader, 0, outData, 0, 4);
int l = len;
if (len > PACKET_MAX - 4)
l = PACKET_MAX - 4;
slice.copyData(off, l, (byte[]) b.getData(), 4);
b.setLength(l + 4);
off += l;
len -= l;
if (len <= 0)
outData[2] |= 0x08; // set E (end slice)
outputQueue.addElement(b);
}
if (segmentQueue.size() > 1) {
MPEGSegment mse = (MPEGSegment) segmentQueue.elementAt(1);
if (mse.startCode < 1 || mse.startCode > 0xaf) {
b.setFlags(b.getFlags() | Buffer.FLAG_RTP_MARKER);
expectingNewOutput = true;
return SEGMENT_DONE_BUFFER_FULL;
}
} else if (inputEOM) {
b.setFlags(b.getFlags() | Buffer.FLAG_RTP_MARKER);
expectingNewOutput = true;
return SEGMENT_DONE_BUFFER_FULL;
}
expectingNewOutput = true;
return SEGMENT_DONE_BUFFER_FULL;
|
public void | finalize()
close();
|
private void | findFirstStartCode()
if (inputQueue.isEmpty())
return;
Buffer inBuffer = (Buffer) inputQueue.firstElement();
// now the buffer is in the pipe, drop it from inputQueue
inputQueue.removeElementAt(0);
byte[] inData = (byte[]) inBuffer.getData();
int off = inBuffer.getOffset();
int len = inBuffer.getLength();
while (len > 4) {
if (inData[off] == 0 && inData[off+1] == 0 && inData[off+2] == 1) {
// treat extension and user_data as part of current header
if ((inData[off+3] & 0xff) != 0xb5
&& (inData[off+3] & 0xff) != 0xb2) {
if (resetInProgress) {
// after reset, need a sequence_header_code or GOP
if ((inData[off+3] & 0xff) == 0xb3
|| (inData[off+3] & 0xff) == 0xb8) {
MPEGSegment ns =
new MPEGSegment((inData[off+3] & 0xff),
off, inBuffer);
segmentQueue.addElement(ns);
return;
}
} else {
MPEGSegment ns = new MPEGSegment((inData[off+3] & 0xff),
off, inBuffer);
segmentQueue.addElement(ns);
return;
}
}
}
off++;
len--;
}
// didn't find anything, try the next buffer
expectingNewInput = true;
|
protected javax.media.Format | getInputFormat()
return inputFormat;
|
public java.lang.String | getName()
return "MPEG Video Packetizer";
|
protected javax.media.Format | getOutputFormat()
return outputFormat;
|
public javax.media.Format[] | getSupportedOutputFormats(javax.media.Format in)
if (in == null)
return outputFormats;
// Make sure the input is MPEG video format
if (matches(in, inputFormats) == null)
return new Format[0];
Format out [] = new Format[1];
out[0] = makeMPEGFormat(in);
return out;
|
private final javax.media.format.VideoFormat | makeMPEGFormat(javax.media.Format in)
VideoFormat vf = (VideoFormat)in;
return new VideoFormat(VideoFormat.MPEG_RTP,
vf.getSize(),
VideoFormat.NOT_SPECIFIED,
Format.byteArray,
vf.getFrameRate());
|
public void | open()
if (inputFormat == null || outputFormat == null)
throw new ResourceUnavailableException(
"Incorrect formats set on MPEG converter");
startTime = 1; // to get past RTPSinkStream
frameRate = 0.0;
picNanos = 0;
sequenceNumber = 0;
resetTime = true;
|
public synchronized int | process(javax.media.Buffer inBuffer, javax.media.Buffer outBuffer)
if (outputQueue.size() > 0) {
Buffer qbuf = (Buffer) outputQueue.firstElement();
outputQueue.removeElementAt(0);
outBuffer.setData((byte[]) qbuf.getData());
outBuffer.setOffset(qbuf.getOffset());
outBuffer.setLength(qbuf.getLength());
outBuffer.setFlags(qbuf.getFlags());
outBuffer.setTimeStamp(qbuf.getTimeStamp());
outBuffer.setSequenceNumber(sequenceNumber++);
outBuffer.setFormat(outputFormat);
expectingNewOutput = true;
return INPUT_BUFFER_NOT_CONSUMED;
}
if (isEOM(inBuffer)) {
inputEOM = true;
if (segmentQueue.isEmpty()) {
propagateEOM(outBuffer);
outBuffer.setSequenceNumber(sequenceNumber++);
return BUFFER_PROCESSED_OK;
}
}
if (inBuffer.isDiscard()) {
updateOutput(outBuffer, outputFormat, 0, 0);
outBuffer.setDiscard(true);
return OUTPUT_BUFFER_NOT_FILLED;
}
int retVal = BUFFER_PROCESSED_FAILED;
try {
retVal = doProcess(inBuffer, outBuffer);
} catch (Exception ex) {
ex.printStackTrace();
return BUFFER_PROCESSED_FAILED;
}
// get the outputFormat from the buffer only if this is the first time.
if (outputFormat == null) {
outputFormat = makeMPEGFormat(inBuffer.getFormat());
}
if (retVal != OUTPUT_BUFFER_NOT_FILLED) {
outBuffer.setSequenceNumber(sequenceNumber++);
}
return retVal;
|
public void | reset()
// Anything to do?
super.reset();
outputQueue.removeAllElements();
inputQueue.removeAllElements();
segmentQueue.removeAllElements();
inputEOM = false;
expectingNewInput = true;
expectingNewOutput = true;
resetInProgress = true;
resetTime = true;
sequenceHeader = null;
frameWidth = 0;
frameHeight = 0;
mpegHeader[0] = 0;
mpegHeader[1] = 0;
mpegHeader[2] = 0;
mpegHeader[3] = 0;
gopTime = 1; // to get past RTPSinkStream
frameTime = 0;
frameCount = 0;
if (debug) {
System.err.println("Packetizer(V): reset completed");
}
|
public javax.media.Format | setInputFormat(javax.media.Format input)
inputFormat = (VideoFormat) input;
return input;
|
public javax.media.Format | setOutputFormat(javax.media.Format output)
if (!(output instanceof VideoFormat)) return null;
outputFormat = makeMPEGFormat(output);
return output;
|
protected java.lang.String | toHex(byte[] inData, int inOffset)
String hex = new String();
for (int i = 0; i < 4; i++) {
hex += hexChar[(inData[inOffset + i] >> 4) & 0x0f];
hex += hexChar[inData[inOffset + i] & 0x0f];
}
return hex;
|