| # Using the mediaDisplay Component in Flash MX Professional 2004 This document contains the following sections: Description Source Files Using the video application How the application was created # Description This sample demonstrates some of the more advanced video features available in Flash MX 2004. The application takes you through a computer-generated world in FLV video and lets the user set video bookmarks and demonstrates advanced video techniques featuring non-linear video, executing functions from video cue points, and using ActionScript to pause, rewind, fast forward and reposition video. This example also demonstrates how to use and control multiple MediaDisplay components, video synchronization, and skinning components. If you plan on including video in your Flash applications, this sample highlights the capability of Flash video. The sample demonstrates how to accomplish the following: Control a mediaDisplay Component with ActionScript Sync up a movieClip's current frame to a mediaDisplay Component's playhead time Play, pause, stop, play backward, and play fast-forward a FLV Pause and resume play from the same playhead time Call a function from a cuePoint Get the duration and total bytes of a FLV Tell if a FLV has reached its end # Source Files The source file for this movie (videoRIA.fla) can be found in the Samples folder on your hard drive. On Windows, go to boot drive\Program Files\Macromedia\Flash MX 2004\Samples\AdvancedVideo. On Macintosh, go to Macintosh HD/Applications/Macromedia Flash MX 2004/Samples/AdvancedVideo. # Using the video application ## Playing the video: Click the Play button to advance the video. The playhead shows the current time in the video. Click the Pause button to stop the video. Click the End button to jump to the end of the video. Click the Start button to jump to the beginning of the video. ## Adding/Deleting a cue point: Click the Mark button. A series of controls appear on the right-side of the window. Each empty thumbnail represents a blank cue point. Click the (+) button to add a cue point, or the (-) button to delete the most recently added cue point. A thumbnail representation of the saved cue point appears in an empty cell. Click the thumbnail to jump to a cue point The playhead advances to time stored by the cue point. ## Playing the Time Lapse video: The Time Lapse video shows lets you move watch the changes to the environment at different time of the day. The video plays in its own window that displays the time of day. Click the Clock button to display the Time Lapse video controls. Click the clock icon to stop the main video and advance the Time Laspse video. Click the clock again to start the main video. ## Displaying the Map: The map shows your progress through the environment as the video plays. Click the Map button. # How the application was created This section contains the following topics: Application overview Saving and navigating to video bookmarks Executing methods from video cue points Synchronizing the 2D map Spinning the clock About keyframes ## Application overview The center of this sample application is a MediaDisplay component named md . The md component loads a Flash Video (FLV) file called main.flv. As the user plays the video, other parts of the application synchronize with and react to the video. The user can interact with the application using various UI components to create bookmarks and navigate to them. A movie clip named mapShell represents the current video location by sliding a two-dimensional map on a guide and under a mask, in synchronization with the main video. A second MediaDisplay component named timeLapse manages a video named clock2.flv. When directed to play by the user, the main video pauses. When this video is directed by the user to stop playing, the main video continues from its paused location. A movie clip named lensFlare waits for ActionScript commands that are generated from video cuepoints in the main video. ## Saving and navigating to video bookmarks Bookmarks in this application are managed and displayed in the movie clip named mark on the lower right side of the Stage just below the component md . When the application starts, mark is made invisible using ActionScript on the _root timeline. To show the mark movie clip, the user must press the Mark button on the left side, under the component md . Inside the movie clip mark, four bookmarks are displayed using MediaDisplay components. The four bookmark components load the mark0.flv through mark3.flv FLV files, respectively. These Flash videos are replicas of the main.flv file. The application uses them to visually show the user the scene at the bookmark the user has created. Layer 2 of the mark movie clip contains the ActionScript needed to manage the bookmarks. The method `plusMethod()` is executed when the user creates a bookmark by clicking the plus sign to the right of the bookmark components:
    function plusMethod(){
      barray.unshift(_parent.videoPosition());
      setBookmarkTime();
    }
The barray array saves the video positions for each bookmark. The `unshift()` method inserts an entry into the 0 position of`barray`, moving each of the existing entries down 1. The contents of the new `barray[0]` are set using the results of a method on the _root timeline called `videoPosition()`. This function simply returns the `playheadTime` property of the md MediaDisplay component, currently playing the main.flv video:
    function videoPosition() {
      return this.md.playheadTime;
    }
The `setBookmarkTime()` method is then called to set the bookmark videos to their saved positions:
    function setBookmarkTime() {
      for (i in barray) {>
        if (i < 4) {
          bookmarkList["b"+i].bm._visible = true;
          bookmarkList["b"+i].bm.play(barray[i]);
          bookmarkList["b"+i].bm.pause();
          bookmarkList["b"+i].bm.onPress = bookmarkPressed;
        }
      }
    }
In the `setBookmarkTime()` method , for each entry in the `barray` array, the bookmark video is played at the saved bookmark time, and then paused. The `onPress` event of the bookmark is then set to execute the `bookmarkPressed()` method.The `onPress` event is generated when the user clicks the bookmark, executing `bookmarkPressed()`:
    function bookmarkPressed() {
      _parent.seekToVideoAt(this.playheadTime);
    }
This method simply calls a _root timeline() method named `seekToVideoAt()`, which receives the playhead time of the paused bookmark video:
    function seekToVideoAt(theTime) {
      this.videoSeekTime = theTime;
    }
The root variable `videoSeekTime` is set to the desired video position. This variable is sampled each time the _root `onEnterFrame()` method is executed. As long as the value of `videoSeekTime` is not equal to –1, the `onEnterFrame()` method immediately begins moving the md playhead toward the requested time (forward or reverse.) You can control the speed at which the video moves by setting the speed variable:
    this.onEnterFrame = function() {
      // fast-forward or rewind to the videoSeekTime
      if (this.videoSeekTime != -1) {
        if (Math.abs(this.md.playheadTime-videoSeekTime)<1) {
          this.videoSeekTime = -1; // done
        } else {
          var speed = .7; /* not a magic number, you can choose the speed you like */
          var newTime = this.md.playheadTime;
          if (this.videoSeekTime > this.md.playheadTime) {
            newTime += speed; //fast-forward
          } else {
            newTime -= speed; // rewind
          }
          this.playVideoAt(newTime);
        }
      }
    }
When the `onEnterFrame()` method detects the FLV video is in the desired position, the videoSeekTime variable is set back to –1 and the video continues from its new location. This effectively creates a fast forward or rewind capability for your MediaDisplay component. When the user removes a bookmark by clicking on the minus sign to the right of the bookmark components, the application calls the `minusMethod()` method:
    function minusMethod(){
      if (barray.length > 0) {
        barray.shift();
      }
      setBookmarkTime();
      if (barray.length < 4) {
        for (var i:Number = barray.length; i < 4; i++) {
          bookmarkList["b"+i].bm._visible = false;
        }
      }
    }
The `minusMethod()` method removes the last bookmark created by executing the `shift()` method on `barray`. This method slices position 0 out of the array and repositions the remaining bookmarks. The `setBookmarkTime()` method is then called to set the bookmark videos to the remaining positions. Finally, the unused bookmark videos are set as invisible. Using the `shift()` and `unshift()` methods to control the position of the bookmark FLV videos leads to an interesting effect. The bookmark FLV files that represent `barray[0]` through `barray[3]` are arranged on the Stage from right to left. As the bookmarks are created and shifted into the array, the result is that the scenes appear from the right and appear to “shift” to the left as new bookmarks are created. Similarly, as the user deletes bookmarks, they shift to the right and the last bookmark created is the first one deleted. ## Executing methods from video cue points You can see the properties of the `md` MediaDisplay component in the component Property inspector. At the bottom of the tab, you can add video cue points to your component. Each time the FLV video being played reaches a cue point, the `cuePoint` event is generated so the applicationcan take action. The md component FLV video has five cue points set. To make the application react to the cue point events, you must create an object that acts as a listener for that event. A listener object contains methods that are executed by Flash when specific events are generated:
    listenerObject = new Object();
    listenerObject.lensFlareMC = this.lensFlare;
    listenerObject.cuePoint = function(eventObject){
      if (eventObject.cuePointName == "lensON") {
        this.lensFlareMC._visible = true;
        this.lensFlareMC.gotoAndPlay(lensFlare._currentframe+1);
      } else if (eventObject.cuePointName == "endFlare") {
        this.lensFlareMC._visible = false;
      } else if (eventObject.cuePointName == "startFlare") {
        this.lensFlareMC._visible = true;
        this.lensFlareMC.gotoAndPlay(2);
      } else if (eventObject.cuePointName == "lensOFF") {
        this.lensFlareMC._visible = false;
        this.lensFlareMC.gotoAndStop(1);
      } else if (eventObject.cuePointName == "init") {
        this.lensFlareMC._visible = false;
        this.lensFlareMC.gotoAndStop(1);
      }
    }
Now you need to tell the `md` Component about the new listener you have created and the name of the event for which you would like your listener to be notified:
    md.addEventListener("cuePoint", listenerObject)
The `cuePoint()` method of the listenerObject object tests the name of the cue point to see which one is being broadcast. Based on the name of the cue point, the listener method directs the lensFlare movie clip to a different position. You can see how this works when the main FLV video is played. As you approach the first cave entrance, you will see transparent colored dots appear and shift with the video movement. They give the appearance they are part of the main.flv video, but they are actually a movie clip synchronized with the playing FLV video. Using this same process, your cue points could also execute other methods that may communicate to a server, change displayed data, or any other action you want to include in your video. ## Synchronizing the 2D map Above the Stage, you can see the movie clip mapShell. This clip slides a large map, representing a 2D view of the area in the main.flv video, under a mask. The `mapShell.onEnterFrame()` method calls the method `updateMapPosition()`, which synchronizes mapShell with the main.flv video. This process gives the appearance that the map is displaying your current position as the video takes you through the imaginary 3D world. The large map movie clip, called `layout`, has the large map inside, riding on a guide layer that moves the map in realistic directions that correspond to the main FLV video position. There is no ActionScript in the mapShell movie clip. The entire map is controlled from the root Timeline. The `mapShell.onEnterFrame()` method contains the following ActionScript:
    mapShell.onEnterFrame = function() {
      // map synchronization
      updateMapPosition();
    }
This ActionScript code tells mapShell to continuously execute the `updateMapPosition()` method:
    function updateMapPosition() {
      if (this.md.playing) {
        var mapFrameCount:Number = this.mapShell.layout._totalframes;
        this.mapShell.layout.gotoAndStop(Math.round(videoProgress() * mapFrameCount));
      } else {
        return
      }
    }
The `updateMapPosition()` method takes the main.flv video's progress from the md component (a value returned from `videoProgress()` as a percentage from 0 to 1) and multiplies that by the total number of frames in the map movie clip. It then directs the layout movie clip to the calculated frame number using the `gotoAndStop()` command. When the user presses the Map button, the map is displayed and then constantly updates its own position based on the position of the main.flv video. Even when bookmarks are pressed, as the video moves to the bookmark, the map position moves accordingly. ## Spinning the clock When the user plays the main FLV video and presses the Clock button, the clock parts and the timeLapse movie clip becomes visible over the left side of the main video. The user can then click anywhere on the clock to start the clock spinning. When the clock spins and the timeLapse video is playing, the main video is paused. When the user clicks the clock again, the clock and timeLapse video pause and the main video starts playing from its paused position. All of the ActionScript code that controls the clock is in the root Timeline. When the application starts, the clock and timeLapse video are set to move in a forward direction. When the clock reaches 12 hours (the unaccelerated length of the timeLapse video), the clock and timeLapse video reverse and play backwards until the video goes back to the beginning, where it reverses again and plays forward. The digital clock readout at the bottom of the timeLapse video is not taken directly from the video playhead position. It is actually calculated from the positions of the hour and minute hand on the analog clock. Flash positions the hands on the clock by calculating a rotation value based on the timeLapse video position. This involves a bit of trigonometry (sin and cos functions) but is fairly straightforward. ## About keyframes One important concept that is important to the functionality of this sample but not immediately apparent is the keyframe. The number of keyframes per second is one of the user options when exporting to FLV video. A keyframe is a frame where all of the information about a video frame is stored in the video file. The information stored about non-keyframes, the ones between keyframes, consists of elements of change since the last keyframe. The farther the play head gets from a keyframe, the lower the video quality becomes. The obvious question is, “Why not use a keyframe every frame?” The reason is your video will be very large and will take more CPU time to play. Storing all elements of every frame is expensive in system resources. The developer must weigh the size and performance of the video with the needs of the application. Another issue affecting the keyframes-per-second setting is how the video will be used with ActionScript. If ActionScript will be directing the video to a specific time, the developer must realize that the video will actually be directed to the keyframe nearest that time. The fewer keyframes per second, the less accurate this type of direction becomes. Using Flash MX and the strategies outlined in this sample application, you can take video presentation to its highest level.