📄 abstractclock.java
字号:
package net.sf.fmj.ejmf.toolkit.media;import javax.media.Clock;import javax.media.ClockStartedError;import javax.media.ClockStoppedException;import javax.media.IncompatibleTimeBaseException;import javax.media.Manager;import javax.media.StopTimeSetError;import javax.media.Time;import javax.media.TimeBase;/** * The AbstractClock provides an abstract implementation of the * javax.media.Clock interface. All methods are implemented * except for setStopTime() and getStopTime(). These methods will * invariably require implementation-specific functionality and * therefore are left to the subclasses to implement. * * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046). Used with permission. * * @see AbstractController * @see StopTimeMonitor * * @author Steve Talley & Rob Gordon */public class AbstractClock implements Clock{ private TimeBase systemtimebase = Manager.getSystemTimeBase(); private TimeBase timebase = systemtimebase; private Time mediaStartTime = new Time(0); private Time mediaStopTime = Clock.RESET; private Time timeBaseStartTime; private float rate = 1.0F; private boolean isStarted = false; /** * Constructs an AbstractClock. */ public AbstractClock() { super(); } //////////////////////////////////////////////////////// // // 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(isStarted) { throw new ClockStartedError( "Cannot set time base on a Started Clock"); } if( timebase == null ) { this.timebase = systemtimebase; } else { this.timebase = timebase; } } /** * Get the TimeBase that this Clock is using. */ public synchronized TimeBase getTimeBase() { return timebase; } /** * Sets the media time. * * @param t * The media time to set * * @exception ClockStartedError * If the Clock is Started. */ public synchronized void setMediaTime(Time t) { if(isStarted) { throw new ClockStartedError( "Cannot set media time on a Started Clock"); } mediaStartTime = t; } /** * Get the media time the media is scheduled to start (if the * Clock is stopped), or the media time at which the Clock * started (if the Clock is started). */ protected Time getMediaStartTime() { return mediaStartTime; } /** * Get the time-base time the media is scheduled to start (if * the Clock is stopped), or the time-base time at which the * Clock started (if the Clock is started). */ protected Time getTimeBaseStartTime() { return timeBaseStartTime; } /** * 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() { if( ! isStarted ) { // If the Clock is stopped return it's starting // media-time return mediaStartTime; } else { // Calculate the media time return calculateMediaTime(); } } /** * Get the media time in nanoseconds. */ public synchronized long getMediaNanoseconds() { return getMediaTime().getNanoseconds(); } /** * Calculates the media time on a started Clock based on the assumption that the Clock is started. */ private synchronized Time calculateMediaTime() { long tbCurrent = timebase.getNanoseconds(); long tbStart = timeBaseStartTime.getNanoseconds(); // If we are scheduled to start but haven't yet reached // the scheduled start time, return the media start time if(tbCurrent < tbStart) { return mediaStartTime; } long mStart = mediaStartTime.getNanoseconds(); long mCurrent = (long)((tbCurrent - tbStart)*rate + mStart); return new Time(mCurrent); } /** * Gets the time until the Clock's media synchronizes with its * time-base. * * @return The time remaining until the time-base * start-time if this Clock is Started and the * time-base start-time has not yet been reached, * or the media time otherwise. */ public synchronized Time getSyncTime() { if(isStarted) { long startNano = timeBaseStartTime.getNanoseconds(); long nowNano = getTimeBase().getNanoseconds(); if( startNano >= nowNano ) { return new Time((long)(nowNano - startNano)); } } return getMediaTime(); } /** * Given a media time, returns the corresponding time-base * time. Uses the current rate, the time-base start time, and * the media start time to calculate. * * @param t * A media time to be mapped to a time-base time. * * @return A time-base time. * * @exception ClockStoppedException * If the clock has not started. */ public synchronized Time mapToTimeBase(Time t) throws ClockStoppedException { if( ! isStarted ) { throw new ClockStoppedException( "Cannot map media time to time-base time on a Stopped Clock"); } long mCurrent = t.getNanoseconds(); long mStart = mediaStartTime.getNanoseconds(); long tbStart = timeBaseStartTime.getNanoseconds(); return new Time((long) (((mCurrent - mStart)/rate) + tbStart)); } /** * 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 ClockStartedError * If the Clock is Started. * * @return The actual rate set. * */ public synchronized float setRate(float rate) { if(isStarted) { throw new ClockStartedError( "Cannot set rate on a Started Clock"); } if( rate != 0.0F ) { this.rate = rate; } return this.rate; } /** * Get the current temporal scale factor. The scale factor * defines the relationship between the * <code>Clock's</code> <i>media time</i> and its * <code>TimeBase</code>. * <p> * For example, a rate of 2.0 indicates that <i>media time</i> * will pass twice as fast as the <code>TimeBase</code> time * once the <code>Clock</code> starts. Similarly, a negative * rate indicates that the <code>Clock</code> runs in the * opposite direction of its <code>TimeBase</code>. All * <code>Clocks</code> are guaranteed to support a rate of * 1.0, the default rate. <code>Clocks</code> are not * required to support any other rate.<p> */ public synchronized float getRate() { return rate; } /** * Set the <i>media time</i> at which you want the * <code>Clock</code> to stop. The <code>Clock</code> will * stop when its <i>media time</i> passes the stop-time. To * clear the stop time, set it to: <code>Clock.RESET</code>. * <p> * You can always call <code>setStopTime</code> on a * <i>Stopped</i> <code>Clock</code>. * <p> * On a <i>Started</i> <code>Clock</code>, the stop-time can * only be set <I>once</I>. A <code>StopTimeSetError</code> is * thrown if <code>setStopTime</code> is called and the * <i>media stop-time</i> has already been set. * * @param mediaStopTime * The time at which you want the * <code>Clock</code> to stop, in <i>media * time</i>. */ public synchronized void setStopTime(Time mediaStopTime) { if( isStarted && this.mediaStopTime != RESET ) { throw new StopTimeSetError( "Stop time may be set only once on a Started Clock"); } this.mediaStopTime = mediaStopTime; } /** * Get the last value successfully set by setStopTime. * Returns the constant Clock.RESET if no stop time is set * * @return The current stop time. */ public synchronized Time getStopTime() { return mediaStopTime; } /** * syncStart the AbstractClock at the previously- * specified time-base start time. * <p> * Synchronous method -- return when transition complete */ public synchronized void syncStart(Time t) { // Enforce state prereqs if(isStarted) { throw new ClockStartedError( "syncStart() cannot be called on a started Clock"); } long now = getTimeBase().getNanoseconds(); long start = t.getNanoseconds(); if( start - now > 0 ) { // Start time is in the future // Set the time-base start time this.timeBaseStartTime = new Time(start); } else { // Start time is in the past // Set the time-base start time to be now this.timeBaseStartTime = new Time(now); } isStarted = true; } /** * Stop the Clock. */ public synchronized void stop() { if(isStarted) { mediaStartTime = calculateMediaTime(); // KAL: TODO: what is the reason for this?// Commented out -- is this necessary?// timeBaseStartTime = timebase.getTime(); isStarted = false; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -