NativeDecoderpublic class NativeDecoder extends VideoCodec
Fields Summary |
---|
private int | nativeDatapointer to the native structure of H263 decoder | private int | pictureDescpointer to the native structure of the picture descriptor | private int | PBFrameCap | private int | bsStart | private int | nextGOB | private int | pendingFrame | private static int | MAX_SEQ | private long | prevSeq | private static final boolean | debug | static final int[] | widths | static final int[] | heights | private int | videoWidth | private int | videoHeight | private boolean | FormatSizeInitFlag | private int | payloadLength |
Constructors Summary |
---|
public NativeDecoder()
supportedInputFormats = new VideoFormat[] {
new VideoFormat(VideoFormat.H263),
new VideoFormat(VideoFormat.H263_RTP),
new VideoFormat(VideoFormat.H263_1998_RTP)
};
defaultOutputFormats = new VideoFormat[] {new YUVFormat() };
PLUGIN_NAME = "H.263 Decoder";
|
Methods Summary |
---|
public boolean | checkFormat(javax.media.Format format)
if ( (format.getEncoding()).equals(VideoFormat.H263_RTP) ) {
return true;
}
else if ( (format.getEncoding()).equals(VideoFormat.H263_1998_RTP) ) {
return true;
}
else {
return super.checkFormat(format);
}
| public void | close()
closeNativeDecoder();
super.close();
| private native boolean | closeNativeDecoder()
| private native boolean | decodeFrameNative(javax.media.Buffer in, javax.media.Buffer out)
| private native boolean | decodePacketNative(byte[] in, int inputOffset, int inputLength, byte[] out, byte[] payloadHeader, int payloadOffset, int sync, int h263_1998)
| public static int | get1998PayloadHeaderLength(byte[] input, int offset)
int l = 2 + ((input[offset]&0x01) << 5) | ((input[offset+1]&0xf8) >> 3);
if ( (input[offset] & 0x02) != 0) { // Video Redundancy present
l++;
}
return l;
| protected javax.media.Format[] | getMatchingOutputFormats(javax.media.Format in)
VideoFormat ivf = (VideoFormat) in;
Dimension inSize = ivf.getSize();
int inMaxDataLength=ivf.getMaxDataLength();
int outNumOfPixels;
if ( ( (ivf.getEncoding()).equals(VideoFormat.H263_RTP) )
|| ( (ivf.getEncoding()).equals(VideoFormat.H263_1998_RTP) ) ) {
if (inSize == null)
outNumOfPixels = videoWidth * videoHeight;
else {
outNumOfPixels = inSize.width * inSize.height;
videoWidth = inSize.width;
videoHeight = inSize.height;
}
outNumOfPixels=videoWidth*videoHeight;
supportedOutputFormats= new VideoFormat[] {
new YUVFormat (
new Dimension(videoWidth,videoHeight),
(outNumOfPixels)+ ((outNumOfPixels) >> 1),
Format.byteArray,
ivf.getFrameRate(),
YUVFormat.YUV_420 ,
videoWidth,
videoWidth>>1,
0,
outNumOfPixels,
outNumOfPixels+(outNumOfPixels >>2)
)};
}
else {
Dimension outSize=movieSizeTo263Size(inSize);
outNumOfPixels=outSize.width*outSize.height;
videoWidth=outSize.width;
videoHeight=outSize.height;
supportedOutputFormats= new VideoFormat[] {
new YUVFormat (
inSize,
(outNumOfPixels)+ ((outNumOfPixels) >> 1),
Format.byteArray,
ivf.getFrameRate(),
YUVFormat.YUV_420 ,
outSize.width,
outSize.width>>1,
0,
outNumOfPixels,
outNumOfPixels+(outNumOfPixels >>2)
) };
}
return supportedOutputFormats;
| private int | getPayloadHeaderLength(byte[] input, int offset)
int l = 0;
byte b = input[offset];
if ( (b & 0x80) != 0) { //mode B or C
if ((b & 0x40) != 0) //mode C
l = 12;
else //mode B
l = 8;
} else { //mode A
l = 4;
}
return l;
| 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);
| protected void | initDecoder()
closeNativeDecoder(); // close the decoder if it was openned
initNativeDecoder(videoWidth,videoHeight);
| private native boolean | initNativeDecoder(int width, int height)
| private static native boolean | initNativeDecoderClass()
| private java.awt.Dimension | movieSizeTo263Size(java.awt.Dimension movieSize)
int width = (movieSize.width + 0xf) & 0xfffffff0;
int height = (movieSize.height + 0xf) & 0xfffffff0;
int formatCap = (width * height) >> 8;
/* transform the number of macroblocks into format*/
if (formatCap <= 48)
return new Dimension(128,96); // SQCIF
if (formatCap <= 99)
return new Dimension(176,144); // QCIF
if (formatCap <= 396)
return new Dimension(352,288); // CIF
if (formatCap <= 1584)
return new Dimension(704,576); // 4CIF
if (formatCap <= 6336)
return new Dimension(1408,1152); // 16CIF
return new Dimension(0,0); // ERROR
| public void | open()
try {
JMFSecurityManager.loadLibrary("jmutil");
JMFSecurityManager.loadLibrary("jmvh263");
initNativeDecoderClass();
initDecoder();
super.open();
return;
} catch (Throwable e) {
//System.out.println(e);
}
throw new ResourceUnavailableException("could not load jmvh263");
| public int | process(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer)
boolean rtpData = false;
boolean rtp1998Data = false;
boolean ret=false;
RTPHeader rtpHeader=null;
int newWidth=videoWidth;
int newHeight=videoHeight;
if (!checkInputBuffer(inputBuffer) ) {
return BUFFER_PROCESSED_FAILED;
}
if (isEOM(inputBuffer) ) {
propagateEOM(outputBuffer);
return BUFFER_PROCESSED_OK;
}
VideoFormat ivf=(VideoFormat) inputBuffer.getFormat();
int inLength=inputBuffer.getLength();
int inMaxLength=ivf.getMaxDataLength();
int outMaxLength=outputFormat.getMaxDataLength();
int inputOffset=inputBuffer.getOffset();
byte[] inData =(byte[]) inputBuffer.getData();
if ( (ivf.getEncoding()).equals(VideoFormat.H263_RTP) ) {
rtpData = true;
payloadLength=getPayloadHeaderLength(inData,inputOffset);
if ( (inData[inputOffset+payloadLength] == 0) && (inData[inputOffset+payloadLength+1] == 0) && ((inData[inputOffset+payloadLength+2] & 0xfc) == 0x80)) {
int s = (inData[inputOffset+payloadLength+4] >> 2) & 0x7;
newWidth=widths[s];
newHeight=heights[s];
FormatSizeInitFlag=true;
}
}
else if ( (ivf.getEncoding()).equals(VideoFormat.H263_1998_RTP) ) {
rtp1998Data = true;
int s = -1;
int picOffset = -1;
if (getSequenceDiff(prevSeq, inputBuffer.getSequenceNumber()) != 1) {
boolean discard = ((inData[inputOffset] & 0x04) == 0);
// Not part of the continuation, report lost packet
if (debug) {
System.err.println(
"NativeDecoder: Sequence out of order, expecting "
+ (prevSeq+1) + " got "
+ inputBuffer.getSequenceNumber()
+ (discard ? " discard packet" : ""));
}
if (discard)
return OUTPUT_BUFFER_NOT_FILLED;
}
prevSeq = inputBuffer.getSequenceNumber();
payloadLength=get1998PayloadHeaderLength(inData,inputOffset);
if (payloadLength > 5) {
// Use PIC header in payload header
if ( ((inData[inputOffset] & 0x02) == 0x02)
&& ((inData[inputOffset+3] & 0xfc) == 0x80)) {
picOffset = inputOffset + 3;
} else if ((inData[inputOffset+2] & 0xfc) == 0x80) {
picOffset = inputOffset + 2;
}
} else if ( ((inData[inputOffset] & 0x04) == 0x04)
&& ((inData[inputOffset+payloadLength] & 0xfc) == 0x80)) {
picOffset = inputOffset + payloadLength;
}
if (picOffset >= 0) {
s = (inData[picOffset+2] >> 2) & 0x7;
if (s == 7) {
// Extended PTYPE, picture size is in the extension
// if UFEP = 001
if (((inData[picOffset+3] >> 1) & 0x07) == 1) {
s = ((inData[picOffset+3] << 2) & 0x04) |
((inData[picOffset+4] >> 6) & 0x03);
} else {
s = -1; // picture type not present
}
}
}
if (s >= 0) {
newWidth=widths[s];
newHeight=heights[s];
FormatSizeInitFlag=true;
}
}
if ( (videoWidth!=newWidth) || (videoHeight!=newHeight) ) {
videoWidth=newWidth;
videoHeight=newHeight;
int outNumOfPixels=videoWidth*videoHeight;
outputFormat = new YUVFormat (
new Dimension(videoWidth,videoHeight),
(outNumOfPixels)+ ((outNumOfPixels) >> 1),
Format.byteArray,
ivf.getFrameRate(),
YUVFormat.YUV_420 ,
videoWidth,
videoWidth>>1,
0,
outNumOfPixels,
outNumOfPixels+(outNumOfPixels >>2)
);
outMaxLength = outputFormat.getMaxDataLength();
// outMaxLength = videoWidth * videoHeight;
videoResized();
FormatSizeInitFlag=true;
}
if ( (rtpData || rtp1998Data) && !FormatSizeInitFlag) {
return BUFFER_PROCESSED_FAILED;
}
byte[] outData = validateByteArraySize(outputBuffer,outMaxLength );
/*
* <PATCH> check for insufficient input:
* The decoder might read up to 8 additional bytes before checking for EOS
* It does not bother the native code, but can cause ArrayOutOfBounds
* in Java code
*/
if ( (inLength+8+inputOffset)>inData.length) {
//System.out.println("allocating more data for H.263");
int newLength=(inLength > inMaxLength) ? inLength : inMaxLength;
byte[] tempArray=new byte[inputOffset+newLength+8];
System.arraycopy(inData,0,tempArray,0,inLength+inputOffset);
inData=tempArray;
inputBuffer.setData(tempArray);
//inputBuffer.setOffset(0);
}
/*
* <PATCH> pad input with EOS
*/
inData[inputOffset+inLength] = 0;
inData[inputOffset+inLength+1] = 0;
inData[inputOffset+inLength+2]= (byte) 0xfc;
inLength += 3;
inputBuffer.setLength(inLength);
if (rtpData) {
inLength-=payloadLength; // this is the length of the bitstream
//rtpHeader= (RTPHeader) inputBuffer.getHeader();
int marker = 0;
if ((inputBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0)
marker = 1;
ret = decodePacketNative(inData,inputOffset+payloadLength,inLength,outData,inData,inputOffset,marker,0);
} else
if (rtp1998Data) {
inLength-=payloadLength; // this is the length of the bitstream
//rtpHeader= (RTPHeader) inputBuffer.getHeader();
int marker = 0;
if ((inputBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0) {
marker = 1;
} else {
inLength -= 3; // skip the EOS pad
}
ret = decodePacketNative(inData,inputOffset+payloadLength,inLength,outData,inData,inputOffset,marker,1);
}
else {
ret = decodeFrameNative(inputBuffer, outputBuffer);
}
if (ret) {
updateOutput(outputBuffer,outputFormat, outMaxLength, 0);
outputBuffer.setFormat(outputFormat);
return BUFFER_PROCESSED_OK;
}
else {
return OUTPUT_BUFFER_NOT_FILLED;
}
| public void | reset()
//we do not initialize the decoder as the first frame is key frame
| public javax.media.Format | setInputFormat(javax.media.Format input)
Format ret = super.setInputFormat(input);
if (ret == null)
return null;
if (opened) {
close();
try {
setOutputFormat(getMatchingOutputFormats(input)[0]);
open();
} catch (Exception e) {
return null;
}
}
return ret;
| protected void | videoResized()
initDecoder();
|
|