//
/**
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;
}
//