// /** This applet uses AWT UI controls to control the rate of a video playback.
**/ //
import com.ms.dxmedia.*; import java.awt.*; import java.applet.*; import java.net.URL; // // There are two components in this applet. One is a DXMCanvas used to display // the movie image, the other is a panel of AWT controls used to control the // playback. public class VCR extends Applet { public void init() { setLayout(new BorderLayout()); DxmMovie cv = new DxmMovie(); Panel ctrls = new Controls(cv._model); add("Center", cv); add("South", ctrls); } } // // // This class extends the DXMCanvas class. The model you set in this class, // by calling the setModel() method, is the model that will be displayed. class DxmMovie extends DXMCanvas { DxmMovie() { _model = new VCRModel(); setModel(_model); } VCRModel _model; } // This class extends the Model class. The createModel method in this class // is where you construct your model. class VCRModel extends Model { // Import a movie in the model and have a switcher behavior to control // the playback rate. public void createModel(BvrsToRun bvrs) { // Create a movie behavior by importing an avi file. URL movieBase = buildURL(getImportBase(), "Movie/"); ImageBvr[] imgArr = {null}; SoundBvr[] sndArr = {null}; NumberBvr lenNum = importMovie(buildURL(movieBase, "movie.avi"), imgArr, sndArr); // The playback rate switcher starts with 1, the normal rate. _rateSw = new ModifiableBehavior(toBvr(1)); // The playback position of the movie is the sum of the rate. Use // modulus to loop the movie since positions less than 0 or greater than // the length of the movie yields emptyImage. The specialMod is a // private function that always returns a positive number less than // lenNum. NumberBvr posNum = specialMod(integral((NumberBvr)_rateSw.getBvr()), lenNum); // Use AppTriggeredEvent for the restart event. When the restart button // is pressed, the event will be triggered. Construct a recursive // position behavior - the resetablePosNum - that resets to itself when // the event occurs. Note that integral has implicit time. When a // restart posNum at the time _resetEv occurs, integration starts from // 0. _resetEv = new AppTriggeredEvent(); NumberBvr resetablePosNum = NumberBvr.newUninitBvr(); resetablePosNum.init(until(posNum, _resetEv, resetablePosNum)); // Play the movie on top of a black background. Use substituteTime // to control the position of a movie. The localTime for movies // is implicit. setImage(overlay((ImageBvr)imgArr[0].substituteTime(resetablePosNum), solidColorImage(black))); // Loop the sound here. setSound((SoundBvr)sndArr[0].loop().substituteTime(resetablePosNum)); } // This function does a "special" mod for negative numbers. It returns // the linear distance between the passed-in numerator and the biggest // multiple of the denominator smaller than the numerator. // For example, specialMode(-1, 5) = 4, specialMod(-4, 5) = 1. // This is defined so that a decreasing number behavior passed in as the // numerator yields a consistent result whether its value is positive or // negative. NumberBvr specialMod(NumberBvr numNum, NumberBvr denomNum) { return (NumberBvr)cond(gt(numNum, toBvr(0)), mod(numNum, denomNum), sub(denomNum, mod(abs(numNum), denomNum))); } // This method changes the value of the rate switcher to the given rate. // This is called by the event handlers of the playback controls. void setRate(int rate) { _rateSw.switchTo(toBvr(rate*0.1)); } // This method is called when the restart button is pressed. It resets // the rate to the normal playback rate, and triggers the event to // restart the movie. void restart() { setRate(10); _resetEv.trigger(); } AppTriggeredEvent _resetEv; ModifiableBehavior _rateSw; } // // // This class extends Panel. It has four buttons - pause, restart, fast forward, // rewind - and a scrollbar. The scrollbar is used to control the playback rate // at a finer level. class Controls extends Panel { // Place the scrollbar at the center, then two buttons on either side. Controls(VCRModel movie) { _movie = movie; setLayout(new BorderLayout()); _rateBar = new Scrollbar(Scrollbar.HORIZONTAL, 10, 1, -40, 40); add("Center", _rateBar); // Pause and restart buttons on the west side. Panel pWest = new Panel(); pWest.setLayout(new GridLayout(1, 2)); pWest.add(new Button("| |")); pWest.add(new Button(">")); add("West", pWest); // Fast forward and rewind buttons on the east side. Panel pEast = new Panel(); pEast.setLayout(new GridLayout(1, 2)); pEast.add(new Button(">>")); pEast.add(new Button("<<")); add("East", pEast); } // The event handler when any buttons are pressed. public boolean handleEvent(Event ev) { switch (ev.id) { case Event.SCROLL_LINE_UP: case Event.SCROLL_LINE_DOWN: case Event.SCROLL_PAGE_UP: case Event.SCROLL_PAGE_DOWN: case Event.SCROLL_ABSOLUTE: // Scroll position changed: Clear the pause state, set the rate to // the current scroll position. _bPaused = false; _movie.setRate(_rateBar.getValue()); return true; case Event.ACTION_EVENT: if (ev.arg == "| |") { // Pause: Toggle the pause state. This means that pressing the pause // button the second time resumes the normal playback rate. // The normal playback rate is 10, the pause rate is 0. // Need to reflect the current rate in the scrollbar. int rate; if (_bPaused) { _bPaused = false; rate = 10; } else { _bPaused = true; rate = 0; } _movie.setRate(rate); _rateBar.setValue(rate); return true; } else if (ev.arg == ">") { // Restart: Clear the pause state, restart the movie at normal rate. _bPaused = false; _movie.restart(); _rateBar.setValue(10); return true; } else if (ev.arg == ">>") {// Fast forward // FastForward: Clear the pause state, set rate to 30 and update the // scrollbar position. _bPaused = false; _movie.setRate(30); _rateBar.setValue(30); return true; } else if (ev.arg == "<<") { // Rewind: Clear the pause state, set rate to -30 and update the // scrollbar position. _bPaused = false; _movie.setRate(-30); _rateBar.setValue(-30); return true; } } return false; } boolean _bPaused = false; Scrollbar _rateBar; VCRModel _movie; } //