FileDocCategorySizeDatePackage
NativeDecoder.javaAPI DocJMF 2.1.1e10535Mon May 12 12:20:46 BST 2003com.sun.media.codec.video.h261

NativeDecoder

public class NativeDecoder extends VideoCodec

Fields Summary
public static final int[]
widths
public static final int[]
heights
private int
nativeData
int
h261Flags
int
syncBit
int
skipBytes
int
nframes
int
sizeChanged
private int
width
private int
height
private boolean
formatSizeInitFlag
Constructors Summary
public NativeDecoder()



      

	supportedInputFormats = new VideoFormat[]{new VideoFormat(VideoFormat.H261),
						  new VideoFormat(VideoFormat.H261_RTP)};

        defaultOutputFormats  = new VideoFormat[] {new YUVFormat() };
        PLUGIN_NAME = "H.261 Decoder";

    
Methods Summary
protected voidallocateBuffer()

	// Always allocate CIF size buffer in case size change occurs at
	// frame boundary.
	int size = 352 * 288;
	size = 4 * (size + size/2);
	allocatePicture(size);
    
private native voidallocatePicture(int size)

public booleancheckFormat(javax.media.Format format)


      if ( (format.getEncoding()).equals(VideoFormat.H261_RTP) ) {
        return true;
      }
      else {
        return super.checkFormat(format);
      }

    
public voidclose()

         freeNativeDecoder();
	 super.close();
    
private native booleandecodeNative(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer, long outBytes)

public voidfindStartCode(javax.media.Buffer inputBuffer)


	byte [] data = (byte[]) inputBuffer.getData();
	int i = 1;
	while (data[i] == 0) {
	    i++;
	}

	skipBytes = i - 1;
	if (data[i] != 1) {
	    skipBytes--;
	    if ((data[i] & 128) != 0)
		h261Flags |= 0x20000000;
	    else if ((data[i] & 64) != 0)
		h261Flags |= 0x40000000;
	    else if ((data[i] & 32) != 0)
		h261Flags |= 0x60000000;
	    else if ((data[i] & 16) != 0)
		h261Flags |= 0x80000000;
	    else if ((data[i] & 8) != 0)
		h261Flags |= 0xa0000000;
	    else if ((data[i] & 4) != 0)
		h261Flags |= 0xc0000000;
	    else if ((data[i] & 2) != 0)
		//discard 7 bits
		h261Flags |= 0xe0000000;
	}

     	i = inputBuffer.getLength() -1;
       	while(data[i] == 0) {
	    i--;
	}


	if (i == 1) {
	    inputBuffer.setLength(i - 1);
	} else {
	    switch (data[i] &0xff) {
	    case 1:
		//should never happen
		break;
	    case 2:
		//discard 7 bits
		h261Flags |= 0x04000000;
		break;
	    case 4:
		h261Flags |= 0x08000000;
		break;
	    case 8:
		h261Flags |= 0x0c000000;
		break;
	    case 16:
		h261Flags |= 0x10000000;
		break;
	    case 32:
		h261Flags |= 0x14000000;
		break;
	    case 64:
		h261Flags |= 0x18000000;
		break;
	    case 128:
		h261Flags |= 0x1c000000;
		break;
	    }
	    inputBuffer.setLength(i-1);
	}

    
private native booleanfreeNativeDecoder()

protected javax.media.Format[]getMatchingOutputFormats(javax.media.Format in)


      	VideoFormat     ivf  = (VideoFormat) in;
	Dimension       inSize = ivf.getSize();
        int             inMaxDataLength=ivf.getMaxDataLength();
        //Dimension       outSize=(inSize); //XXX sbd: is it always the way ?
        int             outNumOfPixels;

        if ( (ivf.getEncoding()).equals(VideoFormat.H261_RTP) ) {
	    // Varify the sizes.
	    if (inSize != null) {
		Dimension  outSize=movieSizeTo261Size(inSize);
		width=outSize.width;
		height=outSize.height;
	  }
          outNumOfPixels=width*height;
          supportedOutputFormats= new  VideoFormat[] {
                new YUVFormat (
                new Dimension(width,height),
                (outNumOfPixels)+ ((outNumOfPixels) >> 1),
                Format.byteArray,
                ivf.getFrameRate(),			       
                YUVFormat.YUV_420 ,
                width,
                width>>1,
                0,
                outNumOfPixels,
                outNumOfPixels+(outNumOfPixels >>2)
                ) };
          }
        else {
          Dimension  outSize=movieSizeTo261Size(inSize);
          width=outSize.width;
          height=outSize.height;
          outNumOfPixels=outSize.width*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 native booleaninitNativeDecoder()

private java.awt.DimensionmovieSizeTo261Size(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 <= 99)
           return new Dimension(176,144);   // QCIF
       if (formatCap <= 396)
           return new Dimension(352,288);   // CIF

       return new Dimension(0,0);    // ERROR

    
public voidopen()


      	try {

            JMFSecurityManager.loadLibrary("jmutil");
            JMFSecurityManager.loadLibrary("jmh261");
            initNativeDecoder();
	    allocateBuffer();
	    super.open();
            return;

	} catch (Throwable e) {
            System.err.println("could not open "+PLUGIN_NAME+". reason:");
            System.err.println(e);
	}


        throw new ResourceUnavailableException("Could not open "+PLUGIN_NAME);
    
public intprocess(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer)


       boolean rtpData = false;

       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();

	byte[] inData =(byte[]) inputBuffer.getData();

	if (ivf.getEncoding().equals(VideoFormat.H261_RTP)){
            rtpData = true;
	    // the RTP H261 Payload header is 4 bytes. Read it into
	    // flags starting at the offset pointed to by the
	    // inputBuffer (the offset points to the end of the RTP header.

            int inputOffset = inputBuffer.getOffset();
            // convert the 4 byte payload header into one int value
            h261Flags = (inData[inputOffset]<<24) + ((inData[inputOffset+1]&0xff)<<16) + ((inData[inputOffset+2]&0xff)<<8) + (inData[inputOffset+3]&0xff) ;

	    //syncBit = ((RTPHeader)(inputBuffer.getHeader())).getMarker();
	    if ( (inputBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0)
	      syncBit = 1;
	    else
	      syncBit = 0;

	    // ask the decoder to skip 4 bytes after the offset as
	    // well to get to the actual h261 compressed payload
	    skipBytes = 4;

            if ( (inData[inputOffset+skipBytes] == 0) && (inData[inputOffset+skipBytes+1] == 1) && ((inData[inputOffset+skipBytes+2] & 0xfc) == 0)) {
                int pictureFormat = (inData[inputOffset+skipBytes+3]>>3)&0x01;
                if ( (width!=widths[pictureFormat]) || (height!=heights[pictureFormat])  ) {
		    
                  width=widths[pictureFormat];
                  height=heights[pictureFormat];
                  int outNumOfPixels=width*height;
		  close();
                  outputFormat = new YUVFormat (
		      new Dimension(width,height),
		      (outNumOfPixels)+ ((outNumOfPixels) >> 1),
		      Format.byteArray,
		      ivf.getFrameRate(),			       
		      YUVFormat.YUV_420 ,
		      width,
		      width>>1,
		      0,
		      outNumOfPixels,
		      outNumOfPixels+(outNumOfPixels >>2)
		      );
		  try {
		      open();
		  } catch (Exception e) {
		      return BUFFER_PROCESSED_FAILED;
		  }
		}

                formatSizeInitFlag=true;
                //System.out.println("start code , width "+width+" height "+height);
            }

	/*
	-ivg
	 I've fixed the H261 decoder to initialize to the right size
	 so it wouldn't have to wait for the first start code.  But that
	 didn't work very well.  The decoder crashes.  So I'm keeping the
	 guard in for now.  Will have to look at it later.
            if (false == formatSizeInitFlag) {
              return BUFFER_PROCESSED_FAILED;
            }
	*/

	} else {

	    // format is not H261_RTP
	    h261Flags = 0x01000000;
	    syncBit = 1;
	    findStartCode(inputBuffer);
	}

	outputBuffer.setFormat(outputFormat);
	int outMaxLength = outputFormat.getMaxDataLength();
	Object outData = validateData(outputBuffer, outMaxLength * 2, true);
	long outBytes = getNativeData(outData);
	boolean ret = decodeNative(inputBuffer, outputBuffer, outBytes);
        if (ret && syncBit == 1) {
	    updateOutput(outputBuffer,outputFormat, outMaxLength, 0);
	    return BUFFER_PROCESSED_OK;
        } else {
	    return OUTPUT_BUFFER_NOT_FILLED;
        }

   
public voidreset()

        // no need to init decoder as first frame is always a key frame
    
public javax.media.FormatsetInputFormat(javax.media.Format input)

	Format ret = super.setInputFormat(input);
	if (ret == null)
	    return null;
	if (opened) {
	    try {
		close();
		outputFormat = (VideoFormat) getMatchingOutputFormats(ret)[0];
		open();
	    } catch (Exception e) {
		return null;
	    }
	}
	return ret;
    
protected voidvideoResized()

        initNativeDecoder();
	allocateBuffer();