在这一系列的第一部分中,我描述了在JMF(JAVA媒体帧工作器 下同)的帮助下,怎样将一部电影片断插入JAVA 3D场景中。这个执行过程使用Model-View-Controller设计模式。
作者:builder.com.cn 2007年8月24日
关键字:
想要得到更多信息,请查询QuickTime指南的movie section
打开动画视频媒体
QTSnapper构造器打开动画:
// globalsprivate boolean isSessionOpen = false;private OpenMovieFile movieFile;private Movie movie;// in the constructor,// start a QuickTime sessionQTSession.open();isSessionOpen = true;// open the moviemovieFile = OpenMovieFile.asRead( new QTFile(fnm) );movie = Movie.fromFile(movieFile);
在QuickTime使用之前调用QTSession.open()方法将其初始化.在终止时相应的调用QTSession.close()方法.
轨迹定位和媒体访问
// more globalsprivate Track videoTrack;private Media vidMedia;// in the constructor, // extract the video track from the movievideoTrack = movie.getIndTrackType(1, StdQTConstants.videoMediaType, StdQTConstants.movieTrackMediaType);if (videoTrack == null) { System.out.println("Sorry, not a video"); System.exit(0);}// get the media used by the video trackvidMedia = videoTrack.getMedia();
一旦媒体打开,从中提取各种信息
// more globalsprivate MediaSample mediaSample;private int numSamples; // number of samplesprivate int sampIdx; // current sample indexprivate int width; // frame widthprivate int height; // frame height// in the constructornumSamples = vidMedia.getSampleCount();sampIdx = 1; // get first sample in the trackmediaSample = vidMedia.getSample(0, vidMedia.sampleNumToMediaTime(sampIdx).time,1);// store width and height of image in the sampleImageDescription imgDesc = ImageDescription) mediaSample.description;width = imgDesc.getWidth();height = imgDesc.getHeight();
sampIdx作为计数器将在抽样中被重复调用(抽样于位置1开始).
动画图像的宽度和高度由第一个抽样获得,接下来所有的抽样都是同样的尺寸.
测算 FPS
由QTSnapper返回的 帧数/秒 将在稍后被用作类的不同使用方法的比较参数.构造器中必要的参数已被初始化.
// frame rate globalsprivate long startTime;private long numFramesMade;// initialize them in the constructorstartTime = System.currentTimeMillis(); numFramesMade = 0;
结束
将应用程序结束时,QTSnapper类中的stopMovie()方法将被调用.它报告FPS,关闭QuickTime.
// globalsprivate DecimalFormat frameDf = new DecimalFormat("0.#"); // 1 dpsynchronized public void stopMovie(){ if (isSessionOpen) { // report frame rate long duration = System.currentTimeMillis() - startTime; double frameRate = ((double) numFramesMade*1000.0)/duration; System.out.println("FPS: " + frameDf.format(frameRate)); QTSession.close(); // close down QuickTime isSessionOpen = false; }}
由于stopMovie()和getFrame()是同步的,所以从动画中提取帧和QuickTime关闭在时间上是不可能同时进行.
缓存帧
getFrame()返回一次抽样样品,称作BufferedImage对象.被选择的帧利用索引指数存贮在sampIdx.
// globalsprivate BufferedImage img, formatImg;synchronized public BufferedImage getFrame(){ if (!isSessionOpen) return null; if (sampIdx > numSamples) // start back with the first sample sampIdx = 1; try { /* Get the sample starting at the specified index time */ TimeInfo ti = vidMedia.sampleNumToMediaTime(sampIdx); mediaSample=vidMedia.getSample(0,ti.time,1); sampIdx++; writeToBufferedImage(mediaSample, img); // resize img, writing it to formatImg Graphics g = formatImg.getGraphics(); g.drawImage(img, 0, 0, FORMAT_SIZE, FORMAT_SIZE, null); // Overlay current t