3-2. Playing Video

Problem

You want to view a video file complete with controls to play, pause, stop, and seek.

Solution

Create a video media player by utilizing the following classes:

  • javafx.scene.media.Media
  • javafx.scene.media.MediaPlayer
  • javafx.scene.media.MediaView

The following code is an implementation of a JavaFX basic video player:

public void start(final Stage primaryStage) {
    primaryStage.setTitle("Chapter 3-2 Playing Video");
    ... setting up the stage

    // rounded rectangle with slightly transparent        
    Node applicationArea = createBackground(scene);
    root.getChildren().add(applicationArea);

    // allow the user to drag window on the desktop
    attachMouseEvents(scene, primaryStage);

    // allows the user to see the progress of the video playing
    progressSlider = createSlider(scene);
    root.getChildren().add(progressSlider);

    // Dragging over surface
    scene.setOnDragOver(… Drag Over code );

    // update slider as video is progressing (later removal)
    progressListener = new ChangeListener<Duration>() {
        public void changed(ObservableValue<? extends Duration> observable, Duration
oldValue, Duration newValue) {
            progressSlider.setValue(newValue.toSeconds());
        }
    };


    // Dropping over surface
    scene.setOnDragDropped(new EventHandler<DragEvent>() {

        @Override
        public void handle(DragEvent event) {
            Dragboard db = event.getDragboard();
            boolean success = false;
            URI resourceUrlOrFile = null;

            … // detect and obtain media file

            // load media
            Media media = new Media(resourceUrlOrFile.toString());

            // stop previous media player and clean up
            if (mediaPlayer != null) {
                mediaPlayer.stop();
                mediaPlayer.currentTimeProperty().removeListener(progressListener);
                mediaPlayer.setOnPaused(null);
                mediaPlayer.setOnPlaying(null);
                mediaPlayer.setOnReady(null);
            }

            // create a new media player
            mediaPlayer = MediaPlayerBuilder.create()
                    .media(media)
                    .build();

            // as the media is playing move the slider for progress
            mediaPlayer.currentTimeProperty().addListener(progressListener);


            // play video when ready status
            mediaPlayer.setOnReady(new Runnable() {
                @Override
                public void run() {
                   progressSlider.setValue(1);

progressSlider.setMax(mediaPlayer.getMedia().getDuration().toMillis()/1000);
                   mediaPlayer.play();
                }
            });

            // Lazy init media viewer
            if (mediaView == null) {
                mediaView = MediaViewBuilder.create()
                        .mediaPlayer(mediaPlayer)
                        .x(4)
                        .y(4)
                        .preserveRatio(true)
                        .opacity(.85)
                        .smooth(true)
                        .build();

mediaView.fitWidthProperty().bind(scene.widthProperty().subtract(220));

mediaView.fitHeightProperty().bind(scene.heightProperty().subtract(30));

                // make media view as the second node on the scene.
                root.getChildren().add(1, mediaView);
            }

            // sometimes loading errors occur
            mediaView.setOnError(new EventHandler<MediaErrorEvent>() {
                public void handle(MediaErrorEvent event) {
                    event.getMediaError().printStackTrace();
                }
            });

            mediaView.setMediaPlayer(mediaPlayer);

            event.setDropCompleted(success);
            event.consume();
        }
    });

    // rectangular area holding buttons
    final Group buttonArea = createButtonArea(scene);

    // stop button will stop and rewind the media
    Node stopButton = createStopControl();

    // play button can resume or start a media
    final Node playButton = createPlayControl();

    // pauses media play
    final Node pauseButton = createPauseControl();

    stopButton.setOnMousePressed(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent me) {
            if (mediaPlayer!= null) {
                buttonArea.getChildren().removeAll(pauseButton, playButton);
                buttonArea.getChildren().add(playButton);
                mediaPlayer.stop();                  
            }
        }
    });
    // pause media and swap button with play button
    pauseButton.setOnMousePressed(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent me) {
            if (mediaPlayer!=null) {
                buttonArea.getChildren().removeAll(pauseButton, playButton);
                buttonArea.getChildren().add(playButton);
                mediaPlayer.pause();
                paused = true;
            }
        }
    });

    // play media and swap button with pause button
    playButton.setOnMousePressed(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent me) {  
            if (mediaPlayer != null) {
                buttonArea.getChildren().removeAll(pauseButton, playButton);
                buttonArea.getChildren().add(pauseButton);
                paused = false;
                mediaPlayer.play();                    
            }
        }
    });

    // add stop button to button area
    buttonArea.getChildren().add(stopButton);

    // set pause button as default
    buttonArea.getChildren().add(pauseButton);

    // add buttons
    root.getChildren().add(buttonArea);

    // create a close button
    Node closeButton= createCloseButton(scene);
    root.getChildren().add(closeButton);

    primaryStage.setOnShown(new EventHandler<WindowEvent>() {
        public void handle(WindowEvent we) {
            previousLocation = new Point2D(primaryStage.getX(), primaryStage.getY());
        }
    });

    primaryStage.setScene(scene);
    primaryStage.show();

}

Following is our attachMouseEvents() method that adds an EventHandler to the Scene to provide the ability to make the video player go into full screen mode.

private void attachMouseEvents(Scene scene, final Stage primaryStage) {

        // Full screen toggle
        scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event){
                if (event.getClickCount() == 2) {
                    primaryStage.setFullScreen(!primaryStage.isFullScreen());
                }
            }
        });
        ... // the rest of the EventHandlers
    }

The following code is a method that creates a slider control with a ChangeListener to enable the user to seek backward and forward through the video:

    private Slider createSlider(Scene scene) {
        Slider slider = SliderBuilder.create()
                .min(0)
                .max(100)
                .value(1)
                .showTickLabels(true)
                .showTickMarks(true)
                .build();
        
        slider.valueProperty().addListener(new ChangeListener<Number>() {
            public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
                if (paused) {
                    long dur = newValue.intValue() * 1000;
                    mediaPlayer.seek(new Duration(dur));
                }
            }
        });
        slider.translateYProperty().bind(scene.heightProperty().subtract(30));
        return slider;
    }

Figure 3-3 depicts a JavaFX basic video player with a slider control.

images

Figure 3-3. JavaFX basic video player

How It Works

To create a video player you will model the application similar to recipe 3-1 by reusing the same application features such as drag-and-drop files, media button controls, and so on. For the sake of clarity, I took the previous recipe and moved much of the UI code into convenience functions so you will be able to focus on the Media APIs without getting lost in the UI code. The rest of the recipes in this chapter consist of adding simple features to the JavaFX basic media player created in this recipe. This being said, the code snippets in the following recipes will be brief, consisting of the necessary code needed for each new desired feature.

Before we begin, I want to talk about media formats. As of the writing of this book. JavaFX 2.0 supports a cross-platform video format called VP6 with a file extension of .flv (which stands for the popular Adobe Flash Video format). The actual encoder and decoder (Codec) to create VP6 and .flv files are licensed through a company called On2. In 2009, On2 was acquired by Google to build VP7 and VP8 to be open and free to advance HTML5. I don’t want to confuse you with the drama, but it is difficult to see how things will unfold as media formats become favored or considered obsolete. Because JavaFX’s goal is to be cross-platform, it would seem logical to use the most popular codec on the Net, but you will be forced to obtain a license to encode your videos into the VP6 .flv file format. So the bottom line is that JavaFX currently can only play video files that are encoded in VP6. (I try to keep in mind that this is the state of media formats today, so don’t channel any frustrations toward the JavaFX SDK.) Please refer to the Javadoc API for more details on the formats to be used. A word to the wise: beware of web sites claiming to be able to convert videos for free. As of this writing, the only encoders capable of encoding video to VP6 legally are the commercial converters from Adobe and Wildform (http://www.wildform.com).

Now, that you know what is the acceptable file format you are probably wondering how to obtain such a file of this type if you don’t have encoding software. If you don’t have an .flv file lying around, you can obtain one from one of my favorite sites called the Media College (http://www.mediacollege.com). From photography to movies, Media College provides forums, tutorials, and resources that help guide you into the world of media. There you will obtain a particular media file to be used in the remaining recipes in this chapter. To obtain the .flv file you will navigate to the following URL: http://www.mediacollege.com/adobe/flash/video/tutorial/example-flv.html.

Next, you will locate the link entitled Windy 50s Mobility Scooter Race that points to our .flv media file (20051210-w50s.flv). In order to download a link consisting of a file, right-click to select “Save target as” or “Save link as”. Once you have saved the file locally on your file system, you can drag the file into the media player application to begin the demo.

images Note As of the writing of this book, the JavaFX media player API currently supports the video format VP6 using an .flv container.

Just like the audio player created in the last recipe, our JavaFX basic video player has the same basic media controls, including stop, pause, and play. In addition to these simple controls we have added new capabilities such as seeking and full screen mode.

When playing a video you’ll need a view area (javafx.scene.media.MediaView) to show the video. You will also be creating a slider control to monitor the progress of the video, which is located at the lower left of the application shown in Figure 3-3. The slider control allows the user to seek backward and forward through the video. The ability to seek will work only if the video is paused. One last bonus feature is making the video become full screen by double-clicking the application window. To restore the window, repeat the double click or press Escape.

To quickly get started, let’s jump into the code. After setting up the stage in the start() method, you will create a black semitransparent background by calling the createBackground() method (applicationArea). Next, you will be invoking the attachMouseEvents() method to wire up all the EventHandlers into the scene that will enable the user to drag the application window about the desktop. Another EventHandler to be attached to the Scene will allow the user to switch to full screen mode. To make a window turn into full screen mode, you will create a conditional to check for the double click of the application window. Once the double-click is performed you will call the Stage’s method setFullScreen() with a Boolean value opposite of the currently set value. Shown here is how to make a window go to full screen mode:

        // Full screen toggle
        scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event){
                if (event.getClickCount() == 2) {
                    primaryStage.setFullScreen(!primaryStage.isFullScreen());
                }
            }
        });

As we continue our steps inside the start() method, you will create a slider control by calling the convenience method createSlider(). The createSlider() method will instantiate a Slider control and add a ChangeListener to move the slider as the video is playing. The ChangeListener’s changed() method is invoked any time the slider’s value changes. Once the changed() method is invoked you will have an opportunity to see the old value and the new value. The following code creates a ChangeListener to update the slider as the video is being played:

    // update slider as video is progressing (later removal)
    progressListener = new ChangeListener<Duration>() {
        public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
            progressSlider.setValue(newValue.toSeconds());
        }
    };

After creating the progress listener (progressListener), you will be creating the dragged-dropped EventHandler on the Scene.

The goal is to determine whether the pause button was pressed before the user can move the slider. Once a paused flag is determined, you will obtain the new value to be converted to milliseconds. The dur variable is used to move the mediaPlayer to seek the position into the video as the user slides the control left or right. The ChangeListener’s changed() method is invoked any time the slider’s value changes. The following code is responsible for moving the seek position into the video based on the user moving the slider.

slider.valueProperty().addListener(new ChangeListener<Number>() {
   public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number
newValue) {
                if (paused) {
                    long dur = newValue.intValue() * 1000;
                    mediaPlayer.seek(new Duration(dur));
                }
            }
        });

Moving right along, you will be implementing a drag-dropped EventHandler to handle the .flv media file being dropped into the application window area. Here you’ll first check to see whether there was a previous mediaPlayer. If so, you will stop the previous mediaPlayer object and do some cleanup:

        // stop previous media player and clean up
        if (mediaPlayer != null) {
           mediaPlayer.stop();
           mediaPlayer.currentTimeProperty().removeListener(progressListener);
           mediaPlayer.setOnPaused(null);
           mediaPlayer.setOnPlaying(null);
           mediaPlayer.setOnReady(null);
        }



        // play video when ready status
        mediaPlayer.setOnReady(new Runnable() {
            @Override
            public void run() {
               progressSlider.setValue(1);

        progressSlider.setMax(mediaPlayer.getMedia().getDuration().toMillis()/1000);
           mediaPlayer.play();
        }
    }); // setOnReady()

As with the audio player, we create a Runnable instance to be run when the media player is in a ready state. You’ll notice also that the progressSlider control being set up to use values in seconds.

Once the media player object is in a ready state you will be creating a MediaView instance to display the media. Shown following is the creation of a MediaView object to be put into the scene graph to display video content:

            // Lazy init media viewer
            if (mediaView == null) {
                mediaView = MediaViewBuilder.create()
                        .mediaPlayer(mediaPlayer)
                        .x(4)
                        .y(4)
                        .preserveRatio(true)
                        .opacity(.85)
                        .build();


                mediaView.fitWidthProperty().bind(scene.widthProperty().subtract(220));
                mediaView.fitHeightProperty().bind(scene.heightProperty().subtract(30));

                        // make media view as the second node on the scene.
                        root.getChildren().add(1, mediaView);
                    }

                    // sometimes loading errors occur
                    mediaView.setOnError(new EventHandler<MediaErrorEvent>() {
                        public void handle(MediaErrorEvent event) {
                            event.getMediaError().printStackTrace();
                        }
                    });

                    mediaView.setMediaPlayer(mediaPlayer);
                    event.setDropCompleted(success);
                    event.consume();
                }
            });

Whew! We are finally finished with our drag-dropped EventHandler for our Scene. Up next is pretty much the rest of the media button controls similar to the end of recipe 3-1. The only thing different is a single instance variable named paused of type boolean that denotes whether the video was paused. This paused flag when set to true will allow the slider control to seek forward or backward through the video; otherwise false. Following is the pauseButton and playButton controlling the mediaPlayer object and setting the paused flag accordingly:

// pause media and swap button with play button
pauseButton.setOnMousePressed(new EventHandler<MouseEvent>() {
    public void handle(MouseEvent me) {
        if (mediaPlayer!=null) {
            buttonArea.getChildren().removeAll(pauseButton, playButton);
            buttonArea.getChildren().add(playButton);
            mediaPlayer.pause();
            paused = true;
        }
    }
});


// play media and swap button with pause button
playButton.setOnMousePressed(new EventHandler<MouseEvent>() {
    public void handle(MouseEvent me) {  
        if (mediaPlayer != null) {
            buttonArea.getChildren().removeAll(pauseButton, playButton);
            buttonArea.getChildren().add(pauseButton);
            paused = false;
            mediaPlayer.play();                    
        }
    }
});

So that is how to create a video media player. In the next recipe, you will be able to listen to media events and invoke actions.

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

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