FileDocCategorySizeDatePackage
DePacketizer.javaAPI DocFobs4JMF API 0.4.113620Wed Dec 28 15:58:18 GMT 2005com.neon.media.codec.video.mp4v

DePacketizer

public class DePacketizer extends VideoCodec
Neon Media MPEG-4 Video RTP De-Packetizer
author
Scott Hays
created
2005/08/26 Copyright (c) 2005 Neon Advanced Technologies Co., Ltd. All rights reserved. The Neon MPEG-4 Video RTP DePacketizer is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The Neon MPEG-4 Video RTP DePacketizer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

Fields Summary
private static String
IN_ENCODING
private static String
OUT_ENCODING
private static final int
DEF_WIDTH
private static final int
DEF_HEIGHT
private boolean
firstFrame
private MP4VFrame
currentFrame
private short
seqNum
private final int
FRAME_BUFFER_INITIAL_SIZE
Constructors Summary
public DePacketizer()

		System.err.println(this.getClass().getName() + " constructor called.");
		PLUGIN_NAME = "Neon MP4V RTP DePacketizer";
		inputFormats = supportedInputFormats = new VideoFormat[] { new VideoFormat(IN_ENCODING), new VideoFormat("MP4V-ES"), new VideoFormat("MP4V-ES/90000") };
		defaultOutputFormats = new VideoFormat[] { new VideoFormat(OUT_ENCODING) };
		
/*		//DEBUG
		try {
			dumpFile = new File("dump.m4v");
			packDumpFile = new File("packdump.m4v");
			completeDFile = new File("completedump.m4v");
			logFile = new File("nmp.log");
			dumpOut = new FileOutputStream(dumpFile);
			packDumpOut = new FileOutputStream(packDumpFile);
			completeDOut = new FileOutputStream(completeDFile);
			logOut = new FileOutputStream(logFile);
			log = new PrintStream(logOut);
		} catch (FileNotFoundException e) {
			System.err.println("mp4v.DePacketizer: failed to open dump files: " + e.getMessage());
			e.printStackTrace();
		}
*/		//DEBUG
	
Methods Summary
private static booleancanStartStream(javax.media.Buffer buffer)

		byte[] payload = (byte[])buffer.getData();
		int offset = buffer.getOffset();
		//System.err.println("mp4v.DePacketizer: offset = " + offset);
		int length = 32;	// VOL SHOULD be in the first 32 bytes so don't bother scanning entire buffer
		if (buffer.getLength() <= length) return false;
		boolean keep_looking = true;
		int currentCode = (payload[offset] & 0xff) << 24 | (payload[offset+1] & 0xff) << 16 | (payload[offset+2] & 0xff) << 8 | (payload[offset+3] & 0xff);

		for (int i=4; i < length; i++) {
			if ((currentCode & 0xfffffff0) == 0x00000120) return true;
			if (currentCode == 0x000001b0) System.err.println("MP4VFrame.canStartStream: frame has VS header");
			if (currentCode == 0x000001b5) System.err.println("MP4VFrame.canStartStream: frame has VO header");
			//System.err.println("MP4VFrame.canStartStream:0x" + Integer.toHexString(currentCode));
			currentCode = (currentCode << 8) | (payload[offset+i] & 0xff);
		}
		return false; // VOL not found
	
private voidcompleteTransfer(javax.media.Buffer inBuffer, javax.media.Buffer outBuffer)

//		System.err.println("mp4v.DePacketizer: completeTransfer called");
		if (outputFormat == null) System.err.println("mp4v.DePacketizer: outputFormat NULL!!!!!!!!!!");
		//SANITY CHECK
		if (!isFrameStart(currentFrame.getFrameBuffer(), 0)) {
			System.err.println("((((((mp4v.DePacketizer: FRAME CORRUPTED!!))))))");
			System.exit(1);
		}

		outBuffer.setFormat(outputFormat);
		
		outBuffer.setData(currentFrame.getFrameBuffer());
		outBuffer.setOffset(0);
		outBuffer.setDuration((long)(((VideoFormat)outputFormat).getFrameRate() + 0.5));
		outBuffer.setSequenceNumber(seqNum++);	//FIXME roll over??
		outBuffer.setTimeStamp(currentFrame.getTimeStamp());
		outBuffer.setLength(currentFrame.getDataLength());
		
/*		//DEBUG
		try {
			dumpOut.write(currentFrame.getFrameBuffer(), 0, currentFrame.getDataLength());
		} catch (Exception e) {
			System.err.println("mp4v.DePacketizer: failed to write frame: " + e.getMessage());
			e.printStackTrace();
		}
*/		//DEBUG
		currentFrame = null;
	
public java.lang.StringgetName()

		return PLUGIN_NAME;
	
public javax.media.Format[]getSupportedOutputFormats(javax.media.Format f)

		System.err.println("mp4v.DePacketizer: getting for f = " + f);
		if (f == null) return defaultOutputFormats;
		else if (f.getEncoding().equalsIgnoreCase(IN_ENCODING)) {
			if (f instanceof VideoFormat) {
				VideoFormat vf = (VideoFormat)f;
				VideoFormat supOutFmt = new VideoFormat(OUT_ENCODING, vf.getSize() == null ? new Dimension(DEF_WIDTH, DEF_HEIGHT):vf.getSize(), vf.getMaxDataLength(), Format.byteArray, vf.getFrameRate());
				System.err.println("mp4v.DePacketizer: supported Output Format = " + supOutFmt);
				return new Format[] { supOutFmt };
			} else return new Format[] {new VideoFormat(OUT_ENCODING, new Dimension(DEF_WIDTH, DEF_HEIGHT), Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED) };
		} 
		System.err.println("mp4v.DePacketizer: getSupportedOutputFormats f = " + f);
		return new Format[0];
	
private static booleanisFrameStart(javax.media.Buffer buffer)

	// 8KB

/*	//DEBUG
	private File dumpFile;
	private File packDumpFile;
	private File completeDFile;
	private File logFile;
	private FileOutputStream dumpOut;
	private FileOutputStream packDumpOut;
	private FileOutputStream completeDOut;
	private FileOutputStream logOut;
	private PrintStream log;
*/	//DEBUG
	
	     
		Object data = buffer.getData();
		byte[] payload = (byte[])data;
		int offset = buffer.getOffset();
		return isFrameStart(payload, offset);
	
private static booleanisFrameStart(byte[] payload, int offset)

		int firstBytes = (payload[offset] & 0xff) << 16 | (payload[offset+1] & 0xff) << 8 | (payload[offset+2] & 0xff);
		// first 3 bytes of a system code
		return firstBytes == 0x000001;
	
public synchronized intprocess(javax.media.Buffer inBuffer, javax.media.Buffer outBuffer)

		if (firstFrame && !(inBuffer.getData() instanceof byte[])) { // assume that if the first inBuffers are byte arrays, all are
			System.err.println("MP4VFrame.isFrameStart: payload is not byte[]");
			return OUTPUT_BUFFER_NOT_FILLED;
		}
		//DEBUG
		//HACK:Sun RTP RECEIVE BUG
		//	Sun RTP seems to require regular I/O, otherwise it seldom delivers received packets
		System.err.println("mp4v.DePacketizer: process() inBuffer.getLength() = " + inBuffer.getLength());
		//DEBUG
		if (isEOM(inBuffer)) {
			propagateEOM(outBuffer);
			return BUFFER_PROCESSED_OK;
		}

		if (inBuffer.isDiscard()) {
			updateOutput(outBuffer, outputFormat, 0, 0);
			outBuffer.setDiscard(true);
			return OUTPUT_BUFFER_NOT_FILLED;
		}
		
/*		//DEBUG
		try {
			completeDOut.write((byte[])inBuffer.getData(), inBuffer.getOffset(), inBuffer.getLength());
		} catch (IOException e) {
			System.err.println("mp4v.DePacketizer: couldn't write to complete dump: " + e.getMessage());
			e.printStackTrace();
		}
*/		//DEBUG
		
		//System.err.println("mp4v.DePacketizer: process packet");
		// lost RTP fragment packet(s) so drop frame
		if (currentFrame != null && inBuffer.getTimeStamp() != currentFrame.getTimeStamp()) {
			System.err.println("mp4v.DePacketizer: DROP FRAME:timestamp mismatch: got(" + inBuffer.getTimeStamp() + ") on packet " + inBuffer.getSequenceNumber() + ", expected(" + currentFrame.getTimeStamp() + ")");
			currentFrame = null;
//			frameBuffer.clear();
		}
		
		// check to see if packet is first of a frame
		if (currentFrame == null && isFrameStart(inBuffer)) {
			// ensure first frame given to encoder has needed configuration information
			if (firstFrame && !canStartStream(inBuffer)) return PlugIn.OUTPUT_BUFFER_NOT_FILLED;
			if (firstFrame) System.err.println(">>>> mp4v.DePacketizer: START STREAM");
			currentFrame = new MP4VFrame(inBuffer);
			firstFrame = false;
		
		} else {
			if (currentFrame == null) {
				System.err.println("^^^^mp4v.DePacketizer: DROP PACKET " + inBuffer.getSequenceNumber() + ": no current frame and packet cannot start frame.");
				return PlugIn.OUTPUT_BUFFER_NOT_FILLED;
			}
//			System.err.println("mp4v.DePacketizer: adding packet to frame");
			currentFrame.add(inBuffer);	
		}
		
		// check to see if entire frame should now have been received
		if ((inBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0) {
			if (!currentFrame.isMissingFragments()) {
				completeTransfer(inBuffer, outBuffer);
				currentFrame = null;
//				System.err.println("____mp4v.DePacketizer: delivering frame._____");
				return PlugIn.BUFFER_PROCESSED_OK;
			} else {
				// frame incomplete and last packet received, so drop
				System.err.println("&&&&mp4v.DePacketizer: DROP FRAME:missing fragments");
				currentFrame = null;
				return PlugIn.OUTPUT_BUFFER_NOT_FILLED;
			}
		}

//		System.err.println("mp4v.DePacketizer: output buffer not filled");

		return PlugIn.OUTPUT_BUFFER_NOT_FILLED;
	
public javax.media.FormatsetOutputFormat(javax.media.Format f)

		VideoFormat vf = (VideoFormat)f;
		if (!f.getEncoding().equalsIgnoreCase(OUT_ENCODING)) {
			System.err.println("mp4v.DePacketizer: setOutputFormat received unsupported encoding: " + f.getEncoding());
			return null;
		}
		System.err.println("mp4v.DePacketizer: setOutputFormat received format with size: " + vf.getSize());
		outputFormat = new VideoFormat(OUT_ENCODING, vf.getSize() == null ? new Dimension(DEF_WIDTH, DEF_HEIGHT):vf.getSize(), vf.getMaxDataLength(), Format.byteArray, vf.getFrameRate()); 
		return outputFormat;