⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 depacketizer.java

📁 FMJ(freedom media for java)是java视频开发的新选择
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
				expect += b.getLength() - JpegRTPHeader.HEADER_SIZE;							}			return true;		}		/**		 * Total length of all fragments.  Does not include JPEG header. 		 * Assumes that complete() has been called and returns true.		 */		public int frameLength()		{			if (!rtpMarker)				throw new IllegalStateException();			if (list.size() <= 0)				throw new IllegalStateException();						// calculate from offset and length of last buffer:			final Buffer b = (Buffer) list.get(list.size() - 1);			final JpegRTPHeader jpegRtpHeader = parseJpegRTPHeader(b);			// Observed: the frame with the marker has valid offset, 			return jpegRtpHeader.getFragmentOffset() + b.getLength() - JpegRTPHeader.HEADER_SIZE;		}				/**		 * Assumes that complete() has been called and returns true.		 */		public int copyToBuffer(Buffer bDest)		{			if (!rtpMarker)				throw new IllegalStateException();			if (list.size() <= 0)				throw new IllegalStateException();			// TODO: perhaps what we should do is copy the header if there is not one.			// The test samples coming from JMStudio had headers in them, so the JPEG could not be			// parsed if (another) header was prepended.			final Buffer bFirst = (Buffer) list.get(0);			final boolean prependHeader = !hasJPEGHeaders((byte []) bFirst.getData(), bFirst.getOffset() + JpegRTPHeader.HEADER_SIZE, bFirst.getLength() - JpegRTPHeader.HEADER_SIZE);			final int MAX_HEADER = prependHeader ? 1024 : 0;	// TODO: what is actual max size for the header?  Seems to be fixed size, 600-700 bytes.			final int MAX_TRAILER = 2;			final int frameLength = frameLength();			final byte[] data;			if (bDest.getData() != null && ((byte []) bDest.getData()).length >= (frameLength + MAX_HEADER + MAX_TRAILER))			{	data = (byte []) bDest.getData();	// reuse existing byte array				// zero out:				zeroData(data);			}			else			{	data = new byte[frameLength + MAX_HEADER + MAX_TRAILER];	// allocate new one - existing one not there or too short			}						int offsetAfterHeaders = 0;			if (prependHeader)			{					// put initial SOI marker manually, we tell RFC2035.MakeHeaders not to do it:				data[offsetAfterHeaders++] = (byte) 0xff;				data[offsetAfterHeaders++] = (byte) 0xd8;								// part of the header with "JFIF" in it, not generated by the code in RFC2035.				offsetAfterHeaders = buildJFIFHeader(data, offsetAfterHeaders);				final JpegRTPHeader jpegRtpHeaderFirst = parseJpegRTPHeader(bFirst);				offsetAfterHeaders = RFC2035.MakeHeaders(false, data, offsetAfterHeaders, jpegRtpHeaderFirst.getType(), jpegRtpHeaderFirst.getQ(), jpegRtpHeaderFirst.getWidthInBlocks(), jpegRtpHeaderFirst.getHeightInBlocks());			}			if (TRACE) System.out.println("offsetAfterHeaders=" + offsetAfterHeaders);			for (int i = 0; i < list.size(); ++i)			{	final Buffer b = (Buffer) list.get(i);				final JpegRTPHeader jpegRtpHeader = parseJpegRTPHeader(b);//				//				if (TRACE) System.out.println("Copying, length=" + (b.getLength() - JpegRTPHeader.HEADER_SIZE) + ":");//				if (TRACE) System.out.println(dump((byte[]) b.getData(), b.getOffset() + JpegRTPHeader.HEADER_SIZE, (b.getLength() - JpegRTPHeader.HEADER_SIZE) > MAX_DUMP_SIZE ? MAX_DUMP_SIZE : (b.getLength() - JpegRTPHeader.HEADER_SIZE)));//				if (TRACE) System.out.println("End copying.");								System.arraycopy((byte []) b.getData(), b.getOffset() + JpegRTPHeader.HEADER_SIZE, data, offsetAfterHeaders + jpegRtpHeader.getFragmentOffset(), b.getLength() - JpegRTPHeader.HEADER_SIZE);			}						final boolean appendEOI = !hasJPEGTrailer(data, offsetAfterHeaders + frameLength, MAX_TRAILER);	// no need to append if it is already there.			int trailing = 0;			if (appendEOI)			{				data[offsetAfterHeaders + frameLength + trailing++] = (byte) 0xff;				data[offsetAfterHeaders + frameLength + trailing++] = (byte) 0xd9;			}						bDest.setData(data);			bDest.setLength(offsetAfterHeaders + frameLength + trailing);			bDest.setOffset(0);			bDest.setTimeStamp(bFirst.getTimeStamp());	// TODO: is the source buffer timestamp in same units?			return offsetAfterHeaders;		}	}		private static void zeroData(byte[] data)	{		int len = data.length;		for (int i = 0; i < len; ++i)		{	data[i] = 0;		}	}		/**	 * Checks to see if the data begins with SOI.  Refers to JPEG headers, not JPEGRTP headers.	 */	private static boolean hasJPEGHeaders(byte[] data, int offset, int len)	{			if (len < 2)			throw new IllegalArgumentException();		if (data[offset++] != (byte) 0xff)			return false;		if (data[offset++] != (byte) 0xd8)			return false;		return true;	// starts with SOI	}		private static boolean hasJPEGTrailer(byte[] data, int offset, int len)	{			if (len < 2)			throw new IllegalArgumentException();		if (data[offset++] != (byte) 0xff)			return false;		if (data[offset++] != (byte) 0xd9)			return false;		return true;	// ends with EOI	}		// 	/**	 * info on JFIF header at http://www.obrador.com/essentialjpeg/headerinfo.htm	 * @return new offset	 */	private static int buildJFIFHeader(byte[] data, int offset)	{		// example://		 ffe000104a46494600010100000100010000		//		 JFIF marker (0xFFE0)		data[offset++] = (byte) 0xff;			data[offset++] = (byte) 0xe0;		//	    *  length -- two bytes		data[offset++] = (byte) 0x00;			data[offset++] = (byte) 0x10;			//	    * identifier -- five bytes: 4A, 46, 49, 46, 00 (the ASCII code equivalent of a zero terminated "JFIF" string)		data[offset++] = (byte) 0x4a;			data[offset++] = (byte) 0x46;			data[offset++] = (byte) 0x49;			data[offset++] = (byte) 0x46;			data[offset++] = (byte) 0x00;			//	    * version -- two bytes: often 01, 02//	          o the most significant byte is used for major revisions//	          o the least significant byte for minor revisions//		data[offset++] = (byte) 0x01;			data[offset++] = (byte) 0x01;			//	    * units -- one byte: Units for the X and Y densities//	          o 0 => no units, X and Y specify the pixel aspect ratio//	          o 1 => X and Y are dots per inch//	          o 2 => X and Y are dots per cm		data[offset++] = (byte) 0x00;			//	    * Xdensity -- two bytes		data[offset++] = (byte) 0x00;			data[offset++] = (byte) 0x01;		//	    * Ydensity -- two bytes		data[offset++] = (byte) 0x00;			data[offset++] = (byte) 0x01;			//	    * Xthumbnail -- one byte: 0 = no thumbnail		data[offset++] = (byte) 0x00;			//	    * Ythumbnail -- one byte: 0 = no thumbnail		data[offset++] = (byte) 0x00;					return offset;	}	private static final BufferFragmentOffsetComparator bufferFragmentOffsetComparator = new BufferFragmentOffsetComparator();	/**	 * Compares buffers by the fragment offset.  Assumes buffers have	 * enough data in them for a JpegRTPHeader.	 * @author Ken Larson	 *	 */	private static class BufferFragmentOffsetComparator implements Comparator	{				public int compare(Object a, Object b)		{			if (a == null && b == null)				return 0;			if (a == null)	// then a < b, return -1				return -1;			if (b == null)				return 1;	// a > b						final Buffer aCast = (Buffer) a;			final Buffer bCast = (Buffer) b;						final JpegRTPHeader jpegRtpHeaderA = JpegRTPHeader.parse((byte[]) aCast.getData(), aCast.getOffset());			final JpegRTPHeader jpegRtpHeaderB = JpegRTPHeader.parse((byte[]) bCast.getData(), bCast.getOffset());						return jpegRtpHeaderA.getFragmentOffset() - jpegRtpHeaderB.getFragmentOffset();		}	}		/**	 * Keeps track of multiple FrameAssemblers for different timestamps.  	 * This is needed because packets may arrive out of order.	 * @author Ken Larson	 *	 */	private static class FrameAssemblerCollection	{		private Map frameAssemblers = new HashMap();	// FrameAssembler keyed by long - timestamp.			public FrameAssembler findOrAdd(long timestamp)		{	FrameAssembler result = (FrameAssembler) frameAssemblers.get(new Long(timestamp));			if (result == null)			{	result = new FrameAssembler();				frameAssemblers.put(new Long(timestamp), result);			}			return result;		}		public void remove(FrameAssembler a)		{	frameAssemblers.remove(a);		}		public void removeOlderThan(long timestamp)		{			final Iterator i = frameAssemblers.entrySet().iterator();			while (i.hasNext())			{				final Entry e = (Entry) i.next();				final Long entryTimestamp = (Long) e.getKey();				if (entryTimestamp.longValue() < timestamp)				{	if (TRACE) System.out.println("Discarding incomplete frame older than " + timestamp + ", ts=" + entryTimestamp);					i.remove();				}			}					}		public void removeAllButNewestN(int n)		{			while (frameAssemblers.size() > n)			{					final long oldestTimestamp = getOldestTimestamp();				if (oldestTimestamp < 0)					throw new RuntimeException();				Long key = new Long(oldestTimestamp);				FrameAssembler a = (FrameAssembler) frameAssemblers.get(key);				String completeIncomplete = a.complete() ? "complete" : "incomplete";				if (TRACE) System.out.println("Discarding " + completeIncomplete + " frame (not in newest " + n + ", ts=" + oldestTimestamp);				frameAssemblers.remove(key);			}					}		public long getOldestTimestamp()		{			long oldestSoFar = -1;						final Iterator i = frameAssemblers.keySet().iterator();			while (i.hasNext())			{				final Long ts = (Long) i.next();				if (oldestSoFar < 0 || ts.longValue() < oldestSoFar)					oldestSoFar = ts.longValue();			}			return oldestSoFar;					}		public void clear()		{	frameAssemblers.clear();		}	}			private static final int MAX_DUMP_SIZE = 200000;		/**	 * Debugging only.  In this version, len is the length to dump to the string, not the	 * length minus offset as in StringUtils.  Returns the string instead of pringing to std out.	 */	private static String dump(byte[] data, int offset, int len)	{		return StringUtils.dump(data, offset, offset + len);	}	/**	 * Debugging only.  Dumps as hex to std out.	 */	private static void dump(Buffer b, String name)	{		if (TRACE) System.out.println(name + ", length=" + b.getLength() + " :");		if (TRACE) System.out.println(dump((byte[]) b.getData(), b.getOffset(), b.getLength() > MAX_DUMP_SIZE ? MAX_DUMP_SIZE : b.getLength()));	}}	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -