From 2ea513bab81cc40459450a0b10c6c45cc08627ef Mon Sep 17 00:00:00 2001 From: eg3p Date: Tue, 15 Oct 2002 21:22:59 +0000 Subject: [PATCH] Began implementing Quicktime for Java (QT4J) option in QD. As it is, Mac OS goes to Quicktime, while Windows goes to JMF. QT player stills needs some work. --- source/org/thdl/quilldriver/QD.java | 127 +++-- source/org/thdl/quilldriver/QDtoHTML.xsl | 67 +++ .../org/thdl/quilldriver/SmartJMFPlayer.java | 379 +++++++++++++++ .../org/thdl/quilldriver/SmartMoviePanel.java | 30 ++ .../quilldriver/SmartMoviePanelException.java | 13 + .../org/thdl/quilldriver/SmartQT4JPlayer.java | 451 ++++++++++++++++++ 6 files changed, 1030 insertions(+), 37 deletions(-) create mode 100644 source/org/thdl/quilldriver/QDtoHTML.xsl create mode 100644 source/org/thdl/quilldriver/SmartJMFPlayer.java create mode 100644 source/org/thdl/quilldriver/SmartMoviePanel.java create mode 100644 source/org/thdl/quilldriver/SmartMoviePanelException.java create mode 100644 source/org/thdl/quilldriver/SmartQT4JPlayer.java diff --git a/source/org/thdl/quilldriver/QD.java b/source/org/thdl/quilldriver/QD.java index 4e05558..7693a9a 100644 --- a/source/org/thdl/quilldriver/QD.java +++ b/source/org/thdl/quilldriver/QD.java @@ -45,7 +45,6 @@ import org.thdl.util.ThdlDebug; import org.thdl.util.ThdlActionListener; import org.thdl.util.ThdlAbstractAction; - public class QD extends JDesktopPane { /** When opening a file, this is the only extension QuillDriver cares about. This is case-insensitive. */ @@ -58,7 +57,7 @@ public class QD extends JDesktopPane { protected SpeakerTable speakerTable; //video related - protected QDPlayer player = null; + protected SmartMoviePanel player = null; //frame related protected JInternalFrame videoFrame = null; @@ -90,7 +89,7 @@ public class QD extends JDesktopPane { protected TibetanDocument findDoc = null; protected TibetanDocument replaceDoc = null; -protected URL keyboard_url = null; + protected URL keyboard_url = null; public QD(ResourceBundle messages) { @@ -109,7 +108,7 @@ public QD(ResourceBundle messages) { public void theRealActionPerformed(ActionEvent e) { new TimePoint(pane, clockIcon, tcp.getOutTime()); tcp.setInTime(tcp.getOutTime().intValue()); - tcp.setOutTime(player.getLastTime()); + tcp.setOutTime(player.getEndTime()); } }; @@ -124,7 +123,7 @@ public QD(ResourceBundle messages) { if (p1 == p2) pane.setCaretPosition(pane.getCaretPosition()-1); tcp.setInTime(tcp.getOutTime().intValue()); - tcp.setOutTime(player.getLastTime()); + tcp.setOutTime(player.getEndTime()); } }; @@ -216,7 +215,7 @@ private void startTimer() { timer.schedule(new TimerTask() { public void run() { - if (player.cmd_isSized()) + if (player.isInitialized()) { timer.cancel(); @@ -275,7 +274,7 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene if (e.getButton() == MouseEvent.BUTTON1) playSegment(); else { - SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getLastTime(), 10); + SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getEndTime(), 10); JSpinner spinner = new JSpinner(snm1); spinner.setPreferredSize(new Dimension(100, 40)); spinner.setValue(getTime()); @@ -306,17 +305,22 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene public void playSegment() { int i=pos.getOffset(); System.out.println(String.valueOf(i)); - for (i++; i in.intValue()) - player.cmd_play(in, out); + if (out.intValue() > in.intValue()) { + try { + player.cmd_playSegment(in, out); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); + } + } } }); JPanel ps = new JPanel(); @@ -483,14 +498,26 @@ class TimeCodeManager extends JPanel { playButton.addActionListener(new ThdlActionListener() { public void theRealActionPerformed(ActionEvent e) { - if (player != null) - player.cmd_play(); + if (player != null) { + try { + player.cmd_playOn(); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); + } + } } }); pauseButton.addActionListener(new ThdlActionListener() { public void theRealActionPerformed(ActionEvent e) { - if (player != null) - player.cmd_stop(); + if (player != null) { + try { + player.cmd_stop(); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); + } + } } }); */ @@ -578,8 +605,13 @@ public void setMedia(File f) { media = f; mediaField.setText(media.getPath()); if (player != null) { - player.cmd_stop(); - player.destroy(); + try { + player.cmd_stop(); + player.destroy(); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); + } videoFrame.getContentPane().remove(player); videoFrame.getContentPane().invalidate(); videoFrame.getContentPane().validate(); @@ -597,13 +629,33 @@ public void setMedia(File f) { URL url = f.toURL(); if (player != null) { - player.cmd_stop(); - player.destroy(); + try { + player.cmd_stop(); + player.destroy(); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); + } + } + + +//if user properties opt for qt4j instead of jmf, then load qt4j instead + + String os = System.getProperty("os.name").toLowerCase(); + try { + if (os.indexOf("windows") != -1) { + player = new SmartJMFPlayer(QD.this, url); + } else if (os.indexOf("mac") != -1) { + player = new SmartQT4JPlayer(); + player.loadMovie(url); + } + media = f; + mediaField.setText(media.getPath()); + startTimer(); + } catch (SmartMoviePanelException smpe) { + smpe.printStackTrace(); + ThdlDebug.noteIffyCode(); } - player = new QDPlayer(QD.this, url); - media = f; - mediaField.setText(media.getPath()); - startTimer(); } catch (MalformedURLException murle) { murle.printStackTrace(); ThdlDebug.noteIffyCode(); @@ -893,6 +945,7 @@ if (keyboard_url != null) { dp.registerKeyboard(); // project.tName.setupKeyboard(); + // project.tTask.setupKeyboard(); sharedDP.setupKeyboard(); sharedDP2.setupKeyboard(); diff --git a/source/org/thdl/quilldriver/QDtoHTML.xsl b/source/org/thdl/quilldriver/QDtoHTML.xsl new file mode 100644 index 0000000..2ce6549 --- /dev/null +++ b/source/org/thdl/quilldriver/QDtoHTML.xsl @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + +

+ + + + + + + + + + +

+Work History +

+ + + + + + + + +
NameTaskStart TimeDuration
+ + + + + + + + minutes + + + + \ No newline at end of file diff --git a/source/org/thdl/quilldriver/SmartJMFPlayer.java b/source/org/thdl/quilldriver/SmartJMFPlayer.java new file mode 100644 index 0000000..7912caf --- /dev/null +++ b/source/org/thdl/quilldriver/SmartJMFPlayer.java @@ -0,0 +1,379 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.quilldriver; + +import java.util.*; +import java.net.*; +import javax.media.*; +import java.awt.*; +import javax.swing.*; +import javax.swing.event.*; + +import org.thdl.util.ThdlDebug; + +/*-----------------------------------------------------------------------*/ +public class SmartJMFPlayer extends SmartMoviePanel implements ControllerListener +{ + private EventListenerList listenerList = new EventListenerList(); + + public URL mediaURL; + + private Player player = null; + private Component visualComponent = null; + private Component controlComponent = null; + private Panel panel = null; + private JPanel vPanel = null; + + private Container parent = null; + + private java.util.Timer timer = null; + private Time stopTime = null; + private Time pauseTime = null; + private boolean stillLoadingVideo = false; + private boolean isMediaAudio = false; + private boolean isSized = false; + + private Float to = null; +/*-----------------------------------------------------------------------*/ + public SmartJMFPlayer(Container p, URL sound) throws SmartMoviePanelException { + super( new GridLayout() ); + parent = p; + loadMovie(sound); + } + public void loadMovie(URL sound) throws SmartMoviePanelException { + if (mediaURL != null) { + cmd_stop(); + destroy(); + } + mediaURL = sound; + start(); + } + public void destroy() throws SmartMoviePanelException { + if (false) + throw new SmartMoviePanelException(); + player.close(); + } +/*-----------------------------------------------------------------------*/ + private void start() { + try { + player = Manager.createPlayer(mediaURL); + player.addControllerListener(this); + } catch (javax.media.NoPlayerException e) { + System.err.println("noplayer exception"); + e.printStackTrace(); + ThdlDebug.noteIffyCode(); + return; + } catch (java.io.IOException ex) { + System.err.println("IO exception"); + ex.printStackTrace(); + ThdlDebug.noteIffyCode(); + return; + } + if (player != null) + player.realize(); + } +/*-----------------------------------------------------------------------*/ + public void displayBorders(boolean borders) throws SmartMoviePanelException + { + if (false) + throw new SmartMoviePanelException(); + } + public void displayController(boolean controller) throws SmartMoviePanelException + { + if (false) + throw new SmartMoviePanelException(); + + } + public boolean isInitialized() { + return isSized; + } +/*-----------------------------------------------------------------------*/ + public synchronized void controllerUpdate(ControllerEvent event) { + if (player == null) + return; + if (event instanceof RealizeCompleteEvent) { + System.out.println("received RealizeCompleteEvent event"); + if (visualComponent == null) { + if (panel == null) { + setLayout(new GridLayout(1,1)); + vPanel = new JPanel(); + vPanel.setLayout( new BorderLayout() ); + if ((visualComponent = player.getVisualComponent())!= null) + vPanel.add("Center", visualComponent); + else { + isMediaAudio = true; + stillLoadingVideo = false; + } + if (!stillLoadingVideo) + { + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + } + add(vPanel); + } + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + isSized = true; + if (stillLoadingVideo) + player.start(); + } else if (event instanceof StartEvent) { + StartEvent se = (StartEvent)event; + Time t = se.getMediaTime(); + long longt = t.getNanoseconds(); + Float from = new Float(longt); + float f = (from.floatValue() / 1000000000); + from = new Float(f); + t = player.getStopTime(); + longt = t.getNanoseconds(); + to = new Float(longt); + f = (to.floatValue() / 1000000000); + to = new Float(f); + if (timer != null) + { + timer.cancel(); + timer = null; + } + timer = new java.util.Timer(true); + timer.schedule(new TimerTask() { + public void run() { + //this is specifically for the MPG stop time bug + if (stopTime != null) + if (player.getMediaTime().getNanoseconds() > stopTime.getNanoseconds()) + player.stop(); + }}, 0, 15); + } else if (event instanceof StopEvent) { + pauseTime = player.getMediaTime(); + + + /*messy problems require messy solutions: + if the slider is present, dragging it while playing creates + a RestartingEvent, and if I set the media time here it messes up + and barely plays at all (maybe because it cancels the previously + set media time? - I don't know). + + but it seems that if you press the play/pause button on the + control widget, then you need to set the media time upon stop + (probably because of problem noted below, namely that you get + weird results if you do player.start() without setting the media + time.*/ + + if (!(event instanceof RestartingEvent)) + player.setMediaTime(pauseTime); + +// player.setStopTime(Clock.RESET); + stopTime = null; + + System.out.println("received StopEvent"); + + if (timer != null) + { + timer.cancel(); + timer = null; + } + if (stillLoadingVideo) + { + System.out.println("received EndOfMediaEvent"); + stillLoadingVideo = false; + player.stop(); + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } else if ( event instanceof CachingControlEvent) { + CachingControlEvent e = (CachingControlEvent) event; + System.out.println("got CachingControlEvent: " + e); + if (!isMediaAudio) + stillLoadingVideo = true; + } else if (event instanceof ControllerErrorEvent) { + player = null; + System.err.println("*** ControllerErrorEvent *** " + ((ControllerErrorEvent)event).getMessage()); + } else if (event instanceof PrefetchCompleteEvent) { + if (panel != null) { + panel.invalidate(); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } +/*-----------------------------------------------------------------------*/ + public void cmd_stop() throws SmartMoviePanelException { + if (player == null) + throw new SmartMoviePanelException("no player"); + try { + player.stop(); + } catch (NotRealizedError err) { + throw new SmartMoviePanelException("JMF player not realized"); + } + } + public void cmd_playOn() throws SmartMoviePanelException { + if (stillLoadingVideo || player == null) { + throw new SmartMoviePanelException("no player or video still loading"); + } + if (player.getState() == Controller.Started) + return; + + if (pauseTime == null) + player.setMediaTime(new Time(0.0)); + else + player.setMediaTime(pauseTime); + if (player.getTargetState() < Player.Started) { + player.setStopTime(Clock.RESET); + player.prefetch(); + } + player.start(); + } + public void cmd_playSegment(Integer from, Integer to) throws SmartMoviePanelException { + if (from == null || player == null || stillLoadingVideo) + throw new SmartMoviePanelException("no player or video still loading"); + + final Time startTime = new Time(from.longValue() * 1000000); + try { + if (player.getState() == Controller.Started) + player.stop(); + while (player.getState() == Controller.Unrealized) + ; + if (to == null) { + stopTime = null; + player.setStopTime(Clock.RESET); + } else { + stopTime = new Time(to.longValue() * 1000000); + player.setStopTime(stopTime); + } + player.setMediaTime(startTime); + player.prefetch(); + player.start(); + } catch(NotRealizedError err) { + throw new SmartMoviePanelException("JMF player not realized"); + } + } +/*-----------------------------------------------------------------------*/ + public int getCurrentTime() { + if (player == null) + return -1; + if (player.getState() < Controller.Realized) + return -1; + long currTime = player.getMediaNanoseconds(); + return new Long(currTime / 1000000).intValue(); + } + public int getEndTime() { + Time t = player.getDuration(); + long l = t.getNanoseconds(); + return new Long(l / 1000000).intValue(); + } +/*-----------------------------------------------------------------------*/ +} + +/* + +After pause the MPEG video and playing it again it gets faster +Author: vladshtr +In Reply To: After pause the MPEG video and playing it again it gets faster +Mar 1, 2001 6:25 PM + +Reply 1 of 1 + + +The problem is in the setting the Media time. + +The safety way is to always set new media time with the +following method: setMediaTime(Time time); .... if you want to +use it after +-player.stop(); used as real stop you can use setMediaTime(new +Time(0.0)); +-player.stop(); used as real pause you have to use the +combination: +player.stop(); +Time currentTime = player.getMediaTime(); +//........ +player.setMediaTime(currentTime); +player.start(); + + +Re: (urgent) when you pause and resume, video plays at rate > 1 +Author: seertenedos +In Reply To: (urgent) when you pause and resume, video plays at rate > 1 +Aug 11, 2002 11:36 PM + +Reply 1 of 1 + + +I found a solution for this problem for those that are interested. + +what you have to do is store the time just before you pause and then set the +time just before you play. here is a copy of my pause and play methods + +// Start the player +private void play() { +if (player != null) +{ +if (pauseTime != null) +{ +player.setMediaTime(pauseTime); +} +if (player.getTargetState() < Player.Started) +player.prefetch(); +player.start(); +} +} + +// Pause the player +private void pause() { +if (player != null) +pauseTime = player.getMediaTime(); +player.stop(); +} + + +that should solve your pause play problems! + +> The problem is below. It seems quite a few people are +> having this problem but i have not seen a solution +> around. I really need a solution to this problem as +> the whole point of my application is that it plays +> divx and mpeg videos. At the moment i have divx +> movies playing through the mpeg demuxer as the avi one +> stuffed up the audio. I think that is the reason it +> affects both divx and mpeg. My application is due in +> one week and my client is not going to be very happy +> if this problem happens every time they pause then +> play the video. +> The player is for divx movies. If anyone knows how to +> solve this problem or how to make it so you can pause +> and resume divx movies please respond. +> +> Pause and Resume playback. +> The video plays at a high rate and there is no audio. +> Problem doesn't appear while seeking. +> +> +> +> + +*/ diff --git a/source/org/thdl/quilldriver/SmartMoviePanel.java b/source/org/thdl/quilldriver/SmartMoviePanel.java new file mode 100644 index 0000000..ee4c233 --- /dev/null +++ b/source/org/thdl/quilldriver/SmartMoviePanel.java @@ -0,0 +1,30 @@ +package org.thdl.quilldriver; + +import java.awt.*; +import java.net.*; + +public abstract class SmartMoviePanel extends Panel +{ +//helper methods - initialize + public abstract void displayBorders(boolean borders) throws SmartMoviePanelException; + public abstract void displayController(boolean controller) throws SmartMoviePanelException; + public abstract void loadMovie(URL mediaUrl) throws SmartMoviePanelException; + +//helper methods - control media + public abstract void cmd_playOn() throws SmartMoviePanelException; + public abstract void cmd_playSegment(Integer startTime, Integer stopTime) throws SmartMoviePanelException; + public abstract void cmd_stop() throws SmartMoviePanelException; + +//helper methods - media status + public abstract boolean isInitialized(); + public abstract int getCurrentTime(); + public abstract int getEndTime(); + +//helper methods - cleanup + public abstract void destroy() throws SmartMoviePanelException; +//constructor + public SmartMoviePanel(GridLayout layout) + { + super(layout); + } +} diff --git a/source/org/thdl/quilldriver/SmartMoviePanelException.java b/source/org/thdl/quilldriver/SmartMoviePanelException.java new file mode 100644 index 0000000..47fde76 --- /dev/null +++ b/source/org/thdl/quilldriver/SmartMoviePanelException.java @@ -0,0 +1,13 @@ +package org.thdl.quilldriver; + +public class SmartMoviePanelException extends Exception +{ + public SmartMoviePanelException() + { + super(); + } + public SmartMoviePanelException(String msg) + { + super(msg); + } +} diff --git a/source/org/thdl/quilldriver/SmartQT4JPlayer.java b/source/org/thdl/quilldriver/SmartQT4JPlayer.java new file mode 100644 index 0000000..0d1eaa2 --- /dev/null +++ b/source/org/thdl/quilldriver/SmartQT4JPlayer.java @@ -0,0 +1,451 @@ +package org.thdl.quilldriver; + +import java.awt.*; +import java.net.*; +import quicktime.*; +import quicktime.app.*; +import quicktime.app.display.*; +import quicktime.app.players.*; +import quicktime.app.image.*; //required for the QT4JAVA test +import quicktime.std.*; +import quicktime.std.movies.*; +import quicktime.std.movies.media.DataRef; +import quicktime.io.*; +import quicktime.app.time.*; +import quicktime.std.clocks.*; + +public class SmartQT4JPlayer extends SmartMoviePanel +{ +//attributes + private QTCanvas canvas; //this hands over screen real estate to + //native graphics that quicktime can control + + private QTPlayer player; //this is the the client for the canvas + //In my app it will get set to a + // quicktime.app.player object + + private Movie movie; //this is the content used in + //QTDrawable player's quicktime.app.player constructor + + private MovieController controller; + + private TimeBaseRateCallBack theMoviesRateCallback; + private TimeBaseExtremesCallBack theMoviesExtremeCallback; + private TimeBaseTimeJumpCallBack theMoviesTimeJumpCallback; + private TimeBaseTimeCallBack theMoviesTimeCallback; + private TimeBaseTimeCallBackStopper theStopper; + +//accessors + public void setPlayer(QTPlayer player) + { + this.player = player; + } + public QTPlayer getPlayer() + { + return player; + } + + public void setMovie(Movie movie) + { + this.movie = movie; + } + public void setMovie(URL movieURL) + { + try + { + DataRef movieDataRef = new DataRef( "file://" + movieURL.getFile() ); + Movie m = new Movie(); + m = m.fromDataRef( movieDataRef, StdQTConstants.newMovieActive ); + setMovie(m); + getMovie().setTimeScale(1000); + } + catch(QTException qte) + { + qte.printStackTrace(); + System.out.println( movieURL.toString() ); + } + } + public Movie getMovie() + { + return movie; + } + + public void setController(MovieController controller) + { + this.controller = controller; + } + public MovieController getController() + { + return controller; + } + + public void setCanvas(QTCanvas canvas) + { + this.canvas = canvas; + } + public QTCanvas getCanvas() + { + return canvas; + } + + +//contract methods - initialize + public void displayBorders(boolean borders) throws SmartMoviePanelException + { + } + public void displayController(boolean controller) throws SmartMoviePanelException + { + } + public void loadMovie(URL mediaURL) throws SmartMoviePanelException + { + setMovie(mediaURL); + try + { + getCanvas().removeClient(); + setController( new MovieController( getMovie() )); + getController().setKeysEnabled(true); + setPlayer(new QTPlayer( getController() )); + getCanvas().setClient( getPlayer(), true ); + this.add( getCanvas() ); + TimeBase theMoviesTimeBase = getMovie().getTimeBase(); + + // this callback is triggered when the rate of the movie changes + theMoviesRateCallback = new TimeBaseRateCallBack(theMoviesTimeBase, 1.0F, StdQTConstants.triggerRateChange); +// theMoviesRateCallback.callMeWhen(); + + // this callback is triggered when the movie ends + theMoviesExtremeCallback = new TimeBaseExtremesCallBack(theMoviesTimeBase, StdQTConstants.triggerAtStop); +// theMoviesExtremeCallback.callMeWhen(); + + // this callback is triggered when the movie starts + theMoviesExtremeCallback = new TimeBaseExtremesCallBack(theMoviesTimeBase, StdQTConstants.triggerAtStart); +// theMoviesExtremeCallback.callMeWhen(); + + // this callback is triggered when there is a jump in the timebase + theMoviesTimeJumpCallback = new TimeBaseTimeJumpCallBack(theMoviesTimeBase); +// theMoviesTimeJumpCallback.callMeWhen(); + + // this schedules the time callback once every 2 seconds + // this callback is triggered at a specific time interval + theMoviesTimeCallback = new TimeBaseTimeCallBack(theMoviesTimeBase, 1, 2, StdQTConstants.triggerTimeEither); +// theMoviesTimeCallback.callMeWhen(); + + //Using the Timer class you can get rescheduled properly and get callbacks at the set intervals. It uses the same callback + //mechanism of internally of the TimeCallback. + //Its recomended to use this Timer class to do callbacks , which would take care of the time base time changes and + //recscheduling of the tickle method . + Timer timer = new Timer(1, 2, new Tickler(), getMovie() ); +// timer.setActive(true); + + } + catch(QTException qte) + { + qte.printStackTrace(); + } + } + +//contract methods - control media + public void cmd_playOn() throws SmartMoviePanelException + { + try + { + getPlayer().setRate(1.0F); + } + catch(QTException qte) + { + qte.printStackTrace(); + } + } + public void cmd_playSegment(Integer startTime, Integer stopTime) throws SmartMoviePanelException + { + try + { + getPlayer().setTime( startTime.intValue() ); + + int value=stopTime.intValue(); + TimeBase theMoviesTimeBase = getPlayer().getTimeBase(); + theStopper = new TimeBaseTimeCallBackStopper(theMoviesTimeBase, 1000, value, StdQTConstants.triggerTimeEither); + theStopper.callMeWhen(); + + cmd_playOn(); + + System.out.println("Set start time to " +startTime.intValue() ); + System.out.println("Set stop time " +stopTime.intValue() ); + System.out.println("Current time " +getPlayer().getTime() ); + System.out.println("Time Stopper's stop trigger " +theStopper.getCallTime() ); + System.out.println("Player Scale: " +getPlayer().getScale() ); + System.out.println("Movie Scale: " +getMovie().getTimeScale() ); + + } + catch (SmartMoviePanelException smpe) {} + catch (StdQTException sqte) {} + catch (QTException qte) {} + } + public void cmd_stop() throws SmartMoviePanelException + { + try + { + getPlayer().setRate(0.0F); + } + catch(QTException qte) + { + qte.printStackTrace(); + } + } + +//contract methods - media status + public boolean isInitialized() + { + return true; + } + public int getCurrentTime() + { + return 0; + } + public int getEndTime() + { + return 0; + } + +//helper methods - QT4J + public void startupQTSession() + { + //Initialize a QT session and add a test image + + //These three try/catch blocks come from PlayMovie.java copyright + // Apple Co. I'm using it to test that QT and QT4Java exist + try + { + if (QTSession.isInitialized() == false) + QTSession.open(); + } + catch (NoClassDefFoundError er) + { + add (new Label ("Can't Find QTJava classes"), "North"); + add (new Label ("Check install and try again"), "South"); + } + catch (SecurityException se) + { + // this is thrown by MRJ trying to find QTSession class + add (new Label ("Can't Find QTJava classes"), "North"); + add (new Label ("Check install and try again"), "South"); + } + catch (Exception e) + { + // do a dynamic test for QTException + //so the QTException class is not loaded unless + // an unknown exception is thrown by the runtime + if (e instanceof ClassNotFoundException || e instanceof java.io.FileNotFoundException) + { + add (new Label ("Can't Find QTJava classes"), "North"); + add (new Label ("Check install and try again"), "South"); + } + else if (e instanceof QTException) + { + add (new Label ("Problem with QuickTime install"), "North"); + if (((QTException)e).errorCode() == -2093) + add (new Label ("QuickTime must be installed"), "South"); + else + add (new Label (e.getMessage()), "South"); + } + } + try + { + setCanvas( new QTCanvas(QTCanvas.kInitialSize, 0.5F, 0.5F) ); + this.add( getCanvas() ); + getCanvas().setClient(ImageDrawer.getQTLogo(), true); + } + catch(QTException qte) + { + qte.printStackTrace(); + } + } + + public void destroy() + { + QTSession.close(); + System.out.println("Clean up performed."); + } + +//constructor + public SmartQT4JPlayer(Container cont, URL mediaURL) + { + super( new GridLayout() ); + startupQTSession(); + } + public SmartQT4JPlayer() + { + super( new GridLayout() ); + startupQTSession(); + } + +// inner classes + /** + * This class extends the RateCallBack class and provides an execute routine + * that is invoked by the callback when the rate of the movie changes + * + *@author travis + *@created September 3, 2002 + */ + + public class TimeBaseRateCallBack extends RateCallBack + { + public TimeBaseRateCallBack(TimeBase tb, float rate, int flag) throws QTException + { + super(tb, rate, flag); + } + + public void execute() + { + try + { + System.out.println("--- RateCallBack@ratechange---"); + + cancel(); + //reschedule + callMeWhen(); + + } catch (StdQTException e) + {} + } + } + + /** + * This class implements a method that is called when the movie stops + * + *@author travis + *@created September 3, 2002 + */ + + class TimeBaseExtremesCallBack extends quicktime.std.clocks.ExtremesCallBack + { + + public TimeBaseExtremesCallBack(TimeBase tb, int flag) throws QTException + { + super(tb, flag); + } + + public void execute() + { + try + { + System.out.println("--- ExtremesCallBack@stop---"); + + //cancel + cancel(); + //reschedule + callMeWhen(); + } + catch (StdQTException e) + {} + } + } + + /** + * This class extends the TimeJumpCallBack class to provide a method that is + * called when the timebase of the movie changes (IE, if the user clicks in + * the movie controller) + * + *@author travis + *@created September 3, 2002 + */ + + class TimeBaseTimeJumpCallBack extends quicktime.std.clocks.TimeJumpCallBack + { + public TimeBaseTimeJumpCallBack(TimeBase tb) throws QTException + { + super(tb); + } + + public void execute() + { + try + { + System.out.println("--- TimeJumpCallBack---"); + + cancel(); + //reschedule + callMeWhen(); + } + catch (StdQTException e) + {} + } + } + + class TimeBaseTimeCallBack extends quicktime.std.clocks.TimeCallBack + { + private int callTime; + private TimeBase theTimeBase; + + public void setCallTime(int time) + { + callTime=time; + value=callTime; + } + public int getCallTime() + { + return callTime; + } + public void execute() + { + try + { + System.out.println("--- TimeCallBack@triggerTimeEither--- called at:" + timeWhenCalledMsecs + "msecs"); + + cancel(); + //reschedule + callMeWhen(); + } + catch (StdQTException e) + {} + } + public TimeBaseTimeCallBack(TimeBase tb, int scale, int value, int flags) throws QTException + { + super(tb, scale, value, flags); +// setCallTime(value/1000); + setCallTime(value); + theTimeBase = tb; + } + } + + class TimeBaseTimeCallBackStopper extends TimeBaseTimeCallBack + { + public void execute() + { + try + { + System.out.println("---TimeCallBackStopper--- called at:" + timeWhenCalledMsecs + "msecs"); + System.out.println("---TimeCallBackStopper--- callTime is: " + getCallTime() + " msecs"); + cmd_stop(); + System.out.println("---TimeCallBackStopper--- Player time is: " + getPlayer().getTime() + " msecs"); + System.out.println("---TimeCallBackStopper--- Movie time is: " + getMovie().getTime() + " msecs"); + + cancelAndCleanup(); + //reschedule + //callMeWhen(); + } + catch (StdQTException e) {} + catch (SmartMoviePanelException smpe) {} + } + public TimeBaseTimeCallBackStopper(TimeBase tb, int scale, int value, int flags) throws QTException + { + super(tb, scale, value, flags); + } + + } + + public class Tickler implements Ticklish + { + public void timeChanged(int newTime) throws QTException + { + System.out.println("* * * * Timer Class * * * timeChanged at:" + newTime); + } + + public boolean tickle(float er, int time) throws QTException + { + System.out.println("* * * * Timer Class * * * tickle at:" + time); + return true; + } + } + +}