FileDocCategorySizeDatePackage
NativeEncoder.javaAPI DocJMF 2.1.1e22168Mon May 12 12:21:00 BST 2003com.ibm.media.codec.video.h263

NativeEncoder

public class NativeEncoder extends VideoCodec

Fields Summary
public static final String
a_copyright_notice
Licensed Materials - Property of IBM "Restricted Materials of IBM" 5648-B81 (c) Copyright IBM Corporation 1997,1999 All Rights Reserved US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corporation.
static final int[]
widths
static final int[]
heights
private int
videoWidth
private int
videoHeight
int
nativeFormat
static final int
DEFAULT_RTP_MTU
static final int
MAX_RTP_MTU
static final int
DEFAULT_MAX_OUTPUT_LENGTH
public int
maxOutputLength
public int
targetOutputLength
long
timeStamp
long
sequenceNumber
long
deltaFrames
boolean
useRtp
Control[]
controls
float
sourceFrameRate
float
targetFrameRate
int
minBitRate
int
maxBitRate
int
useBitRate
int
iFramePeriod
int
frameDecimation
int
frame2skip
boolean
initCompleted
boolean
settingsChanged
boolean
dropFrame
boolean
okToDrop
EncodeControl
encodeControl
private int
nativeData
private int
prevTr
private int
tr
public boolean
frameDone
private int
outputLength
private boolean
interFlag
Constructors Summary
public NativeEncoder()





    // Constructor
      
///       System.out.println("[h263Encoder:Constructor]");
        supportedInputFormats = new VideoFormat[] {
	                                new YUVFormat(YUVFormat.YUV_420)
			        };

        defaultOutputFormats  = new VideoFormat[] {
	                                new VideoFormat(VideoFormat.H263),
					new VideoFormat(VideoFormat.H263_RTP)
			        };

        PLUGIN_NAME = "H.263 Encoder";
    
Methods Summary
public synchronized voidclose()

//       System.out.println("[h263Encoder:close]");
	if (encodeControl != null)
	    encodeControl.close();
        closeNativeEncoder();
	super.close();
    
private synchronized voidcloseNative()

        closeNativeEncoder();
    
private native booleancloseNativeEncoder()

private native booleanencodeFrameNative(javax.media.Buffer in, javax.media.Buffer out)

protected voidfinalize()

	if (encodeControl != null) {
	    encodeControl.frame.dispose();
	    encodeControl = null;
	}
    
public java.lang.Object[]getControls()

        if (controls==null) {
             controls=new Control[8];
             controls[0]=new H263Adapter(this, false, false,false,false,false,0,1000,false);
             controls[1]=new BitRateAdapter(this,useBitRate,minBitRate,maxBitRate,true);
             controls[2]=new KeyFrameAdapter(this,iFramePeriod,true);
             controls[3]=new QualityAdapter(this,1.0F,0.0F,1.0F,false,true);
             controls[4]=new FrameRateAdapter(this,targetFrameRate,
	                                           sourceFrameRate/3,
						   sourceFrameRate,true);
             controls[5]=new FrameProcessingAdapter(this);
             controls[6]=new PacketSizeAdapter(this,targetOutputLength,true);
	     encodeControl = new EncodeControl(controls);
	     controls[7]= encodeControl;
        }

        return (Object[])controls;
    
protected javax.media.Format[]getMatchingOutputFormats(javax.media.Format in)

      	VideoFormat     ivf  = (VideoFormat) in;
	Dimension       inSize = ivf.getSize();
	
        if (inSize==null)
            return null;

	videoWidth  =   inSize.width;
        videoHeight =   inSize.height;

	// Amith - allow only default frame rate
        supportedOutputFormats= new  VideoFormat[2];
        for (int i=0;i<2;) {
            float useFrameRate=ivf.getFrameRate();
            if (i==2)
                useFrameRate /= 2.0F;

            if (i==4)
                useFrameRate /= 3.0F;

            supportedOutputFormats[i++]=
                new VideoFormat (
                    VideoFormat.H263,
                    new Dimension(inSize),
                    Format.NOT_SPECIFIED,
                    Format.byteArray,
		    useFrameRate);

            supportedOutputFormats[i++]=
		    new VideoFormat (              //Hagai
                    VideoFormat.H263_RTP,
                    new Dimension(inSize),
                    Format.NOT_SPECIFIED,
                    Format.byteArray,
		    useFrameRate);
	}

        return  supportedOutputFormats;
    
protected voidinitEncoder()

       if (maxOutputLength != outputFormat.getMaxDataLength() ) {
           VideoFormat f=outputFormat;
           outputFormat = new VideoFormat(f.getEncoding(),f.getSize(),maxOutputLength,Format.byteArray,f.getFrameRate());
//           System.out.println("of "+outputFormat);
       }
/*
       System.out.println("[h263Encoder:initEncoder]");
       System.out.println("nativeFormat="+ nativeFormat);
       System.out.println("sourceFrameRate="+ sourceFrameRate);
       System.out.println("targetFrameRate="+ targetFrameRate);
       System.out.println("useBitRate="+ useBitRate);
       System.out.println("iFramePeriod="+ iFramePeriod);
       System.out.println("maxOutputLength="+ maxOutputLength);
       System.out.println("targetOutputLength="+ targetOutputLength);
       System.out.println("useRTP="+useRtp);
*/
       closeNative();
//       System.out.println("[h263Encoder:initEncoder] : closed");
//       initNativeEncoder(nativeFormat,useRtp);

       if (useRtp)
          initNativeEncoder(nativeFormat,
                         targetOutputLength, //MTUPacketSize
			 sourceFrameRate,
			 targetFrameRate,
			 useBitRate, //targetBitRate,
			 iFramePeriod );//IFramePeriod
        else
                  initNativeEncoder(nativeFormat,
                         0, // "No RTP"
			 sourceFrameRate,//sourceFrameRate,
			 targetFrameRate,//targetFrameRate,
			 useBitRate, //targetBitRate,
			 iFramePeriod);//IFramePeriod



//       System.out.println("[h263Encoder:initEncoder] : done");
    
private native booleaninitNativeEncoder(int nativeFormat, int MTUPacketSize, float sourceFrameRate, float targetFrameRate, int targetBitRate, int IFramePeriod)

public voidopen()


	// Validate sizes here.

        // Native format
        //
        //	|FRAME FORMAT		width		height	    image_format |
	//	|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
	//	|SQCIF			 128		 96		  0	 |
	//	|QCIF (PAL)		 176		 144		  1      |
	//	|CIF (PAL)		 352		 288              2	 |


        ///===add support for non standard frame size here==
        if ( (videoWidth==128) && (videoHeight==96 ) ) {
             nativeFormat=0;
        } else if ( (videoWidth==176) && (videoHeight==144) ) {
             nativeFormat=1;
        } else if ( (videoWidth==352) && (videoHeight==288) ) {
             nativeFormat=2;
        } else  {
	    Log.error("Class: " + this);
	    Log.error("  can only encode in sizes: 128x96, 176x144, 352x288.");
	    throw new ResourceUnavailableException("could not load jmvh263");
	}

        try {
            JMFSecurityManager.loadLibrary("jmutil");
            JMFSecurityManager.loadLibrary("jmh263enc");
            //initFrame();
//            initEncoder();
	    super.open();
	    if (encodeControl != null)
		encodeControl.open(controls);
            return;
            }
	catch (Throwable e) {
            System.out.println(e);
        }

	//System.out.println("[h263encoder::open]could not load jmvh263");
	throw new ResourceUnavailableException("could not load jmvh263");
    
public synchronized intprocess(javax.media.Buffer inputBuffer, javax.media.Buffer outputBuffer)


      if (!initCompleted) {
//          System.out.println("init encoder");
          initCompleted=true;
          initEncoder();
      }

      // Drop frame when necessary.
      if (okToDrop && dropFrame) {
	  dropFrame = false;
	  outputBuffer.setDiscard(true);
	  if (settingsChanged)
	      reset();
	  return BUFFER_PROCESSED_OK;
      }

      okToDrop = false;

//    System.out.println("[h263Encoder:process]");
       if ( frameDone==true) {
//          System.out.println(frame2skip);
          frame2skip++;
          if (frame2skip!=frameDecimation) {
              updateOutput(outputBuffer,outputFormat, 0 , 0);
//              outputBuffer.setDiscard(true);
              return OUTPUT_BUFFER_NOT_FILLED;
          }
          frame2skip=0;

          if (!checkInputBuffer(inputBuffer) ) {
              return BUFFER_PROCESSED_FAILED;
              }

	  if (isEOM(inputBuffer) ) {
	      propagateEOM(outputBuffer);
	      okToDrop = true;
	      if (settingsChanged)
		  reset();
	      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();
       
       if (outMaxLength < MAX_RTP_MTU)
	   outMaxLength = MAX_RTP_MTU;

      byte[] inData =(byte[]) inputBuffer.getData();
      byte[] outData = validateByteArraySize(outputBuffer,outMaxLength );

      boolean ret = encodeFrameNative(inputBuffer,outputBuffer);
//      if (frameDone == false)
//      System.out.println("[NativeEncoder:process] tr=" +tr + " outputLength= "+ outputLength + " timeStamp=" + inputBuffer.getTimeStamp() );

      if (outputLength>=0)
	      outputBuffer.setLength(outputLength);

      // update the output buffer fileds that are needed within the RTP header.
      if (useRtp) {
           outputBuffer.setSequenceNumber(sequenceNumber);

      sequenceNumber++;

//      RTPHeader header = (RTPHeader)outputBuffer.getHeader(); // this should have been done elsewhere ??
//      if (null == header)
//               header = new RTPHeader();

        if (true == frameDone) {


                timeStamp = inputBuffer.getTimeStamp();
                // The above libe should be repaced with the line bellow if there is a possibility that the input
                // Buffer does not have a timeStamp
                // timeStamp += ((long)((tr-prevTr)&0x000000ff))*deltaFrames;
                prevTr= tr;
 	  	int flags =  outputBuffer.getFlags();
                flags |= Buffer.FLAG_RTP_MARKER;
 	        outputBuffer.setFlags(flags);
                }
        else    {
                }
	  // No need to set the time stamp.
          //outputBuffer.setTimeStamp(timeStamp);
      } else {  // set key frame for intra frames
          int flags =  outputBuffer.getFlags();
          if (!interFlag)
              flags |= Buffer.FLAG_KEY_FRAME;
          else
	      flags &= ~Buffer.FLAG_KEY_FRAME;
          outputBuffer.setFlags(flags);
      }


      // note that encoder update output length
      updateOutput(outputBuffer,outputFormat, outputBuffer.getLength() , 0);
      // Amith - added this because outputFormat is defined in both BasicCodec
      //         and VideoCodec
      outputBuffer.setFormat(outputFormat);
      
      if (true == frameDone)
        if (outputLength !=-1) {
	    okToDrop = true;
	    if (settingsChanged)
	        reset();
            return BUFFER_PROCESSED_OK;
        } else {
//            System.out.println("[NativeEncoder:process]Last Gob Does not fit intop MTU");
            return (OUTPUT_BUFFER_NOT_FILLED);
        }
      else
        if (outputLength ==-1) { // a gob doesn't fit in an MTU
//             System.out.println("[NativeEncoder:process] A gob doesn't fit in an MTU");
             return (INPUT_BUFFER_NOT_CONSUMED|OUTPUT_BUFFER_NOT_FILLED);
         }
      else
            return INPUT_BUFFER_NOT_CONSUMED;
    
public final synchronized voidreset()

//       System.out.println("[h263Encoder:reset]");
       initEncoder();
       settingsChanged = false;
    
private native booleansetFramesBehind(int numOfFrames)

public javax.media.FormatsetInputFormat(javax.media.Format format)

        YUVFormat     ivf  = (YUVFormat) super.setInputFormat(format);
        if (ivf==null)
            return null;

	Dimension       inSize = ivf.getSize();
        if (inSize==null)
            return null;
	if (ivf.getOffsetU() > ivf.getOffsetV())
	    return null;
        videoWidth  =   inSize.width;
        videoHeight =   inSize.height;

        sourceFrameRate=ivf.getFrameRate();

        deltaFrames = (long) (1000000.0/ivf.getFrameRate());    // in Nano Seconds

	if (opened) {
	    VideoFormat newOut;
	    newOut = 
                new VideoFormat (
				 outputFormat.getEncoding(),
				 new Dimension(inSize),
				 Format.NOT_SPECIFIED,
				 Format.byteArray,
				 ivf.getFrameRate());
	    close();
	    setOutputFormat(newOut);
	    try {
		open();
	    } catch (ResourceUnavailableException re) {
		return null;
	    }
	}
        return  format;

    
public javax.media.FormatsetOutputFormat(javax.media.Format format)
Hagai overides VideoCodec.setOutputFormat in order to init RTP variables

	VideoFormat f = (VideoFormat)super.setOutputFormat(format);
	if (f.getMaxDataLength() == Format.NOT_SPECIFIED) {
	    if (f.getEncoding().equals(VideoFormat.H263_RTP)) {
		useRtp = true;
		maxOutputLength = MAX_RTP_MTU;
		targetOutputLength = DEFAULT_RTP_MTU;
	    } else {
		useRtp = false;
		maxOutputLength = DEFAULT_MAX_OUTPUT_LENGTH;
		targetOutputLength = DEFAULT_MAX_OUTPUT_LENGTH;
	    }
	    f = new VideoFormat(f.getEncoding(),f.getSize(),maxOutputLength,Format.byteArray,f.getFrameRate());
	    targetFrameRate=f.getFrameRate();
	    frameDecimation= (int)(sourceFrameRate/targetFrameRate);
	    useBitRate = (int) ((targetFrameRate * f.getSize().width *
				 f.getSize().height) / 5);
	    f = (VideoFormat)super.setOutputFormat(f);

	}
	return f;  // How do we define who is responsible for initiating the MTU
    
private native booleansetQuality(float quality)

protected voidvideoResized()

//   System.out.println("[h263Encoder:videoResized]");
        initEncoder();