Search code examples
javajavafxvlcj

VLCJ How to prepare media without playing it?


I use embeddedMediaPlayer.media().play(path); which loads the video and plays it at the same time no problems, but I'd rather it opened and didn't auto play the video. If I use embeddedMediaPlayer.media().prepare(path); it doesn't really seem to do anything since if I then use embeddedMediaPlayer.controls().play(); to play the video it doesn't start the video..

Is there something else I need to do to load the video properly? With embeddedMediaPlayer.media().play(path); I get this in the terminal showing that the video is fully loaded:

[00007fd615b78b00] videotoolbox decoder: Using Video Toolbox to decode 'h264'
[00007fd615b78b00] videotoolbox decoder: vt cvpx chroma: 420v

But with embeddedMediaPlayer.media().prepare(path); I don't get that. It seems it's not actually 'preparing' the video despite the function's name to that effect.

EDIT: Code used is from the demo program https://github.com/caprica/vlcj-javafx-demo

public class VlcjJavaFxApplication extends Application {

private final MediaPlayerFactory mediaPlayerFactory;

private final EmbeddedMediaPlayer embeddedMediaPlayer;

private ImageView videoImageView;

public VlcjJavaFxApplication() {
    this.mediaPlayerFactory = new MediaPlayerFactory();
    this.embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
    this.embeddedMediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
        @Override
        public void playing(MediaPlayer mediaPlayer) {
        }

        @Override
        public void paused(MediaPlayer mediaPlayer) {
        }

        @Override
        public void stopped(MediaPlayer mediaPlayer) {
        }

        @Override
        public void timeChanged(MediaPlayer mediaPlayer, long newTime) {
        }

        @Override
        public void mediaChanged(MediaPlayer mediaPlayer, MediaRef media) {
            System.out.println("media changed");
        }
    });
}

@Override
public void init() {
    this.videoImageView = new ImageView();
    this.videoImageView.setPreserveRatio(true);

    embeddedMediaPlayer.videoSurface().set(videoSurfaceForImageView(this.videoImageView));
}

@Override
public final void start(Stage primaryStage) throws Exception {
    List<String> params = getParameters().getRaw();
    // if (params.size() != 1) {
    //     System.out.println("Specify a single MRL");
    //     System.exit(-1);
    // }

    BorderPane root = new BorderPane();
    root.setStyle("-fx-background-color: black;");

    videoImageView.fitWidthProperty().bind(root.widthProperty());
    videoImageView.fitHeightProperty().bind(root.heightProperty());

    root.widthProperty().addListener((observableValue, oldValue, newValue) -> {
        // If you need to know about resizes
    });

    root.heightProperty().addListener((observableValue, oldValue, newValue) -> {
        // If you need to know about resizes
    });

    root.setCenter(videoImageView);

    Scene scene = new Scene(root, 1200, 675, Color.BLACK);
    primaryStage.setTitle("vlcj JavaFX");
    primaryStage.setScene(scene);
    primaryStage.show();

    scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
        public void handle(KeyEvent ke) {
            if (ke.getCode().toString() == "ESCAPE")
                System.exit(0);
            else if (ke.getCode().toString() == "SLASH")
                playPause();
        }
    });

    embeddedMediaPlayer.media()
            .prepare("/Volumes/Movies/stuff/projects/JavaFX/test/src/assets/test.mp4");
    // embeddedMediaPlayer.media()
    //         .play("/Volumes/Movies/stuff/projects/JavaFX/test/src/assets/test.mp4");//this plays fine
    // embeddedMediaPlayer.media().play(params.get(0));

    embeddedMediaPlayer.controls().setPosition(0.4f);
}

private void playPause() {
    System.out.println(embeddedMediaPlayer.status().isPlayable());//prepare - false, play = true
    embeddedMediaPlayer.controls().play();
}

Solution

  • It seems it's an actual issue or the prepare method is not supposed to work like this. Leastways I posted the issue on the developed github page and it's been open several days with no response from anyone.

    https://github.com/caprica/vlcj/issues/1094

    The vlcj demo project is set up to play a video automatically and I guess it is that way because that's the only way. The prepare method seems to prepare a video but you have to either wait...or press play once for it load and then again to play it. I guess it's kind of 'half prepared'.

    EDIT: Issue deleted directly from github by author without solution. Very odd. The author didn't seem to understand that the problem was a delay in playback, and not a failure to play back. Before the issue's deletion, there was this statement from the author which seems to explain the delay:

    "In theory, you're supposed to wait for the mediaChanged event after prepare and before calling play, because LibVLC at some point reasonably recently made setting media asynchronous."

    There's a workaround for instant playback which is to use the start method and have it pause on first opening or on media change. That way a video will be ready for playback straight away.