Actually, you can play the video in any 3D form.
There's a great project for playing videos with @caprica called VLCJ : Java Infrastructure for VLC Media Player .
While the project is intended for rendering in AWT canvas, the author made several tests to display it also in JavaFX Canvas .
Based on its JavaFX class, it is easy to display a buffer in a 3D form instead of a 2D node canvas.
Settings
First you need to install the first VLC video player.
Then you will need some dependencies: vlcj-3.6.0.jar , jna-3.5-2.jar and platform-3.5.2.jar and slfj4j-api.1.7.12.jar.
In addition, I will use some custom 3D forms from FXyz , although you can use the regular ones from the API, like a Box .
The basics
The trick for rendering video in 3D form uses a diffuse map of its material, which takes an image and determines its texture.
You can find more information about this here or here .
So, for each available frame, we will create a new image and set it as a diffuse map:
ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size()); BufferFormat bufferFormat = ((DefaultDirectMediaPlayer) mediaPlayerComponent.getMediaPlayer()).getBufferFormat(); WritableImage textureImage = new WritableImage(bufferFormat.getWidth(), bufferFormat.getHeight()); if (bufferFormat.getWidth() > 0 && bufferFormat.getHeight() > 0) { textureImage.getPixelWriter().setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer, bufferFormat.getPitches()[0]); // apply new frame as texture image to the 3D shape material material.setDiffuseMap(textureImage); }
An AnimationTimer allows you to update frames and textures.
Example
This is a working sample that displays video on a segmented torus.
public class Video3D extends Application { static { // path to the VLC video player System.setProperty("jna.library.path", "C:/Program Files/VideoLAN/VLC"); } // http://download.blender.org/peach/bigbuckbunny_movies/ // (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org private static final String VIDEO_FILE = "C:\\BigBuckBunny_320x180.mp4"; private final DirectMediaPlayerComponent mediaPlayerComponent; private final WritablePixelFormat<ByteBuffer> pixelFormat; private final SegmentedTorusMesh torus = new SegmentedTorusMesh(50,40,12,3.2d,4.5d); private final PhongMaterial material = new PhongMaterial(Color.WHEAT); private double mousePosX, mousePosY; private double mouseOldX, mouseOldY; private final Rotate rotateX = new Rotate(-20, Rotate.X_AXIS); private final Rotate rotateY = new Rotate(240, Rotate.Y_AXIS); private final AnimationTimer timer; public TestVLC(){ mediaPlayerComponent = new TestMediaPlayerComponent(); pixelFormat = PixelFormat.getByteBgraInstance(); timer = new AnimationTimer() { @Override public void handle(long now) { renderFrame(); } }; } protected void startTimer() { mediaPlayerComponent.getMediaPlayer().playMedia(VIDEO_FILE); timer.start(); } protected void stopTimer() { mediaPlayerComponent.getMediaPlayer().stop(); timer.stop(); } @Override public void start(Stage primaryStage) { torus.setCullFace(CullFace.NONE); torus.setzOffset(1.4); torus.setMaterial(material); PerspectiveCamera camera = new PerspectiveCamera(true); camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -30)); Group root3D = new Group(camera,torus); SubScene subScene = new SubScene(root3D, 800, 600, true, SceneAntialiasing.BALANCED); subScene.setFill(Color.AQUAMARINE); subScene.setCamera(camera); BorderPane pane = new BorderPane(); pane.setCenter(subScene); Button play = new Button("Play"); play.setOnAction(e->startTimer()); Button stop = new Button("Stop"); stop.setOnAction(e->stopTimer()); ToolBar toolBar = new ToolBar(play, stop); toolBar.setOrientation(Orientation.VERTICAL); pane.setRight(toolBar); pane.setPrefSize(600,400); Scene scene = new Scene(pane); scene.setOnMousePressed((MouseEvent me) -> { mouseOldX = me.getSceneX(); mouseOldY = me.getSceneY(); }); scene.setOnMouseDragged((MouseEvent me) -> { mousePosX = me.getSceneX(); mousePosY = me.getSceneY(); rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY)); rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX)); mouseOldX = mousePosX; mouseOldY = mousePosY; }); primaryStage.setScene(scene); primaryStage.setTitle("Video - JavaFX 3D"); primaryStage.show(); } @Override public final void stop() throws Exception { stopTimer(); mediaPlayerComponent.getMediaPlayer().stop(); mediaPlayerComponent.getMediaPlayer().release(); } /** * Implementation of a direct rendering media player component that renders * the video to a JavaFX canvas. * https://github.com/caprica/vlcj-javafx/blob/master/src/test/java/uk/co/caprica/vlcj/javafx/test/JavaFXDirectRenderingTest.java */ private class TestMediaPlayerComponent extends DirectMediaPlayerComponent { public TestMediaPlayerComponent() { super(new TestBufferFormatCallback()); } } /** * Callback to get the buffer format to use for video playback. */ private class TestBufferFormatCallback implements BufferFormatCallback { @Override public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) { final int width = sourceWidth; final int height = sourceHeight; Platform.runLater(() -> { torus.setMajorRadius(width/100); torus.setMinorRadius(height/40); }); return new RV32BufferFormat(width, height); } } protected final void renderFrame() { Memory[] nativeBuffers = mediaPlayerComponent.getMediaPlayer().lock(); if (nativeBuffers != null) { Memory nativeBuffer = nativeBuffers[0]; if (nativeBuffer != null) { ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size()); BufferFormat bufferFormat = ((DefaultDirectMediaPlayer) mediaPlayerComponent.getMediaPlayer()).getBufferFormat(); WritableImage textureImage = new WritableImage(bufferFormat.getWidth(), bufferFormat.getHeight()); if (bufferFormat.getWidth() > 0 && bufferFormat.getHeight() > 0) { textureImage.getPixelWriter().setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer, bufferFormat.getPitches()[0]); material.setDiffuseMap(textureImage); } } } mediaPlayerComponent.getMediaPlayer().unlock(); } public static void main(String[] args) { launch(args); } }
And these are just two snapshots of what you get.

