📄 abstractplayer.java
字号:
package net.sf.fmj.ejmf.toolkit.media;import java.awt.Component;import java.io.IOException;import java.util.Vector;import javax.media.Clock;import javax.media.ClockStartedError;import javax.media.ClockStoppedException;import javax.media.Controller;import javax.media.ControllerErrorEvent;import javax.media.ControllerEvent;import javax.media.ControllerListener;import javax.media.DurationUpdateEvent;import javax.media.GainControl;import javax.media.IncompatibleSourceException;import javax.media.IncompatibleTimeBaseException;import javax.media.NotRealizedError;import javax.media.Player;import javax.media.ResourceUnavailableEvent;import javax.media.Time;import javax.media.TransitionEvent;import javax.media.protocol.DataSource;import net.sf.fmj.ejmf.toolkit.media.event.ManagedControllerErrorEvent;/** * The AbstractPlayer class provides a basic implementation of a * javax.media.Player. The abstract "do" methods from * AbstractController have been implemented here to provide support * for management of multiple Controllers. Subclasses of this * class should instead implement the following abstract "do" * methods to transition their Controller: * <p> * <UL> * <LI>doPlayerRealize()</LI> * <LI>doPlayerPrefetch()</LI> * <LI>doPlayerSyncStart()</LI> * <LI>doPlayerDeallocate()</LI> * <LI>doPlayerStop()</LI> * </UL> * <p> * The rules for implementation of these methods are identical to * those for implementing a AbstractController: * <p> * <OL> * <LI>Do not return until the state change is complete. Once the * state change is complete, return ASAP.</LI> * <p> * <LI>Do not call one another. They will be called in the correct * order at the correct time.</LI> * <p> * <LI>Do not set the current or target states. They are set * automatically.</LI> * <p> * <LI>Do not post any TransitionEvents. They are posted * automatically.</LI> * <p> * <LI>Do not call any of the Clock routines. They will be called * automatically.</LI> * <p> * <LI>Return true if successful. If unsuccessful, post an * appropriate ControllerErrorEvent and return false.</LI> * <p> * <LI>When the end of the media has been reached, call endOfMedia(). * This will post an EndOfMediaEvent and set the appropriate * states. Do not post an EndOfMediaEvent in any other way.</LI> * </OL> * <p> * Other abstact methods that should be implemented are: * <p> * <UL> * <LI>doPlayerClose()</LI> * <LI>doPlayerSetMediaTime()</LI> * <LI>doPlayerSetRate()</LI> * <LI>getPlayerStartLatency()</LI> * <LI>getPlayerDuration()</LI> * </UL> * * <p> * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046). Used with permission. * </p> * @author Steve Talley */public abstract class AbstractPlayer extends AbstractController implements Player, ControllerListener{ private DataSource source; private Vector controllers; private Time duration; private ControllerErrorEvent controllerError; private GainControl gainControl; private Component visualComponent; private Component controlPanelComponent; /** * Construct a AbstractPlayer. */ public AbstractPlayer() { super(); controllers = new Vector(); duration = new Time(0); } //////////////////////////////////////////////////////////// // // Abstract methods // //////////////////////////////////////////////////////////// /** * Implement to realize the Player. * <p> * This method should not be called directly. Instead, call * realize(). * * @return True if successful, false otherwise. */ public abstract boolean doPlayerRealize(); /** * Implement to prefetch the Player. * <p> * This method should not be called directly. Instead, call * prefetch(). * * @return True if successful, false otherwise. */ public abstract boolean doPlayerPrefetch(); /** * Implement to start the Player. * <p> * This method should not be called directly. Instead, call * start(). * * @return True if successful, false otherwise. */ public abstract boolean doPlayerSyncStart(Time t); /** * Implement to deallocate the Player. * <p> * This method should not be called directly. Instead, call * deallocate(). * * @return True if successful, false otherwise. */ public abstract boolean doPlayerDeallocate(); /** * Implement to stop the Player. * <p> * This method should not be called directly. Instead, call * stop(). * * @return True if successful, false otherwise. */ public abstract boolean doPlayerStop(); /** * Close the Player. Typically this method will release as * many resources as possible, especially those that may be * needed by other Players. * <p> * This method should not be called directly. Instead, call * close(). */ public abstract void doPlayerClose(); /** * Override to provide implementation-specific functionality. * When this method is called, it is guaranteed that the * Controller is Stopped and that the given time is within the * Controller's duration. * <p> * This method should not be called directly. Instead, call * setMediaTime(). * * @param t * The media time to set */ public abstract void doPlayerSetMediaTime(Time t); /** * Override to provide implementation-specific functionality. * When this method is called, it is guaranteed that the * Controller is Stopped. * <p> * This method should not be called directly. Instead, call * setRate(). * * @param rate * The requested rate to set * * @return The actual rate that was set */ public abstract float doPlayerSetRate(float rate); /** * Returns the start latency of the media played by <U>this</U> * Player only. It does not consider any of the Controllers * that this Player may be managing. */ public abstract Time getPlayerStartLatency(); /** * Returns the duration of the media played by <U>this</U> Player * only. It does not consider any of the Controllers that * this Player may be managing. */ public abstract Time getPlayerDuration(); //////////////////////////////////////////////////////////// // // javax.media.Duration methods // //////////////////////////////////////////////////////////// /** * Gets the duration of this Player. */ public synchronized final Time getDuration() { if( duration == null ) { updateDuration(); } return duration; } /** * Update the duration of this Player. It is defined to be * the longest duration between this Player and any of the * Controllers that this Player may be managing. If any of * the Controllers returns DURATION_UNKNOWN or * DURATION_UNBOUNDED, then the duration is set to this value. */ private synchronized final void updateDuration() { Time duration = getPlayerDuration(); if( duration != DURATION_UNKNOWN ) { for(int i = 0, n = controllers.size(); i < n; i++) { Controller c = (Controller)controllers.elementAt(i); Time d = c.getDuration(); if( d == DURATION_UNKNOWN ) { duration = d; break; } if( duration != DURATION_UNBOUNDED && ( d == DURATION_UNBOUNDED || d.getNanoseconds() > duration.getNanoseconds() ) ) { duration = d; } } } boolean newDuration = false; if( duration == DURATION_UNKNOWN || duration == DURATION_UNBOUNDED || this.duration == DURATION_UNKNOWN || this.duration == DURATION_UNBOUNDED) { if( this.duration != duration ) { newDuration = true; } } else if( this.duration == null || duration.getNanoseconds() != this.duration.getNanoseconds() ) { newDuration = true; } // If the duration has changed since it was last // calculated, update it and post a DurationUpdateEvent if( newDuration ) { this.duration = duration; postEvent( new DurationUpdateEvent(this,duration) ); } } //////////////////////////////////////////////////////////// // // javax.media.Clock methods // //////////////////////////////////////////////////////////// /** * Sets the media time. If the Player is in the Started * state, it is stopped before setting the media time and * restarted afterwards. * * @param t * The media time to set * * @exception NotRealizedError * If the Controller is not Realized. */ public synchronized void setMediaTime(Time t) { boolean isStarted = (getState() == Started); if(isStarted) { stopInRestart(); } super.setMediaTime(t); if(isStarted) { start(); } } /** * Sets the rate. If the Player is in the Started state, it * is stopped before setting the rate and restarted * afterwards. * * @param rate * The temporal scale factor (rate) to set. * * @exception NotRealizedError * If the Controller is not Realized. */ public synchronized float setRate(float rate) { boolean isStarted = (getState() == Started); if(isStarted) { stopInRestart(); } float newRate = super.setRate(rate); if(isStarted) { start(); } return newRate; } //////////////////////////////////////////////////////////// // // javax.media.Controller methods // //////////////////////////////////////////////////////////// /** * Gets the start latency of this Player. It is defined to * be the longest start latency between this Player and any * of the Controllers that this Player may be managing. If * any of the Controllers returns LATENCY_UNKNOWN, it's value * is skipped in the calculation of the maximum latency. * * @return The maximum start latency of this Player and * all its managed Controllers, or * LATENCY_UNKNOWN if the Player and its managed * Controllers all return LATENCY_UNKNOWN. */ public synchronized Time getStartLatency() { int currentState = getState(); if(currentState == Unrealized || currentState == Realizing) { throw new NotRealizedError( "Cannot get start latency from an Unrealized Controller"); } Time latency = getPlayerStartLatency(); for(int i = 0, n = controllers.size(); i < n; i++) { Controller c = (Controller)controllers.elementAt(i); Time l = c.getStartLatency(); if( l == LATENCY_UNKNOWN ) { continue; } if( latency == LATENCY_UNKNOWN || l.getNanoseconds() > latency.getNanoseconds() ) { latency = l; } } return latency; } //////////////////////////////////////////////////////////// // // javax.media.Player methods // //////////////////////////////////////////////////////////// /** * Start the player on a new thread. If necessary, the * Player will be prefetched before being started. * Subclasses should override doSyncStart() to do the actual work * to transition the Controller. * <p> * Checks for Player state prerequisites and creates a * StartThread to start the AbstractPlayer. If there * is already a thread transitioning the AbstractPlayer * forward, then the target state of the AbstractPlayer is * set to Started and the method returns. * <p> * Asynchronous method -- Start synchronous transition on * another thread and return ASAP. */ public final void start() { int state = getState(); int target = getTargetState(); // Has this state already been reached? if( state == Started ) { postStartEvent(); return; } // Set the target state if( target < Started ) { setTargetState(Started); } // Start on a separate thread Thread thread = new Thread() { public void run() { if( AbstractPlayer.this.getState() < Started ) { synchronousStart(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -