📄 qtmediaplayer.java
字号:
/* * File: QTMediaPlayer.java * Project: MPI Linguistic Application * Date: 02 May 2007 * * Copyright (C) 2001-2007 Max Planck Institute for Psycholinguistics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package mpi.eudico.client.annotator.player;import mpi.eudico.client.annotator.Constants;import mpi.eudico.client.annotator.ElanLayoutManager;import mpi.eudico.client.annotator.ElanLocale;import mpi.eudico.client.annotator.export.ImageExporter;import mpi.eudico.client.annotator.gui.FormattedMessageDlg;import mpi.eudico.client.mediacontrol.ControllerEvent;import mpi.eudico.client.mediacontrol.ControllerListener;import mpi.eudico.client.mediacontrol.ControllerManager;import mpi.eudico.client.mediacontrol.PeriodicUpdateController;import mpi.eudico.server.corpora.clomimpl.abstr.MediaDescriptor;import mpi.util.TimeFormatter;import quicktime.QTException;import quicktime.QTSession;import quicktime.app.display.QTCanvas;import quicktime.app.time.TaskAllMovies;import quicktime.app.view.QTComponent;import quicktime.app.view.QTFactory;import quicktime.io.OpenMovieFile;import quicktime.io.QTFile;import quicktime.qd.Pict;import quicktime.qd.PixMap;import quicktime.qd.QDDimension;import quicktime.qd.QDGraphics;import quicktime.qd.QDRect;import quicktime.std.StdQTConstants;import quicktime.std.clocks.ExtremesCallBack;import quicktime.std.clocks.TimeBase;import quicktime.std.clocks.TimeRecord;import quicktime.std.image.Matrix;import quicktime.std.movies.Movie;import quicktime.std.movies.MovieController;import quicktime.std.movies.TimeInfo;import quicktime.std.movies.Track;import quicktime.std.movies.media.DataRef;import quicktime.std.movies.media.GenericMedia;import quicktime.std.movies.media.MPEGMedia;import quicktime.std.movies.media.Media;import quicktime.std.movies.media.MovieMedia;import quicktime.std.movies.media.StreamMedia;import quicktime.std.movies.media.VideoMedia;import quicktime.util.QTUtils;import quicktime.util.RawEncodedImage;import java.awt.*;import java.awt.event.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.ComponentEvent;import java.awt.event.HierarchyEvent;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.awt.image.DirectColorModel;import java.awt.image.MemoryImageSource;import java.io.File;import javax.swing.JMenuItem;import javax.swing.JPopupMenu;import javax.swing.SwingUtilities;/** * The QuickTime implementation of an elan media player */public class QTMediaPlayer extends ControllerManager implements ElanMediaPlayer, ControllerListener, ActionListener { /** Holds value of property DOCUMENT ME! */ public static final int STOP_WITH_STOP_TIME = 0; /** Holds value of property DOCUMENT ME! */ public static final int STOP_WITH_PREVIEW = 1; static int scratchCount = 0; // private QTJComponent canvas; private QTComponent canvas; private float aspectRatio; /** Holds value of property DOCUMENT ME! */ protected long offset; private long milliSecondsPerSample; // private long intervalStopTime; /** Holds value of property DOCUMENT ME! */ boolean playingInterval; /** Holds value of property DOCUMENT ME! */ boolean streaming; //private PeriodicUpdateController periodicController; /** Holds value of property DOCUMENT ME! */ ExtremesCallBack endOfMediaCallback; private JPopupMenu popup; private boolean isWavPlayer; private MediaDescriptor mediaDescriptor; private ElanLayoutManager layoutManager; private boolean detached; private JMenuItem durationItem; private JMenuItem detachItem; private JMenuItem infoItem; private JMenuItem saveItem; // private VisualComponent visualComponent; //private Panel visualComponent; private Component visualComponent; /** Holds value of property DOCUMENT ME! */ int stopMode; /** Holds value of property DOCUMENT ME! */ TimeBase timeBase; /** Holds value of property DOCUMENT ME! */ long exactStopTime; /** Holds value of property DOCUMENT ME! */ protected Movie movie; //private Movie movie; private MovieController controller; private QTFile scratchFile; private String scratchName = "tmpMedia"; private boolean isEditSave = false; private int mpegImageWidth = 0; private int mpegImageHeight = 0; private boolean frameRateAutoDetected = false; private boolean rateDetectionAttempted = false; /** * Create a QTMediaPlayer for a media URL * * @param mediaDescriptor DOCUMENT ME! * * @throws NoPlayerException DOCUMENT ME! */ public QTMediaPlayer(MediaDescriptor mediaDescriptor) throws NoPlayerException { this.mediaDescriptor = mediaDescriptor; // WebStart related initialization, see at the end of this file for details initQTJNI(); try { QTSession.open(); System.out.println("QuickTime version: " + QTSession.getQTMajorVersion() + "." + QTSession.getMinorVersion() + "." + QTSession.getBugFixVersion()); String URLString = mediaDescriptor.mediaURL; System.out.println("mediaURL = " + URLString); //URLString = "rtsp://nt06.mpi.nl:80/De_Eng.mp4"; //DataRef dataRef = new DataRef(rtspURL); //Movie mov = Movie.fromDataRef(dataRef, StdQTConstants.newMovieActive | StdQTConstants4.newMovieAsyncOK); // remove the file: part of the URL String fileString = URLString; if (URLString.startsWith("file:")) { streaming = false; fileString = URLString.substring(5); QTFile qtFile = new QTFile(fileString); movie = Movie.fromFile(OpenMovieFile.asRead(qtFile)); movie.setTimeScale(1000); movie.update(); Movie editMovie = createScratchMovie(); if (editMovie != null) { movie = editMovie; isEditSave = true; } } else { // rtsp stuff streaming = true; DataRef dataRef = new DataRef(URLString); movie = Movie.fromDataRef(dataRef, StdQTConstants.newMovieActive); } quicktime.app.view.MoviePlayer player = new quicktime.app.view.MoviePlayer(movie); controller = new MovieController(movie); controller.activate(); controller.setAttached(true); // this might help to let the video be scaled correctly in the ELAN window after loading?? Matrix matrix = new Matrix(); matrix.scale(1.1f, 1.1f, 0f, 0f); movie.setMatrix(matrix); if (URLString.endsWith("wav") || mediaDescriptor.mimeType.equals( MediaDescriptor.GENERIC_AUDIO_TYPE)) { isWavPlayer = true; // ask api?? canvas = null; visualComponent = null; } else { if (URLString.startsWith("file") && (URLString.endsWith("mpg") || URLString.endsWith("mpeg"))) { MPEGVideoHeader mpegHeader = new MPEGVideoHeader(fileString); mpegImageWidth = mpegHeader.getWidth(); mpegImageHeight = mpegHeader.getHeight(); // System.out.println("MPEG w: " + mpegImageWidth + " - h: " + mpegImageHeight); } //canvas = QTFactory.makeQTJComponent(player); //canvas.asJComponent().addMouseListener(new MouseHandler()); canvas = QTFactory.makeQTComponent(movie); // canvas = QTFactory.makeQTComponent(controller); visualComponent = canvas.asComponent(); visualComponent.addMouseListener(new MouseHandler()); // visualComponent = new VisualComponent(canvas.asComponent()); // visualComponent = new Panel(); // visualComponent.setLayout(null); popup = new JPopupMenu(); durationItem = new JMenuItem(ElanLocale.getString( "Player.duration") + ": " + TimeFormatter.toString(getMediaDuration())); durationItem.setEnabled(false); infoItem = new JMenuItem(ElanLocale.getString("Player.Info")); infoItem.addActionListener(this); saveItem = new JMenuItem(ElanLocale.getString( "Player.SaveFrame")); saveItem.addActionListener(this); popup.addSeparator(); popup.add(saveItem); popup.add(infoItem); popup.add(durationItem); JPopupMenu.setDefaultLightWeightPopupEnabled(false); } // for (int i = 1; i <= movie.getTrackCount(); i++) { // quicktime.std.movies.Track t = movie.getIndTrack(i); // System.out.println("media " + t.getMedia()); // System.out.println("sample2 " + t.getMedia().sampleNumToMediaTime(1)); // } float boundsW = player.getOriginalSize().getWidth(); // 352 352 float boundsH = player.getOriginalSize().getHeight(); // 288 240 // System.out.println("w: " + boundsW + " h: " + boundsH); aspectRatio = boundsW / boundsH; System.out.println("Aspect ratio: " + aspectRatio); offset = mediaDescriptor.timeOrigin; // ask api milliSecondsPerSample = 40; // when called here, this causes a video to appear in the upper left corner of the screen, // on top of the menubar //detectFrameRate(); // callback for end of media timeBase = movie.getTimeBase(); endOfMediaCallback = new TimeBaseExtremesCallBack(timeBase, StdQTConstants.triggerAtStop); endOfMediaCallback.callMeWhen(); //stopMode = STOP_WITH_PREVIEW;//STOP_WITH_STOP_TIME;// // STOP_WITH_PREVIEW sometimes results in strange behavior after playing an interval: // the mediatime cannot be set to a value before the interval begintime stopMode = STOP_WITH_STOP_TIME; movie.goToBeginning(); if (isWavPlayer) { // this causes a video to appear in the upper left corner of the screen, // on top of the menubar TaskAllMovies.addMovieAndStart(); //stopMode = STOP_WITH_STOP_TIME;//?? } } catch (QTException e) { System.out.println("QTException while creating QT player "); e.printStackTrace(); QTSession.close(); throw new NoPlayerException("QTException while creating QT player."); } } /** * Tries to detect the frame rate, and from there calculate the ms per frame value. * Not straightforward, especially for MPEG1 and MPEG2. */ private void detectFrameRate() { try { rateDetectionAttempted = true; int scale = movie.getTimeScale(); boolean isVisual = false; Track track = null; for (int i = 0; i < movie.getTrackCount(); i++) { track = movie.getTrack(i + 1); System.out.println("Media: " + track.getMedia().getClass().getName()); if (track.getMedia() instanceof MovieMedia || track.getMedia() instanceof MPEGMedia || track.getMedia() instanceof VideoMedia || track.getMedia() instanceof StreamMedia || track.getMedia() instanceof GenericMedia) { // mpeg-2 identifies as generic media isVisual = true; break; } } if (!isVisual) { System.out.println("Media: non-video..."); return; } int numTestFrames = 30; System.out.println("duration=" + movie.getDuration() + " timescale=" + movie.getTimeScale()); movie.task(0); int flags = StdQTConstants.nextTimeStep; int[] modes = new int[] { StdQTConstants.visualMediaCharacteristic }; TimeInfo info = movie.getNextInterestingTime(flags, modes, 0, 1.0f); System.out.println(info); int numframes = 0; int lastTime = info.time; int numDuplicateTimes = 0; while ((info.time >= 0) && (numframes <= numTestFrames)) { ++numframes; info = movie.getNextInterestingTime(flags, modes, info.time, 1.0f); if (info.time == lastTime) { // something wrong?? numDuplicateTimes++; System.out.println("T: same time..."); if (numDuplicateTimes == 3) { break; } } else { lastTime = info.time; } //System.out.println("T: " + info.time); } System.out.println("frames = " + numframes + " cur time: " + info.time); float frameRate = 0f; if (numframes > numTestFrames) { frameRate = ((numframes + 1) * scale) / (float) info.time; } else if (numframes > 0) { frameRate = (numframes * scale) / (float) info.time; } else { // ms per frame can not be calculated System.out.println("framerate could not be calculated"); return; } System.out.println("framerate: " + frameRate); System.out.println("Ms per frame: " + (int) Math.round(1000 / frameRate)); if (frameRate > 0) { frameRateAutoDetected = true; milliSecondsPerSample = (int) Math.round(1000 / frameRate); } } catch (QTException qte) { qte.printStackTrace(); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public MediaDescriptor getMediaDescriptor() { return mediaDescriptor; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Movie getMovie() { if (isEditSave) { return movie; } return null; } /** * Returns the (mpeg) media width and height as read from the mpegfile. * @return the dimension according to fields in the stream headers */ public Dimension getMediaFileDimension() { if ((mpegImageWidth > 0) && (mpegImageHeight > 0)) { return new Dimension(mpegImageWidth, mpegImageHeight); } return null; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public String getFrameworkDescription() { return "Quicktime For Java Media Player"; } /** * Elan controllerUpdate Used to stop at the stop time in cooperation with * the playInterval method * * @param event DOCUMENT ME! */ public synchronized void controllerUpdate(ControllerEvent event) { } /** * play between two times. This method uses the contollerUpdate method to * detect if the stop time is passed. The setintervalStopTime method of * JMF can not be used because it gives unstable behaviour * * @param startTime DOCUMENT ME! * @param stopTime DOCUMENT ME! */ public void playInterval(long startTime, long stopTime) { if ((movie == null) || playingInterval || (stopTime <= startTime)) { return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -