Playback Audio with Video and Create a Media Playback Component Using JavaFX

Exclusive offer: get 50% off this eBook here
JavaFX 1.2 Application Development Cookbook

JavaFX 1.2 Application Development Cookbook — Save 50%

Over 60 recipes to create rich Internet applications with many exciting features

$23.99    $12.00
by Vladimir Vivien | August 2010 | Cookbooks Java

One of the exciting features of JavaFX is its inherent support for multimedia. In the previous article we saw Manipulating Images with JavaFX. In this article by Vladimir Vivien, author of JavaFX 1.2 Application Development Cookbook, readers learn how to playback both audio and video using the Media API. This article also shows how to create practical custom playback controls.

In this article, we will cover the following topics:

  • Playing audio with MediaPlayer
  • Playing video with MediaView
  • Creating a media playback component

(For more resources on Java, see here.)

Playing audio with MediaPlayer

Playing audio is an important aspect of any rich client platform. One of the celebrated features of JavaFX is its ability to easily playback audio content. This recipe shows you how to create code that plays back audio resources using the MediaPlayer class.

Getting ready

This recipe uses classes from the Media API located in the javafx.scene.media package. As you will see in our example, using this API you are able to load, configure, and playback audio using the classes Media and MediaPlayer. For this recipe, we will build a simple audio player to illustrate the concepts presented here. Instead of using standard GUI controls, we will use button icons loaded as images. If you are not familiar with the concept of loading images, review the recipe Loading and displaying images with ImageView in the previous article.

In this example we will use a JavaFX podcast from Oracle Technology Network TechCast series where Nandini Ramani discusses JavaFX. The stream can be found at http://streaming.oracle.com/ebn/podcasts/media/8576726_Nandini_Ramani_030210.mp3.

How to do it...

The code given next has been shortened to illustrate the essential portions involved in loading and playing an audio stream. You can get the full listing of the code in this recipe from ch05/source-code/src/media/AudioPlayerDemo.fx.

def w = 400;
def h = 200;
var scene:Scene;
def mediaSource = "http://streaming.oracle.com/ebn/podcasts/media/
8576726_Nandini_Ramani_030210.mp3";

def player = MediaPlayer {media:Media{source:mediaSource}}

def controls = Group {
layoutX:(w-110)/2
layoutY:(h-50)/2
effect:Reflection{
fraction:0.4 bottomOpacity:0.1 topOffset:3
}
content:[
HBox{spacing:10 content:[
ImageView{id:"playCtrl"
image:Image{url:"{__DIR__}play-large.png"}
onMouseClicked:function(e:MouseEvent){
def playCtrl = e.source as ImageView;
if(not(player.status == player.PLAYING)){
playCtrl.image =
Image{url:"{__DIR__}pause-large.png"}
player.play();
}else if(player.status == player.PLAYING){
playCtrl.image =
Image{url:"{__DIR__}play-large.png"}
player.pause();
}
}
}
ImageView{id:"stopCtrl"
image:Image{url:"{__DIR__}stop-large.png"}
onMouseClicked:function(e){
def playCtrl = e.source as ImageView;
if(player.status == player.PLAYING){
playCtrl.image =
Image{url:"{__DIR__}play-large.png"}
player.stop();
}
}
}
]}
]
}

When the variable controls is added to a scene object and the application is executed, it produces the screen shown in the following screenshot:

Playback Audio with Video and Create a Media Playback Component Using JavaFX

How it works...

The Media API is comprised of several components which, when put together, provides the mechanism to stream and playback the audio source. To playback audio requires two classes, including Media and MediaPlayer. Let's take a look at how these classes are used to playback audio in the previous example.

  • The MediaPlayer—the first significant item in the code is the declaration and initialization of a MediaPlayer instance assigned to the variable player. To load the audio file, we assign an instance of Media to player.media. The Media class is used to specify the location of the audio. In our example, it is a URL that points to an MP3 file.
  • The controls—the play, pause, and stop buttons are grouped in the Group object called controls. They are made of three separate image files: play-large.png, pause-large.png, and stop-large.png, loaded by two instances of the ImageView class. The ImageView objects serve to display the control icons and to control the playback of the audio:
    • When the application starts, imgView displays image play-large.png. When the user clicks on the image, it invokes its action-handler function, which firsts detects the status of the MediaPlayer instance. If it is not playing, it starts playback of the audio source by calling player.play() and replaces the play-large.png with the image pause-large.png. If, however, audio is currently playing, then the audio is stopped and the image is replaced back with play-large.png.
    • The other ImageView instance loads the stop-large.png icon. When the user clicks on it, it calls its action-handler to first stop the audio playback by calling player.stop(). Then it toggles the image for the "play" button back to icon play-large.png.

As mentioned in the introduction, JavaFX will play the MP3 file format on any platform where the JavaFX format is supported. Anything other than MP3 must be supported natively by the OS's media engine where the file is played back. For instance, on my Mac OS, I can play MPEG-4, because it is a supported playback format by the OS's QuickTime engine.

There's more...

The Media class models the audio stream. It exposes properties to configure the location, resolves dimensions of the medium (if available; in the case of audio, that information is not available), and provides tracks and metadata about the resource to be played.

The MediaPlayer class itself is a controller class responsible for controlling playback of the medium by offering control functions such as play(), pause(), and stop(). It also exposes valuable playback data including current position, volume level, and status. We will use these additional functions and properties to extend our playback capabilities in the recipe Controlling media playback in this article.

See also

 

JavaFX 1.2 Application Development Cookbook Over 60 recipes to create rich Internet applications with many exciting features
Published: August 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(For more resources on Java, see here.)

Playing video with MediaView

The previous recipe shows you how to play audio using the JavaFX Media API. This recipe builds on the versatility of the Media API and extends the previous recipe, Playing audio with MediaPlayer, and creates a video player with a few changes to the code.

Getting ready

This recipe uses classes from the Media API located in the javafx.scene.media package. As mentioned in the introduction of this recipe, the example presented here extends the code from the previous recipe to transform the audio player to now play video. We are going to reuse the same icons and the same logic to control the playback of the video. To review how to configure and use the Media API for playback, review the previous recipe Playing audio with MediaPlayer.

To illustrate video playback, the application plays back the award-winning, open-sourced, short, animated movie Big Buck Bunny. By default, the recipe will play the 854 x 480 H.264 version found at the address http://mirror.bigbuckbunny.de/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov.

How to do it...

Similar to audio, playing video is simple. The abbreviated code given next highlights the portion of the code that is changed to be able to display video. You can see the full listing of the code at ch05/source-code/src/media/VideoPlayerDemo.fx.

def w = 800;
def h = 600;
def maxW = w * 0.8;
def maxH = h * 0.7;
var scene:Scene;
def mediaSource =
"http://mirror.bigbuckbunny.de/peach/bigbuckbunny_movies/big_buck_
bunny_480p_h264.mov";

def player = MediaView{
layoutX:(w - maxW)/2 layoutY:(h-maxH)/2
mediaPlayer:MediaPlayer {media:Media{source:mediaSource}}
fitWidth:maxW fitHeight:maxH
}

def controls = Group {
layoutX:(w-110)/2
layoutY:h-100
effect:Reflection{
fraction:0.4 bottomOpacity:0.1 topOffset:3}
content:[
HBox{spacing:10 content:[
ImageView{id:"playCtrl"
image:Image{url:"{__DIR__}play-large.png"}
onMouseClicked:function(e:MouseEvent){
def playCtrl = e.source as ImageView;
if(not(player.mediaPlayer.status ==
MediaPlayer.PLAYING)){
playCtrl.image = Image{
url:"{__DIR__}pause-large.png"
}
player.mediaPlayer.play();
}else if(player.mediaPlayer.status ==
MediaPlayer.PLAYING){
playCtrl.image = Image{
url:"{__DIR__}play-large.png"
}
player.mediaPlayer.pause();
}
}
}
ImageView{id:"stopCtrl"
image:Image{url:"{__DIR__}stop-large.png"}
onMouseClicked:function(e:MouseEvent){
def playCtrl = e.source as ImageView;
if(player.mediaPlayer.status ==
MediaPlayer.PLAYING){
playCtrl.image = Image{
url:"{__DIR__}play-large.png"
}
player.mediaPlayer.stop();
}
}
}
]}
]
}

When the Group variable controls and the MediaView instance's player are placed on the scene, the application will create a window as shown in the next screenshot.

Playback Audio with Video and Create a Media Playback Component Using JavaFX

How it works...

While playing audio only requires the use of the classes Media and MediaPlayer, playing video requires an additional class called the MediaView. It is of type Node and can be used to display the content of a video on the screen. Let's take a closer look at the code:

  • The MediaView—the first major component to be initialized is the MediaView assigned to variable player. The code uses the MediaView instance to configure the dimensions and the location where the video will be rendered. In order to control playback, the code assigns the player.mediaPlayer property an instance of MediaPlayer, used to control playback. MediaPlayer is then assigned an instance of Media (through the property MediaPlayer.media) to specify the location of the video resource we want to playback.
  • The controls—the GUI controls in this example work the exact same way as described in Playing audio with MediaPlayer. We use a group of image icons to represent playback functions play, pause, and stop. When the play icon is pressed, it is starts playing the video by calling the player.mediaPlayer.play() function and toggles itself to the pause icon. When the pause icon is pressed, it pauses the video using function player.mediaPlayer.pause(). Finally, when the user presses the stop button, it makes a call to player.mediaPlayer.stop() to stop playback and toggles the play button back to the play icon.

There's more...

Processing video is expensive. The JavaFX MediaView class supports properties which can be used to provide rendering-time hints to maximize playback performance. These Boolean properties include:

  • compositable:Boolean—if true, other nodes may overlay the MediaView node using transparency.
  • preserveRatio:Boolean—if true, the aspect ratio of the video is preserved when the node is resized through the fitWidth or fitHeight property.
  • rotatable:Boolean—when true, it allows the MediaView node to receive rotation requests through the rotate property.
  • transformable:Boolean—the node will only apply transformations through the transforms:Transform[] property when this is set to true.

See also

 

JavaFX 1.2 Application Development Cookbook Over 60 recipes to create rich Internet applications with many exciting features
Published: August 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(For more resources on Java, see here.)

Creating a media playback component

The previous two recipes, Playing audio with MediaPlayer and Playing video with MediaView, show you how to build applications quickly to playback media sources with basic controls, such as play, pause, and stop. However, the Media API supports more functionalities than what have been discussed so far. This recipe shows you how to build a custom media component to playback media sources providing extended functionalities such as fast forward, reverse, and timing information.

Getting ready

This recipe uses classes from the Media API located in the javafx.scene.media package. The example presented here extends the code from the previous recipe Playing video with MediaView to create a playback component. The component will take advantage of the functionalities and runtime data provided by the Media API to extend the features of the video player example. Before you continue, ensure that you are familiar with the materials covered in the recipes Playing audio with MediaPlayer and Playing video with MediaView.

How to do it...

The shortened code given next provides highlights of the more significant items involved in creating the playback component. You can access the full listing of the code from ch05/source-code/src/media/MediaControllerComponent.fx.

  1. Let's define class MediaController as CustomNode that encapsulates the playback icons/buttons and control logic:

    class MediaController extends CustomNode{
    public var mediaPlayer:MediaPlayer;

    var timestat = bind
    "{%02d mediaPlayer.currentTime.toHours()
    mod 12 as Integer}:"
    "{%02d mediaPlayer.currentTime.toMinutes()
    mod 60 as Integer}:"
    "{%02d mediaPlayer.currentTime.toSeconds()
    mod 60 as Integer}/"
    "{%02d mediaPlayer.media.duration.toHours()
    mod 12 as Integer}:"
    "{%02d mediaPlayer.media.duration.toMinutes()
    mod 60 as Integer}:"
    "{%02d mediaPlayer.media.duration.toSeconds()
    mod 60 as Integer}";

    // image icons
    def imgReverse = Image{url:"{__DIR__}reverse-small.png"};
    def imgPlay = Image{url:"{__DIR__}play-small.png"};
    def imgPause = Image{url:"{__DIR__}pause-small.png"};
    def imgFfwd = Image{url:"{__DIR__}ffwd-small.png"};
    def imgVolup = Image{url:"{__DIR__}volup-small.png"}
    def imgVolDn = Image{url:"{__DIR__}voldown-small.png"};

    def controls = Group {
    content:[
    HBox{spacing:10 content:[
    // reverse button
    ImageView{id:"reverseCtrl" image:imgReverse
    onMousePressed:function(e:MouseEvent){
    mediaPlayer.currentTime =
    mediaPlayer.currentTime
    - (mediaPlayer.media.duration * 0.01);
    }
    }

    // play button
    ImageView{id:"playCtrl" image:imgPlay
    onMouseClicked:function(e:MouseEvent){
    ... // starts media playback
    }
    }

    // fast forward
    ImageView{id:"ffwdCtrl" image:imgFfwd
    onMousePressed:function(e:MouseEvent){
    mediaPlayer.currentTime =
    mediaPlayer.currentTime
    + (mediaPlayer.media.duration * 0.01);
    }
    }

    // volume up
    ImageView{id:"voldn" image:imgVolDn;
    onMouseClicked:function(e){
    mediaPlayer.volume =
    mediaPlayer.volume - 0.4;
    }
    }

    // volume down
    ImageView{id:"volup" image:imgVolup
    onMouseClicked:function(e){
    mediaPlayer.volume =
    mediaPlayer.volume + 0.4;
    }
    }
    ]}

    // progress bar
    Line{
    startX:0 startY:40 endX:100 endY:40
    stroke:Color.MAROON
    }
    Circle{
    radius:5
    fill:Color.MAROON
    centerX:bind
    if(mediaPlayer.media.duration > 0ms)
    (mediaPlayer.currentTime /
    mediaPlayer.media.duration)*100
    else 5
    centerY:40
    }
    Text{
    x:105 y:35
    textAlignment:TextAlignment.LEFT
    textOrigin:TextOrigin.TOP
    font:Font.font("Sans Serif", 10)
    content: bind timestat
    }
    ]
    }
    override protected function create () : Node {
    return controls
    }
    }

  2. The next code segment shows you how to use the MediaController class defined earlier:

    def w = 800;
    def h = 600;
    def maxW = w * 0.8;
    def maxH = h * 0.7;
    var scene:Scene;
    def mediaSource = "http://mirror.bigbuckbunny.de/peach/bigbuckbunny_
    movies/big_buck_bunny_480p_h264.mov";

    def video = MediaView{
    layoutX:(w - maxW)/2 layoutY:(h-maxH)/2
    mediaPlayer:MediaPlayer {media:Media{source:mediaSource}}
    fitWidth:maxW fitHeight:maxH
    }

    def controls = MediaController {
    mediaPlayer: video.mediaPlayer
    showReflection:true
    layoutX: (w - 200)/2 layoutY:video.fitHeight + 50
    }

When we place variable video and the instance of MediaController in a scene and execute the application, we get a screen as shown in the next screenshot:

Playback Audio with Video and Create a Media Playback Component Using JavaFX

How it works...

The custom class presented in this recipe implements a CustomNode which encapsulates the icons and logic for media playback control functions including reverse, play, fast-forward, volume up, and volume down. The class also provides visual feedback on the length and current progression of the video playback. Let's take a closer look at the custom class:

  • Textual time progression—before we look at the control functions, we will look at how the component reports time progression for the playback. The first item involved in time progression feedback is the variable timestat (to which a Text object that displays progression information is bound). timestat is itself bound to several expressions that return values containing current time and total time of playback, using values from mediaPlayer.currentTime and mediaPlayer.media.duration. Since time is reported as a Duration type, we have to pluck out each time subdivision (hour, minute, seconds) individually using the mod operator. Then, each unit is formatted to be printed as zero-padded values as shown in the snippet below:

    var timestat = bind
    "{%02d mediaPlayer.currentTime.toHours()
    mod 12 as Integer}:"
    "{%02d mediaPlayer.currentTime.toMinutes()
    mod 60 as Integer}:"
    ...

  • Visual time progression—to provide visual feedback of the progression of the playback, the media controller uses a custom progress bar composed of a Circle that slides along a Line instance. The line represents the total duration of the video, and the location of the circle (along the line) represents the current position of the playhead. To achieve this, the Circle.centerX property is bound to an expression that returns a ratio of mediaPlayer.currentTime/mediaPlayer.media.duration. This ratio is used to normalize the progress bar by multiplying it to the length of the line to get the current position of the circle, as shown in the snippet below:

    Circle{
    ...
    centerX:bind
    if(mediaPlayer.media.duration > 0ms)
    (mediaPlayer.currentTime /
    mediaPlayer.media.duration)*100
    else 5
    }

  • The controls—as before, the control buttons consist of image icons displayed by instances of ImageView. The custom component loads six icons that represent functionalities such as reverse, play, pause, fast-forward, volume up, and volume down. The play and pause icons, assigned to ImageView instance with id = "playCtrl", use the same logic from previous media playback recipes (consult the recipe Playing audio with MediaPlayer for details). Let's see how the others work:
    • To fast-forward and reverse, we use ImageView instances with id="reverseCtrl" and id="ffwdCtrl" respectively. When the user clicks on these icons, the code adds one percent of the total duration to (or subtracts from) mediaPlayer.currentTime property. This has the effect of moving the playhead in the desired direction.
    • To adjust the volume is even simpler. We use instances of ImageView with id="volup" and id="voldn" to control the volume. When the user clicks on the icon, it sets mediaPlayer.volume to the desired ratio. To increase the volume we add 0.4 to the current volume. To decrease the volume, we subtract 0.4 from the current volume level.

Summary

In this article, we will cover the following topics:

  • Playing audio with MediaPlayer
  • Playing video with MediaView
  • Creating a media playback component

Further resources on this subject:


About the Author :


Vladimir Vivien

Vladimir Vivien is a software engineer living in the United States. Past and current experiences include development in Java and .Net for industries including publishing, financial, and healthcare where he worked with a number of varied technologies including user-facing GUI frontends and backend mid-tiers. Vladimir enjoys taking part in open source projects and has contributed JmxBuilder to the Groovy project and is an author of other projects such as JmxLogger. Beside JavaFX, he has a wide range of technology interests including Java, OSGi, Scala, and anything else that runs on the JVM.

Books From Packt


NetBeans Platform 6.9 Developer's Guide
NetBeans Platform 6.9 Developer's Guide

MooTools 1.2 Beginner's Guide
MooTools 1.2 Beginner's Guide

YUI 2.8: Learning the Library
YUI 2.8: Learning the Library

Learning Ext JS 3.0
Learning Ext JS 3.0

Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server

Tomcat 6 Developer's Guide
Tomcat 6 Developer's Guide

Spring Persistence with Hibernate
Spring Persistence with Hibernate

EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g
EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software