Lobo Project Blog

Primarily about the Lobo web browser and the Cobra rendering engine

JavaFX Video in a Swing Application – Technically Doable

Posted by lobochief on December 29, 2008

There has already been some discussion on how you can embed a JavaFX scene object in a Swing application (see Josh Marinacci’s post). There has also been some discussion on how to write video playback code in JavaFX (see here and here).

What I wanted to find out is what it would take to play JavaFX video in a standalone Swing application. I mean technically. I won’t get into the legal aspects (discussed previously) in this post.

Figuring out which JAR files you need is not difficult to guess. The main difficulty involves the fact that various native DLLs are needed. Instead of trying to guess what the javafx startup program does differently to java, I decided to have a JavaFX program tell me, by printing properties java.class.path and java.library.path.

The java.library.path property value is not lengthy in Windows, and it is exactly what I would’ve expected.

C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop

Now take a look at java.class.path.

C:\Program  Files\JavaFX\javafx-sdk1.0\bin\..\lib\shared\javafxrt.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\eula.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\Decora-SSE.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\Decora-D3D.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\Decora-HW.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\Decora-OGL.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\Scenario.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\gluegen-rt.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\javafx-swing.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\javafxgui.jar;C:\Progr
amFiles\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\jmc.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\jogl.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\websvc.jar;C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop\script-api.jar;.;

Well, not all of those are probably needed in any given program, but I’d include all of those just so there are no differences with the javafx launcher.

So now we know how we need to run the standalone Swing application.

java -Djava.library.path=”C:\Program Files\JavaFX\javafx-sdk1.0\bin\..\lib\desktop” -cp “… humongous classpath …” javafx_tests.FXVideoPlayer

I’ve also confirmed that if you copy the DLL files to a different directory and point java.library.path to it, that also works.

We just need to write the code. What I did is come up with a FXVideoPlayer class, a Swing component. It takes a source URL and has a play() method. Its source code follows.


import javax.swing.*;
import java.awt.*;
import javafx.scene.media.*;
import javafx.scene.*;
import javafx.reflect.*;

import com.sun.javafx.runtime.TypeInfo;
import com.sun.javafx.runtime.sequence.*;
import com.sun.scenario.scenegraph.fx.*;
import com.sun.scenario.scenegraph.*;

public class FXVideoPlayer extends JPanel {
    private static final FXClassType PANEL_SCENE_TYPE;
    private final FXObjectValue fxMedia;
    private final FXClassType mediaType;
    private final FXObjectValue fxMediaPlayer;
    private final FXClassType mediaPlayerType;

    static {
        String helperName = "com.sun.javafx.scene.JSGPanelSceneImpl";
        FXClassType type = FXContext.getInstance().findClass(helperName);
        PANEL_SCENE_TYPE = type;
    }

    public FXVideoPlayer(String source) {
        Media media = new Media();
        // Some crazy JavaFX reflection here to get a Media object we can use.
        FXClassType mediaType = FXContext.getInstance().findClass(
                Media.class.getName());
        FXObjectValue fxMedia = mediaType.allocate();
        fxMedia.initVar("source", FXLocal.getContext().mirrorOf(source));
        fxMedia.initialize();
        this.fxMedia = fxMedia;
        this.mediaType = mediaType;
        // Same here to set MediaPlayer.media.
        FXClassType mediaPlayerType = FXContext.getInstance().findClass(
                MediaPlayer.class.getName());
        FXObjectValue fxMediaPlayer = mediaPlayerType.allocate();
        fxMediaPlayer.initVar("media", fxMedia);
        fxMediaPlayer.initialize();
        this.fxMediaPlayer = fxMediaPlayer;
        this.mediaPlayerType = mediaPlayerType;
        // And now we set MediaView.mediaPlayer
        FXClassType mediaViewType = FXContext.getInstance().findClass(
                MediaView.class.getName());
        FXObjectValue fxMediaView = mediaViewType.allocate();
        fxMediaView.initVar("mediaPlayer", fxMediaPlayer);
        fxMediaView.initialize();
        MediaView mediaView = (MediaView) ((FXLocal.ObjectValue) fxMediaView)
                .asObject();
        // Finally, let's create a scene!
        FXClassType sceneType = FXContext.getInstance().findClass(
                Scene.class.getName());
        FXObjectValue fxScene = sceneType.allocate();
        Sequence contentSequence = Sequences.make(TypeInfo
                .makeTypeInfo(mediaView), new MediaView[] { mediaView });
        fxScene.initVar("content", FXLocal.getContext().mirrorOf(
                contentSequence));
        fxScene.initialize();
        FXClassType type = PANEL_SCENE_TYPE;
        if (type == null) {
            throw new IllegalStateException("JSGPanelSceneImpl type not set.");
        }
        FXObjectValue panelSceneImpl = type.allocate();
        panelSceneImpl.initVar("scene", fxScene);
        panelSceneImpl.initialize();
        FXValue jsgPanelV = type.getVariable("jsgPanel").getValue(
                panelSceneImpl);
        JComponent sceneComponent = (JComponent) ((FXLocal.ObjectValue) jsgPanelV)
                .asObject();

        this.setLayout(new BorderLayout());
        this.setPreferredSize(new Dimension(100, 100));
        this.setBackground(Color.GREEN);
        this.add(BorderLayout.CENTER, sceneComponent);
    }

    public void play() {
        this.mediaPlayerType.getFunction("play").invoke(this.fxMediaPlayer);
    }

    /* Entry point for testing below */

    private static final String MEDIA_LOCATION = "http://sun.edgeboss.net/download/sun/media/1460825906/1460825906_2956241001_big-buck-bunny-640x360.flv";

    public static void main(String[] arg) {
        System.out.println("java.library.path="
                + System.getProperty("java.library.path"));
        System.out.println("java.class.path="
                + System.getProperty("java.class.path"));
        final FXVideoPlayer player = new FXVideoPlayer(MEDIA_LOCATION);
        JFrame window = new JFrame("FX View Player Test");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setLayout(new BorderLayout());
        window.add(BorderLayout.CENTER, player);
        window.setSize(new Dimension(700, 500));
        window.setVisible(true);

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                player.play();
            }
        });
    }
}

The JavaFX reflection code can get complicated, but hey, it works. It’s basically the same methodology you’d use to embed a Scene as explained by Josh Marinacci.

Of course, you could write much of the above in JavaFX and have a thiner layer in Swing, but where’s the fun in that?

4 Responses to “JavaFX Video in a Swing Application – Technically Doable”

  1. Pure Swing code with none of the JavaFX internals is at http://www.pushing-pixels.org/?p=909

  2. David said

    That’s a very good attempt to do thing differently.

    For those who want simpler solution integrating media support into Swing application can directly use the media API without the JavaFX classes and API :^> . The advantage of this approach is to reduce the complexity of the code (by not using JavaFX’s layer) and perhaps save some (Negligible) memory and offer slight performance improvement.

    So for those who want to find out how to do this can read the following Sun’s presentation
    Incorporating Media into Java and JavaFX™
    Technology Based Platforms
    http://dsc.sun.com/learning/javaoneonline/2008/pdf/TS-6509.pdf

    Have fun with JavaFX and Swing…

  3. lobochief said

    Yes, I’m sure there’s a way to do it by only using jmc.jar and the required DLLs. I’m not familiar with that API. Is there documentation on the JMC API other than the PDF?

    Personally what I was interested in finding out is if you could run JavaFX code with MediaView and MediaPlayer inside a Swing application that is run standalone (the Lobo browser) with java and not javafx. Now I see how it could potentially be done.

  4. lqd said

    Just for fun i’ll kick in another way that lets you add hw accelerated effects, transforms and all: using scenario’s SGMediaView that comes with javafx but is for swing (scenario 1.0, not the gpl’d scenario 0.6).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: