Chapter 12
Embedded Video and Music

Key Skills & Concepts

• Adding video to an app

• Inverse binding

• Using the MediaPlayer

With the abundance of business and sites built around streaming media, it is only natural that JavaFX allow you to take full advantage of video and audio media. In the past, programming an application to play any kind of media meant hours of writing controls, finding the right codecs for the files you wanted to play, and writing parsers to read the media files. It was long and arduous work that you would really only attempt if you were completely confident in your abilities as a programmer.

JavaFX has packaged a few nodes that make working with media files as easy as possible. In this chapter you learn about the MediaView and MediaPlayer nodes. You use these nodes to write apps that display video, play audio, and allow users a level of control over the media they choose to play.

In the first section, you learn how MediaView and MediaPlayer can be used together to play a video file. However, before you begin, you need to create a new, empty JavaFX script. Your script should appear as follows:

/*
 * Chapter12.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */
package com.jfdimarzio.javafxforbeginners;

/**
 * @author JFDiMarzio
 */

You also need to create a second empty JavaFX script. This second file will hold a custom node for the playback of media files. You will be adding to this second file throughout the chapter. Name the file MyMediaPlayer.fx, and set it up as follows:

/*
 * MyMediaPlayer.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */

package com.jfdimarzio.javafxforbeginners;


/**
 * @author JFDiMarzio
 */

In the following sections you learn how easy it is to add video files and audio files to your applications.

Playing Video

JavaFX uses the MediaView node to display video to the screen. However, the MediaView is really just a container for a MediaPlayer. The MediaPlayer node is the one that plays the video.

In this section you use a MediaView and a MediaPlayer to play some sample video from within your application. You will be surprised at just how easy JavaFX makes it to play video from a script.

TIP

The sample video used in this section can be downloaded from http://www.microsoft.com/windows/windowsmedia/musicandvideo/hdvideo/contentshowcase.aspx.

Let’s start by creating a MediaPlayer. After the MediaPlayer is created, you will add it to a MediaView in your Chapter12 script.

To begin, open your MyMediaPlayer.fx script. The nodes needed to work with media files are located in the import javafx.scene.media package. JavaFX does a really good job of naming everything logically and placing all related classes in common packages. The javafx.scene.media package is no exception.

Import the following package to your MyMediaPlayer file:

import javafx.scene.media.MediaPlayer;

Now, establish a new MyMediaPlayer class that extends MediaPlayer:

public class MyMediaPlayer extends MediaPlayer  {

}

So why go through the extra step of creating a custom node for the MediaPlayer? Although it is true that you could just add the MediaPlayer directly to a MediaView and be done with it, the stock MediaPlayer is very simplistic. As you progress through this chapter you will be adding functionality to MyMediaPlayer that extends the usability of MediaPlayer.

For now you override two properties of the MediaPlayer, just to show how easy it is to load and play a video file. The autoPlay property tells the MediaPlayer to start playing the file immediately, as soon as it is loaded. Let’s override the autoPlay property to be true:

public class MyMediaPlayer extends MediaPlayer  {
    override var autoPlay = true;
}

The second override we want to make is to the media property. The media property is a Media node and represents the actual media file to be played using the MediaPlayer. For this example you are going to override the media property to hard-code a sample video file. This saves you the effort of constantly having to assign this property.



Import the following statement to establish a Media node:

import javafx.scene.media.Media;

The code to override the media property of the MediaPlayer should look like this:

public class MyMediaPlayer extends MediaPlayer  {
    override var autoPlay = true;
    override var media = Media {
        source: " file:///C:/wmdownloads/Robotica_720.wmv"
    }
}

In this example, the custom MediaPlayer you have created always plays the Robotica_720 .wmv file from the wmdownloads folder of the local drive. The finished MyMediaPlayer script should appear as follows:

/*
 * MyMediaPlayer.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */

package com.jfdimarzio.javafxforbeginners;

import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;

/**
 * @author JFDiMarzio
 */

public class MyMediaPlayer extends MediaPlayer  {
    override var autoPlay = true;
    override var media = Media {
        source: "C:/wmdownloads/Robotica_720.wmv"
    }
}

Now you can use MyMediaPlayer just as you would use the standard MediaPlayer node. Let’s add a MediaView to the Chapter12.fx script and assign MyMediaPlayer to it. Given that you have not yet added any code to the Chapter12.fx script, you need to import the correct package for the MediaView, as follows:

import javafx.scene.media.MediaView;

var myMediaPlayer : MyMediaPlayer = MyMediaPlayer {
}

The only property you need to set right now in your MediaView is mediaPlayer. The mediaPlayer property holds your MediaPlayer node, and as you discovered earlier in this section, the MediaPlayer node plays your media file. Here, you have created a var named myMediaPlayer of your custom MediaPlayer. This var can be assigned to the mediaPlayer property of your MediaView, as shown here:

MediaView {
           mediaPlayer : myMediaPlayer
}

This code is pretty self-explanatory. You are creating a MediaView node to hold your MediaPlayer and send the MediaPlayer to the screen. MyMediaPlayer (the MediaPlayer you created earlier in the section) is assigned to the mediaPlayer property of the MediaView.

The full Chapter12.fx script file should appear as follows:

/*
 * Chapter12.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */

package com.jfdimarzio.javafxforbeginners;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.media.MediaView;

var myMediaPlayer : MyMediaPlayer = MyMediaPlayer {
}

Stage {
      title : "EmbeddedMedia"
      onClose: function () {  }
      scene: Scene {
             width: 1280
             height: 720
             content: [ MediaView {
                                mediaPlayer : myMediaPlayer
                            }
                         ]
                    }
}

Compile and run this example. You will see a sample video begin to play as soon as the application is loaded. The file plays automatically because you overrode the autoPlay property to be true.

If you look a little more closely at the video playback, you may notice that it is very simplistic: There are no controls for playing and pausing the video. There are also no controls to indicate the progress of the video or to allow the user to skip through the video at will. In short, there are no controls whatsoever in the script.

To give your users control over the playback of a video, you need to write the controls yourself. In the remainder of this section, you write some controls on your MediaPlayer and present them to the user.

TIP

Because you thought ahead and already created a custom MediaPlayer, the process for creating your controls will be much easier.

Let’s create a quick button to control the playback of the video.

Creating a Play/Pause Button

In this section you create a play/pause button using the RoundButton custom button you created earlier in this book. If you do not have all the code for the RoundButton readily available, don’t worry. The full RoundButton script should look like this (you can re-create it from here if needed):

/*
 * RoundButton.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/23/2010 – created
 *
 * A Round Button using a SwingButton
 *
 */
package com.jfdimarzio.javafxforbeginners;

import javafx.scene.shape.Circle;

/**
 * @author JFDiMarzio
 */

public class RoundButton extends javafx.ext.swing.SwingButton{
    var type:String = '||';

   override var clip = Circle {
       centerX: 18,
        centerY: 12
       radius: 8
      };

   public var buttonType:Number on replace{
            if (buttonType == 1){
                type = '>';
            }else{
                type = '||';
            }
        };

   override var text = bind type;
}

One cosmetic change has been made to this version of the RoundButton. The type variable in this version of RoundButton has been changed from + or – to > or ||. This indicates whether the button is being used for playing the video or pausing the video, respectively.

TIP

If you need a refresher for how the RoundButton works, refer to Chapter 11.

Next, let’s change one setting in your MyMediaPlayer script. Change the autoPlay property from true to false, as shown next. This keeps the video from playing until you click the play button.

/*
 * MyMediaPlayer.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */

package com.jfdimarzio.javafxforbeginners;

import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;

/**
 * @author JFDiMarzio
 */

public class MyMediaPlayer extends MediaPlayer  {
    override var autoPlay = false;
    override var media = Media {
        source: "C:/wmdownloads/Robotica_720.wmv"
    }
}

Now that the button is ready and the MediaPlayer is ready, the last step is to set up the Chapter12.fx script to use the button in controlling the video.

The first step is to establish a variable that can be used to track what mode the video is currently in (play or pause):

var playVideo : Integer = 1;

You can bind your button to this value to determine if the video is currently being played or is currently paused. The button will really do all the work here, but you do need to help it along a little. You need to write a function for the button’s action that will play or pause the video based on the bound value of playVideo.

Use an if…else statement to test the value of playVideo; then call either myMediaPlayer .play() or myMediaPlayer.pause() accordingly. The function within your button’s action should look like this:

if (playVideo == 1){
              myMediaPlayer.play();
              playVideo = 0
}else{
              myMediaPlayer.pause();
              playVideo = 1
}

Notice that if the var playVideo is 1, the video is played and playVideo is set to 0. By setting playVideo to 0, you ensure that the next time the button is clicked, the video will be paused.

The full code of the Chapter12.fx script should appear as follows:

/*
 * Chapter12.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */

package com.jfdimarzio.javafxforbeginners;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.media.MediaView;

var myMediaPlayer: MyMediaPlayer = MyMediaPlayer {
         }
var playVideo: Integer = 1;

Stage {
    title: "EmbeddedMedia"
    onClose: function () {
    }
    scene: Scene {
         width: 1280
         height: 720
         content: [MediaView {
                mediaPlayer: myMediaPlayer
             }
            RoundButton {
                buttonType: bind playVideo;
                 action: function () {
                    if (playVideo == 1) {
                        myMediaPlayer.play();
                        playVideo = 0
                    } else {
                        myMediaPlayer.pause();
                        playVideo = 1
                    }
                }
             }
         ]
     }
}

Compile and run this example. Your video will now load, but it will not play until you click the > button. Once the video plays, the button displays “||” and clicking it will cause the video to pause.

Now that you have created a simple play/pause button, let’s make a progress indicator that allows the user to advance and rewind the video.

Creating a Progress Indicator

To create a progress indicator, you need to know two key pieces of information. First, you need to know the total length of the video you are playing. Second, you need to know at what point in time of the playback you are currently. Luckily, JavaFX can tell you both of these things. However, it may take some massaging of the data to get it into a usable format.

Within the MyMediaPlayer control is a media property. The media property is the Media node of the actual video file being played. The Media node has a property called duration. Therefore, to get the total running time of the video being played, you can make the following call:

myMediaPlayer.media.duration.toMillis();

The toMillis() method of duration translates the duration into milliseconds. Milliseconds are much easier to work with and are much more flexible than a Duration object.

To get the current playback time, you need to be a little more creative. The MediaPlay node has a property called currentTime, which also returns a Duration object that represents the current time position of the playback. Why do we need to get creative if the MediaPlayer already has a property for the current time? Keep in mind that you are creating a control that not only marks off the current playback but allows you to set the current playback position as well. For this you need to work in something a little more flexible than a Duration object.

The control you will be using as your progress indicator is a Slider. The position of the Slider’s toggle is controlled by a value property, which is typed as a Number. Therefore, it would be much easier for you if you could convert the MediaPlayer’s currentTime into a Number; this would allow you to bind the currentTime directly to the Slider.

Because currentTime is already typed as a Duration, you cannot change it to a Number, even if you override it (you cannot change the type of a property during an override). Therefore, you have to create a new property in MyMediaPlayer that can hold a translated version of the currentTime property.

Create a new public var in MyMediaPlayer called progressIndicator. In this property you are going to set currentTime to the Duration of progressIndicator, as follows:

public var progressIndicator: Number = 0 on replace {
       if (media.duration.toMillis() != java.lang.Double.NEGATIVE_INFINITY
        and media.duration.toMillis() != java.lang.Double.POSITIVE_INFINITY) {
           currentTime = media.duration.valueOf(progressIndicator);
       }
   };

In this property, after some checks to make sure that the duration of the video is valid, you use duration.valueOf() to convert progressIndicator into a currentTime value. Now, when progressIndicator is set to a value (in milliseconds), it will move the video to that time by setting currentTime. The next step is to set progressIndicator to the currentTime value, thus giving you something to bind to.

Override the currentTime property as follows:

override var currentTime on replace {
          if(media.duration.toMillis() != java.lang.Double.NEGATIVE_INFINITY
              and
            media.duration.toMillis() != java.lang.Double.POSITIVE_INFINITY
            and
            media.duration.toMillis() != 0 and
            currentTime.toMillis() != java.lang.Double.NEGATIVE_INFINITY
              and
            currentTime.toMillis() != java.lang.Double.POSITIVE_INFINITY) {
            progressIndicator = currentTime.toMillis()
        }
    }

Much like the progressIndicator property, the override for currentTime first checks that the media duration is valid and then that the currentTime is valid. Assuming it passes these checks, progressIndicator is set to currentTime converted into milliseconds.

You now have the values needed to get and set the current playback time of the video. The full MyMediaPlayer file should now look like this:

/*
 * MyMediaPlayer.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */
package com.jfdimarzio.javafxforbeginners;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;

/**
 * @author JFDiMarzio
 */
public class MyMediaPlayer extends MediaPlayer {

    override var autoPlay = false;
    public var progressIndicator: Number = 0 on replace {
         if (media.duration.toMillis() != java.lang.Double.NEGATIVE_INFINITY
         and media.duration.toMillis() !=
           java.lang.Double.POSITIVE_INFINITY) {
            currentTime = media.duration.valueOf(progressIndicator);
         }
    };
    override var currentTime on replace {
          if(media.duration.toMillis() != java.lang.Double.NEGATIVE_INFINITY
               and
              media.duration.toMillis() != java.lang.Double.POSITIVE_INFINITY
               and
              media.duration.toMillis() != 0 and
              currentTime.toMillis() != java.lang.Double.NEGATIVE_INFINITY
               and
              currentTime.toMillis() != java.lang.Double.POSITIVE_INFINITY) {
              progressIndicator = currentTime.toMillis()
         }
     }
    override var media = Media {
        source: "C:/wmdownloads/Robotica_720.wmv"
     }
}

With the values in MyMediaPlayer created and ready to be used, you can now set up your Slider.

In earlier chapters of this book, you learned how to use bind. Binding allows you to set values in properties that can be updated dynamically. The Slider you are building needs to be set dynamically to the current playback time of the video using bind. However, the Slider also needs to set the current playback time if it is changed. To accomplish this you need to use a new binding concept:

bind…with inverse

The with inverse modifier of bind allows the binding to work in both directions. Thus, the Slider value can be set from the current playback time, and changing the Slider value will also change the current playback time.

There is one caveat to using inverse binding: You cannot bind directly to the value that you want to use. Rather, you must indirectly bind to it through a variable. This concept will become clearer as you begin coding.

First, in the Chapter12.fx script, add a variable named progress, typed as a Number:

var progress : Number ;

Next, in the myMediaPlayer variable you created in the Chapter12.fx script, inverse-bind progressIndicator to the new progress variable:

var myMediaPlayer: MyMediaPlayer = MyMediaPlayer {
            progressIndicator: bind progress with inverse;
        }

Binding progressIndicator inversely to progress allows a bidirectional update of myMediaPlayer.progressIndicator through progress.

The final step is to create a Slide and inversely bind the value property to progress, as follows:

import javafx.scene.control.Slider;
Slider {
                translateX: 35
                translateY: 5
                min: 0
                max: bind myMediaPlayer.media.duration.toMillis()
                value: bind progress with inverse;
                vertical: false
            }

The final Chapter12.fx script should appear as follows:

/*
 * Chapter12.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */
package com.jfdimarzio.javafxforbeginners;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.media.MediaView;
import javafx.scene.control.Slider;

var myMediaPlayer: MyMediaPlayer = MyMediaPlayer {
            progressIndicator: bind progress with inverse;
         }

var playVideo: Integer = 1;

var progress : Number ;

Stage {
     title: "EmbeddedMedia"
     onClose: function () {
     }
     scene: Scene {
         width: 1280
         height: 720
         content: [MediaView {
                mediaPlayer: myMediaPlayer
             }
             RoundButton {
                buttonType: bind playVideo;
                 action: function () {
                    if (playVideo == 1) {
                        myMediaPlayer.play();
                         playVideo = 0
                    } else {
                        myMediaPlayer.pause();
                         playVideo = 1
                    }
                }
             }
            Slider {
                translateX: 35
                 translateY: 5
                min: 0
                max: bind myMediaPlayer.media.duration.toMillis()
                value: bind progress with inverse;
                vertical: false
             }
         ]
     }
}

Compile and run these scripts. You now have a pause/play button and a progress indicator that allows the user to change the current playback position of the video.

In the next section you learn how to use the MediaPlayer for audio playback.

Playing Audio

Audio files such as MP3s can be played just as easily as video files. In fact, simply changing the media source to an MP3 file is all that is required to turn your video player into an audio player. The following change plays the MP3 “Dream Police” by Cheap Trick:

    override var media = Media {
        source: "C:/wmdownloads/CheapTrick-DreamPolice.mp3"
    }

NOTE

As noted earlier in this chapter, there also seems to be a compatibility issue with the JavaFX media player and Mac. Hopefully this will be corrected in future releases.

JavaFX has made the playing of media files, of any format, a very easy task to take on. Using the skills you learned earlier in this chapter, create a vertical Slider to control the volume on your audio player. (Hint: The mediaPlayer has a property called volume that you can bind to as is.)

Compare your solution with the code that follows:

/*
 * Chapter12.fx
 *
 * v1.0 - J. F. DiMarzio
 *
 * 6/25/2010 – created
 *
 * Embedded Video and Music
 *
 */
package com.jfdimarzio.javafxforbeginners;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.media.MediaView;
import javafx.scene.control.Slider;
import javafx.scene.media.MediaError;

var myMediaPlayer: MyMediaPlayer = MyMediaPlayer {
            progressIndicator: bind progress with inverse;
            volume: bind playbackVolume with inverse;
        }

var playVideo: Integer = 1;
var progress : Number ;

var playbackVolume : Number = 2 ;

Stage {
     title: "EmbeddedMedia"
     onClose: function () {
     }
     scene: Scene {
         width: 200
         height: 200
         content: [MediaView {
                mediaPlayer: myMediaPlayer
             }
             RoundButton {
                buttonType: bind playVideo;
                 action: function () {
                    if (playVideo == 1) {
                        myMediaPlayer.play();
                        playVideo = 0
                    } else {
                        myMediaPlayer.pause();
                        playVideo = 1
                    }
                }
             }
             Slider {
                 translateX: 35
                 translateY: 5
                 min: 0
                 max: bind myMediaPlayer.media.duration.toMillis()
                 value: bind progress with inverse;
                 vertical: false
             }
             Slider {
                 translateX: 5
                 translateY: 35
                 min: 0
                 max: 5
                 value: bind playbackVolume with inverse;
                 vertical: true
                rotate: 180
             }
        ]
     }
}

In the next chapter you learn how to use JavaFX layouts.

images Chapter 12 Self Test

1. What node is used to hold a MediaPlayer?

2. What package contains all the nodes needed to work with media files?

3. What property of the MediaPlayer tells the media file to play once it has loaded?

4. What media formats can the MediaPlayer play?

5. What property of the MediaPlayer will pause media playback?

6. True or false? MediaPlayer.mediaLength() will give you the total running time of a media file.

7. What type is MediaPlayer.currentTime?

8. What type of binding allows for bidirectional updating?

9. True or false? Using inverse binding, you can bind directly to a value.

10. What property of MediaPlayer can you bind to in controlling the playback volume?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.2.240