📄 abstractcontroller.java
字号:
package net.sf.fmj.ejmf.toolkit.media;import java.util.Vector;import javax.media.ClockStartedError;import javax.media.ClockStoppedException;import javax.media.Control;import javax.media.Controller;import javax.media.ControllerClosedEvent;import javax.media.ControllerErrorEvent;import javax.media.ControllerEvent;import javax.media.ControllerListener;import javax.media.DataStarvedEvent;import javax.media.DeallocateEvent;import javax.media.EndOfMediaEvent;import javax.media.IncompatibleTimeBaseException;import javax.media.MediaTimeSetEvent;import javax.media.NotPrefetchedError;import javax.media.NotRealizedError;import javax.media.PrefetchCompleteEvent;import javax.media.RateChangeEvent;import javax.media.RealizeCompleteEvent;import javax.media.RestartingEvent;import javax.media.StartEvent;import javax.media.StopAtTimeEvent;import javax.media.StopByRequestEvent;import javax.media.StopEvent;import javax.media.StopTimeChangeEvent;import javax.media.Time;import javax.media.TimeBase;import javax.media.TransitionEvent;import net.sf.fmj.ejmf.toolkit.controls.RateControl;/** * The AbstractController class provides a basic implementation of a * javax.media.Controller. Subclasses should implement the * following abstract "do" methods to transition their Controller: * <p> * <UL> * <LI>doRealize()</LI> * <LI>doPrefetch()</LI> * <LI>doSyncStart()</LI> * <LI>doDeallocate()</LI> * <LI>doStop()</LI> * </UL> * <p> * Follow these rules when implementing these methods: * <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>doClose()</LI> * <LI>doSetMediaTime()</LI> * <LI>doSetRate()</LI> * </UL> * * <p> * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046). Used with permission. * </p> * @see AbstractPlayer * * @author Steve Talley */public abstract class AbstractController extends AbstractClock implements Controller{ private int previousState; private int currentState = Unrealized; private int targetState; private StopTimeMonitor stopTimeMonitor; private ControllerEventQueue eventqueue; private ThreadQueue threadqueue; private Vector controls = new Vector(); private Vector listeners = new Vector(); /** * Construct a AbstractController. */ public AbstractController() { super(); eventqueue = new ControllerEventQueue(listeners, "ControllerEventQueue for " + this); stopTimeMonitor = new StopTimeMonitor(this, "StopTimeMonitor for " + this); threadqueue = new ThreadQueue("ThreadQueue for " + this); // TODO: do not start in constructor, and stop somewhere // constructor sometimes gets called for a controller that will never be used, and these threads just hang around. eventqueue.start(); stopTimeMonitor.start(); threadqueue.start(); addControl( new RateControl(this) ); } //////////////////////////////////////////////////////////// // // Abstract methods // //////////////////////////////////////////////////////////// /** * Implement to realize the Controller. * <p> * This method should not be called directly. Instead, call * realize(). * * @return True if successful, false otherwise. */ public abstract boolean doRealize(); /** * Implement to prefetch the Controller. * <p> * This method should not be called directly. Instead, call * prefetch(). * * @return True if successful, false otherwise. */ public abstract boolean doPrefetch(); /** * Implement to start the Controller. * <p> * This method should not be called directly. Instead, call * syncStart(). * * @return True if successful, false otherwise. */ public abstract boolean doSyncStart(Time t); /** * Implement to deallocate the Controller. * <p> * This method should not be called directly. Instead, call * prefetch(). * * @return True if successful, false otherwise. */ public abstract boolean doDeallocate(); /** * Implement to stop the Controller. * <p> * This method should not be called directly. Instead, call * stop(). * * @return True if successful, false otherwise. */ public abstract boolean doStop(); /** * Close the Controller. Typically this method will release as * many resources as possible, especially those that may be * needed by other Controllers. * <p> * This method should not be called directly. Instead, call * close(). */ public abstract void doClose(); /** * 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 doSetMediaTime(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 doSetRate(float rate); //////////////////////////////////////////////////////// // // javax.media.Clock methods // //////////////////////////////////////////////////////// /** * Set the <code>TimeBase</code> for this <code>Clock</code>. * This method can only be called on a <i>Stopped</i> * <code>Clock</code>. A <code>ClockStartedError</code> is * thrown if <code>setTimeBase</code> is called on a * <i>Started</i> <code>Clock</code>. * <p> * A <code>Clock</code> has a default <code>TimeBase</code> that * is determined by the implementation. To reset a * <code>Clock</code> to its default <code>TimeBase</code>, * call <code>setTimeBase(null)</code>. * * @param timebase * The new <CODE>TimeBase</CODE> or * <CODE>null</CODE> to reset the * <code>Clock</code> to its default * <code>TimeBase</code>. * * @exception IncompatibleTimeBaseException * Thrown if the <code>Clock</code> can't use the * specified <code>TimeBase</code>. */ public synchronized void setTimeBase(TimeBase timebase) throws IncompatibleTimeBaseException { if(currentState == Unrealized || currentState == Realizing) { throw new NotRealizedError( "Cannot set TimeBase on an Unrealized Controller."); } super.setTimeBase(timebase); } /** * Get the TimeBase that this Controller is using. */ public synchronized TimeBase getTimeBase() { if(currentState == Unrealized || currentState == Realizing) { throw new NotRealizedError( "Cannot get time base from an Unrealized Controller"); } return super.getTimeBase(); } /** * Sets the stop time for this AbstractController. Posts a * StopTimeChangeEvent if the stop time given is different * than the current stop time. * * @param mediaStopTime * The time at which you want the * <code>Clock</code> to stop, in <i>media * time</i>. * * @exception NotRealizedError * If the Controller is not Realized. * * @exception ClockStartedError * If the Controller is Started. */ public synchronized void setStopTime(Time mediaStopTime) { if(currentState == Unrealized || currentState == Realizing) { throw new NotRealizedError( "Cannot set stop time on an unrealized Controller"); } Time oldStopTime = getStopTime(); // If the stop time has changed, post an event if( mediaStopTime.getNanoseconds() != oldStopTime.getNanoseconds() ) { // Set in superclass super.setStopTime(mediaStopTime); // Post event postEvent( new StopTimeChangeEvent(this, mediaStopTime) ); } } /** * Sets the media time. * * @param t * The media time to set * * @exception NotRealizedError * If the Controller is not Realized. * * @exception ClockStartedError * If the Controller is Started. */ public synchronized void setMediaTime(Time t) { if(currentState == Unrealized || currentState == Realizing) { throw new NotRealizedError( "Cannot set media time on an Unrealized Controller"); } long nano = t.getNanoseconds(); Time duration = getDuration(); // Enforce upper bound on start time if( duration != DURATION_UNKNOWN && duration != DURATION_UNBOUNDED ) { long limit = duration.getNanoseconds(); if( nano > limit ) { t = new Time(limit); } } // Set the media time super.setMediaTime(t); // Call implementation-specific functionality doSetMediaTime(t); // Post MediaTimeSetEvent postEvent( new MediaTimeSetEvent(this, t) ); } /** * Calculates the current media time based on the current * time-base time, the time-base start time, the media start * time, and the rate. * * @return The current media time */ public synchronized Time getMediaTime() { Time mediaTime = super.getMediaTime(); Time duration = getDuration(); // Compare media time with duration if( duration != DURATION_UNKNOWN && duration != DURATION_UNBOUNDED && mediaTime.getNanoseconds() > duration.getNanoseconds() ) { return duration; } return mediaTime; } /** * Set the temporal scale factor. The argument * <i>suggests</i> the scale factor to use. * <p> * The <code>setRate</code> method returns the actual rate set * by the <code>Clock</code>. <code>Clocks</code> should set * their rate as close to the requested value as possible, but * are not required to set the rate to the exact value of any * argument other than 1.0. A <code>Clock</code> is only * guaranteed to set its rate exactly to 1.0. * * @param rate * The temporal scale factor (rate) to set. * * @exception NotRealizedError * If the Controller is not Realized. * * @exception ClockStartedError * If the Controller is Started. * * @return The actual rate set. * */ public synchronized float setRate(float rate) { if( currentState == Unrealized || currentState == Realizing ) { throw new NotRealizedError( "Cannot set rate on an Unrealized Controller."); } // Save the current rate float oldRate = getRate(); // Enforce superclass reqs float superRate = super.setRate(rate); // Set the rate in the subclass float subRate = doSetRate(superRate); // If the rate has changed since setting in the // superclass, set it agagin if( rate != 1.0F && superRate != subRate ) { superRate = super.setRate(subRate); // If it has changed again, give up and set to the // only rate guaranteed to be accepted if( superRate != subRate ) { return setRate(1.0F); } } // If the rate has changed, commit it and post an event. if(superRate != oldRate) { postEvent( new RateChangeEvent(this, superRate) ); } return superRate; } //////////////////////////////////////////////////////////// // // javax.media.Duration methods //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -