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

📄 javaoggparser.java

📁 FMJ(freedom media for java)是java视频开发的新选择
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package net.sf.fmj.theora_java;import java.awt.Dimension;import java.awt.image.BufferedImage;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.util.logging.Level;import java.util.logging.Logger;import javax.media.BadHeaderException;import javax.media.Buffer;import javax.media.Duration;import javax.media.Format;import javax.media.IncompatibleSourceException;import javax.media.ResourceUnavailableException;import javax.media.Time;import javax.media.Track;import javax.media.format.AudioFormat;import javax.media.format.RGBFormat;import javax.media.format.VideoFormat;import javax.media.protocol.ContentDescriptor;import javax.media.protocol.DataSource;import javax.media.protocol.PullDataSource;import javax.media.protocol.PullSourceStream;import javax.media.util.ImageToBuffer;import net.sf.fmj.media.AbstractDemultiplexer;import net.sf.fmj.media.AbstractTrack;import net.sf.fmj.utility.LoggerSingleton;import net.sf.fmj.utility.URLUtils;import net.sf.theora_java.jheora.utils.YUVConverter;import com.fluendo.jheora.Colorspace;import com.fluendo.jheora.YUVBuffer;import com.jcraft.jogg.Packet;import com.jcraft.jogg.Page;import com.jcraft.jogg.StreamState;import com.jcraft.jogg.SyncState;/** * Uses jheora,jogg,jorbis to parse Ogg files, and decode vorbis and theora data within them. * Adapted from theora-java's jheora net.sf.theora_java.jheora.example.PlayerExample, which is adapted from player_example.c. * @author Ken Larson * */public class JavaOggParser extends AbstractDemultiplexer {	private static final Logger logger = LoggerSingleton.logger;	private static final boolean ENABLE_VIDEO = true;	private static final boolean ENABLE_AUDIO = true;			/* never forget that globals are a one-way ticket to Hell */	/* Ogg and codec state for demux/decode */	private final SyncState   oy = new SyncState();	private final Page         og = new Page();	private StreamState vo = new StreamState();	private StreamState to = new StreamState();	private final com.fluendo.jheora.Info      ti = new com.fluendo.jheora.Info();	private final com.fluendo.jheora.Comment   tc = new com.fluendo.jheora.Comment();	private final com.fluendo.jheora.State     td = new com.fluendo.jheora.State();	private final com.jcraft.jorbis.Info      vi = new com.jcraft.jorbis.Info();	private final com.jcraft.jorbis.DspState vd = new com.jcraft.jorbis.DspState();	private final com.jcraft.jorbis.Block     vb = new com.jcraft.jorbis.Block(vd);	private com.jcraft.jorbis.Comment   vc = new com.jcraft.jorbis.Comment();	private int              theora_p=0;	private int              vorbis_p=0;	private int              stateflag=0;	/* single frame video buffering */	private int          videobuf_ready=0;	private long /*ogg_int64_t*/  videobuf_granulepos=-1;	private double       videobuf_time=0;	// in seconds	/* single audio fragment audio buffering */	private int          audiobuf_fill=0;	private int          audiobuf_ready=0;	private short []audiobuf;	private long /*ogg_int64_t*/  audiobuf_granulepos=0; /* time position of last sample */	/** In bytes. */	private int          audiofd_fragsize;      /* read and write only complete fragments	                                       so that SNDCTL_DSP_GETOSPACE is	                                       accurate immediately after a bank	                                       switch */		 private final Packet op = new Packet();		// if USE_DATASOURCE_URL_ONLY is true, this is a bit of a hack - we don't really use the DataSource, we just grab its URL.  So arbitrary data sources won't work.	private final boolean USE_DATASOURCE_URL_ONLY = false;		private ContentDescriptor[] supportedInputContentDescriptors = new ContentDescriptor[] {			new ContentDescriptor("video.ogg"),			new ContentDescriptor("audio.ogg"),			new ContentDescriptor("application.ogg"),			new ContentDescriptor("application.x_ogg"),									// TODO: content descriptors are problematic, because an .ogg file will be interpreted as an audio file, and 			// another handler may try it.						// See http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions			// for mime type info.	};		// also, once this parser is able to simply extract the tracks, rather than just decode the data, 	// information on the container-less mime types is available at http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions			public JavaOggParser()	{		super();	}		private static final Object OGG_SYNC_OBJ = new Boolean(true);	// synchronize on this before using the libraries, to prevent threading problems.		private PullDataSource source;		private PullSourceStreamTrack[] tracks;			@Override	public ContentDescriptor[] getSupportedInputContentDescriptors()	{		return supportedInputContentDescriptors;	}		@Override	public Track[] getTracks() throws IOException, BadHeaderException	{		return tracks;	}		@Override	public void setSource(DataSource source) throws IOException, IncompatibleSourceException	{		final String protocol = source.getLocator().getProtocol();				if (USE_DATASOURCE_URL_ONLY)		{			if (!(protocol.equals("file")))				throw new IncompatibleSourceException();		}		else		{				if (!(source instanceof PullDataSource))			throw new IncompatibleSourceException();		}				this.source = (PullDataSource) source;			}			private FileInputStream infile;	private PullSourceStream instream;	private int buffer_data(SyncState oy) throws IOException	{			if (USE_DATASOURCE_URL_ONLY)			return buffer_data(infile, oy);		else			return buffer_data(instream, oy);	}		private int buffer_data(FileInputStream in, SyncState oy) throws IOException	{		final int BUFSIZE = 4096;		int fill = oy.buffer(BUFSIZE);		byte[] buffer2 = oy.data;		int bytes = in.read(buffer2, fill, BUFSIZE);		if (bytes < 0)			return bytes; // EOF		oy.wrote(bytes);		return (bytes);	}		private int buffer_data(PullSourceStream in, SyncState oy) throws IOException	{		final int BUFSIZE = 4096;		int fill = oy.buffer(BUFSIZE);		byte[] buffer2 = oy.data;		int bytes = in.read(buffer2, fill, BUFSIZE);		if (bytes < 0)			return bytes; // EOF		oy.wrote(bytes);		return (bytes);	}	/** dump the theora (or vorbis) comment header */	private static int dump_comments(com.fluendo.jheora.Comment tc)	{		int i, len;				logger.info("Encoded by " + tc.vendor);		if (tc.user_comments != null && tc.user_comments.length > 0)		{			logger.info("theora comment header:");			for (i = 0; i < tc.user_comments.length; i++)			{				if (tc.user_comments[i] != null)				{					final String value = tc.user_comments[i];					logger.info("\t" + value);				}			}		}		return (0);	}	/**	 * Report the encoder-specified colorspace for the video, if any. We	 * don't actually make use of the information in this example; a real	 * player should attempt to perform color correction for whatever	 * display device it supports.	 */	private static void report_colorspace(com.fluendo.jheora.Info ti)	{	    if (ti.colorspace == Colorspace.UNSPECIFIED)	    {	        /* nothing to report */	    }	    else if (ti.colorspace == Colorspace.ITU_REC_470M)	    {	    	logger.info("  encoder specified ITU Rec 470M (NTSC) color.");	    }	    else if (ti.colorspace == Colorspace.ITU_REC_470BG)	    {	    	logger.info("  encoder specified ITU Rec 470BG (PAL) color.");		}	    else	    {	    	logger.warning("warning: encoder specified unknown colorspace (" + ti.colorspace + ")");	    }	}	/** helper: push a page into the appropriate steam 	 * this can be done blindly; a stream won't accept a page that doesn't	 * belong to it	 */	private int queue_page(Page page)	{		if (theora_p != 0)			to.pagein(og);		if (vorbis_p != 0)			vo.pagein(og);		return 0;	}		private void resetVars()	{		theora_p=0;		vorbis_p=0;		stateflag=0;		/* single frame video buffering */		videobuf_ready=0;		videobuf_granulepos=-1;		videobuf_time=0;	// in seconds		/* single audio fragment audio buffering */		audiobuf_fill=0;		audiobuf_ready=0;		audiobuf=null;		audiobuf_granulepos=0; /* time position of last sample */				// TODO: we might want to re-init others to be sure.	}		// @Override	@Override	public void open() throws ResourceUnavailableException	{		System.out.println("OPEN!");				synchronized (OGG_SYNC_OBJ)		{			resetVars();						try			{				final String urlStr;				if (USE_DATASOURCE_URL_ONLY)				{					// just use the file URL from the datasource					final File f = new File(URLUtils.extractValidPathFromFileUrl(source.getLocator().toExternalForm()));					infile = new FileInputStream(f);				} else				{					source.connect();					source.start();	// TODO: stop/disconnect on stop/close.					instream = source.getStreams()[0];									}				/* start up Ogg stream synchronization layer */				oy.init();				/* init supporting Vorbis structures needed in header parsing */				vi.init();				vc.init();				/* init supporting Theora structures needed in header parsing */				//tc.init();				//ti.init();				//System.out.println("Parsing headers...");				/* Ogg file open; parse the headers */				/* Only interested in Vorbis/Theora streams */				while (stateflag == 0)				{					int ret = buffer_data(oy);					if (ret <= 0)						break;					while (oy.pageout(og) > 0)					{						StreamState test = new StreamState();						/* is this a mandated initial header? If not, stop parsing */						if (og.bos() == 0)						{							/* don't leak the page; get it into the appropriate stream */							queue_page(og);							stateflag = 1;							break;						}						test.init(og.serialno());						test.pagein(og);						test.packetout(op);												/* identify the codec: try theora */						if (ENABLE_VIDEO && theora_p == 0 && ti.decodeHeader(tc, op) >= 0)						{							/* it is theora */							to = test;							theora_p = 1;						} else if (ENABLE_AUDIO && vorbis_p == 0 && vi.synthesis_headerin(vc, op) >= 0)						{							/* it is vorbis */							vo = test;							//memcpy(&vo,&test,sizeof(test));							vorbis_p = 1;						} else						{							/* whatever it is, we don't care about it */							test.clear();						}					}					/* fall through to non-bos page parsing */				}				/* we're expecting more header packets. */				while ((theora_p != 0 && theora_p < 3) || (vorbis_p != 0 && vorbis_p < 3))				{					int ret;					/* look for further theora headers */					while (theora_p != 0 && (theora_p < 3) && ((ret = to.packetout(op))) != 0)					{						if (ret < 0)						{							throw new ResourceUnavailableException("Error parsing Theora stream headers; corrupt stream?");						}						if (ti.decodeHeader(tc, op) != 0)						{							throw new ResourceUnavailableException("Error parsing Theora stream headers; corrupt stream?");						}						theora_p++;						if (theora_p == 3)							break;					}					/* look for more vorbis header packets */					while (vorbis_p != 0 && (vorbis_p < 3) && ((ret = vo.packetout(op))) != 0)					{						if (ret < 0)						{							throw new ResourceUnavailableException("Error parsing Vorbis stream headers; corrupt stream?");						}						if (vi.synthesis_headerin(vc, op) != 0)						{							throw new ResourceUnavailableException("Error parsing Vorbis stream headers; corrupt stream?");						}						vorbis_p++;						if (vorbis_p == 3)							break;					}					/* The header pages/packets will arrive before anything else we					   care about, or the stream is not obeying spec */					if (oy.pageout(og) > 0)					{						queue_page(og); /* demux into the appropriate stream */					} else					{						final int ret2 = buffer_data(oy); /* someone needs more data */						if (ret2 <= 0)						{							throw new ResourceUnavailableException("End of file while searching for codec headers.");						}					}				}				//System.out.println("Initializing decoders...");				/* and now we have it all.  initialize decoders */				if (theora_p != 0)				{					td.decodeInit(ti);					final double fps = (double) ti.fps_numerator / (double) ti.fps_denominator;					logger.info("Ogg logical stream " + Integer.toHexString(getSerialNo(to)) + " is Theora " + ti.width + "x" + ti.height + " " + fps + " fps");					// TODO: jheora doesn't have pixelformat as a field of ti:					//	    switch(ti.pixelformat){					//	      case TheoraLibrary.OC_PF_420: System.out.printf(" 4:2:0 video\n"); break;					//	      case TheoraLibrary.OC_PF_422: System.out.printf(" 4:2:2 video\n"); break;					//	      case TheoraLibrary.OC_PF_444: System.out.printf(" 4:4:4 video\n"); break;					//	      case TheoraLibrary.OC_PF_RSVD:					//	      default:					//	  	    System.out.printf(" video\n  (UNKNOWN Chroma sampling!)\n");					//		break;					//	    }					if (ti.width != ti.frame_width || ti.height != ti.frame_height)					{	logger.warning("  Frame content is " + ti.frame_width + "x" + ti.frame_height + " with offset (" +  ti.offset_x + "," + ti.offset_y + ").");						// TODO: we need to handle cropping properly. 					}					report_colorspace(ti);					dump_comments(tc);				} else				{					/* tear down the partial theora setup */					ti.clear();					// tc.clear();				}				if (vorbis_p != 0)				{					vd.synthesis_init(vi);					vb.init(vd);					logger.info("Ogg logical stream " + Integer.toHexString(getSerialNo(vo)) + " is Vorbis " + vi.channels + " channel " + vi.rate + " Hz audio.");				} else				{					/* tear down the partial vorbis setup */					vi.clear();					// vc.clear();				}								stateflag = 0; /* playback has not begun */				VideoTrack videoTrack = null;				AudioTrack audioTrack = null;				if (theora_p != 0)				{					videoTrack = new VideoTrack();				}				if (vorbis_p != 0)				{					audioTrack = new AudioTrack();				}				if (audioTrack == null && videoTrack == null)					throw new ResourceUnavailableException("No audio or video track found");				else if (audioTrack != null && videoTrack != null)					tracks = new PullSourceStreamTrack[] { videoTrack, audioTrack };				else if (audioTrack != null)					tracks = new PullSourceStreamTrack[] { audioTrack };				else					tracks = new PullSourceStreamTrack[] { videoTrack };			} catch (IOException e)			{				logger.log(Level.WARNING, "" + e, e);				throw new ResourceUnavailableException("" + e);			}		}				super.open();	}	@Override	public void close()	{		synchronized (OGG_SYNC_OBJ)		{			if (tracks != null)			{				for (int i = 0; i < tracks.length; ++i)				{					if (tracks[i] != null)					{						tracks[i].deallocate();						tracks[i] = null;					}				}				tracks = null;			}			if (vorbis_p != 0)			{				vo.clear();				vb.clear();				vd.clear();				// vc.clear();				vi.clear();			}			if (theora_p != 0)			{				to.clear();				td.clear();				//tc.clear();				ti.clear();			}			oy.clear();			try			{				if (infile != null)					infile.close();			} catch (IOException e)			{				logger.log(Level.WARNING, "" + e, e);			}						resetVars();	// this will prevent vi.clear from being called twice, which can cause an NPE		}		super.close();	}	// @Override	@Override	public void start() throws IOException	{	}		// TODO: should we stop data source in stop?//	// @Override//	public void stop()//	{

⌨️ 快捷键说明

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