Lobo Project Blog

Primarily about the Lobo web browser and the Cobra rendering engine

Posts Tagged ‘video’

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?

Posted in javafx | Tagged: | 4 Comments »