javamedia-playermediavlcj

vlcj setPosition()/setTime() doesn't do anything - what am I doing wrong?


thanks so much in advance for helping me with this seemingly tiny thing - yet I can't figure it out. MP4 Video/audio playback works just fine, yet I can't set the position in the video.

Here's my stripped down code:

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;

import javax.swing.JPanel;

import com.sun.jna.NativeLibrary;
import java.util.logging.Level;
import java.util.logging.Logger;
import uk.co.caprica.vlcj.binding.RuntimeUtil;
import uk.co.caprica.vlcj.player.base.ControlsApi;
import uk.co.caprica.vlcj.player.base.MediaApi;


import uk.co.caprica.vlcj.player.base.MediaPlayer;
import uk.co.caprica.vlcj.player.component.CallbackMediaPlayerComponent;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.component.callback.FilledCallbackImagePainter;
import uk.co.caprica.vlcj.player.component.callback.FixedCallbackImagePainter;
import uk.co.caprica.vlcj.player.component.callback.ScaledCallbackImagePainter;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.renderer.RendererItem;
import uk.co.caprica.vlcjplayer.event.TickEvent;
import uk.co.caprica.vlcjplayer.view.action.mediaplayer.MediaPlayerActions;


public class TestClass extends JPanel {
    private EmbeddedMediaPlayerComponent ourMediaPlayer;
    TestClass(){
        //NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "C:\\Program Files\\VideoLAN\\VLC");

        ourMediaPlayer = new EmbeddedMediaPlayerComponent();



        /* Set the canvas */
        Canvas c = new Canvas();
        c.setBackground(Color.black);
        c.setVisible(true);

        /* Set the layout */
        this.setLayout(new BorderLayout());

        /* Add the canvas */
        this.add(c, BorderLayout.CENTER);
        this.setVisible(true);
        this.add(ourMediaPlayer);



    }
    public void play() {
       /* Play the video */
 
        System.out.println("Starting...");  

        
        ourMediaPlayer.mediaPlayer().controls().setPosition((float) 0.5); // NOPE
        ourMediaPlayer.mediaPlayer().media().play("/home/manfred/ExtraDisk/Work/BTL/Movement2022/walking.mp4"); // works
        ourMediaPlayer.mediaPlayer().controls().stop(); // works
        
        ourMediaPlayer.mediaPlayer().controls().setPosition((float) 0.5); //NOPE
    
        try { 
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        ourMediaPlayer.mediaPlayer().controls().setPosition((float) 0.5);  //NOPE
        ourMediaPlayer.mediaPlayer().controls().setTime(2000); // NOPE
        ourMediaPlayer.mediaPlayer().controls().start(); //works
        
        
        //System.time.sleep(2);
        System.out.println("Started!");  
        try { 
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        ourMediaPlayer.mediaPlayer().controls().stop(); // works

    }
}

Playback via .mediaPlayer().media().play() works, so does start and stop via .mediaPlayer().controls().start() and .mediaPlayer().controls().stop().

What doesn't work is .mediaPlayer().controls().setTime(xx) and .mediaPlayer().controls().setPosition(xx), basically nothing happens.

What am I not doing right here? Is this a threading issue? Anyone have any working minimal examples?

Thanks again, any help is greatly appreciated!


Solution

  • It is not possible to use the API to set the time/position before playback has started.

    LibVLC operates asynchronously for many operations. Just calling play() does not mean that playback has started, so setting the time/position immediately after play() is called will not (always) work.

    There are at least two approaches you can use:

    1. Wait for a media player "ready" event, and set the time/position (this will fire an event each time the media player is ready, so each time you play it, although you can write a one-shot listener that unregisters itself if you only want to do it the first time you play).
        public static void main(String[] args) throws Exception {
            MediaPlayer mediaPlayer = new MediaPlayerFactory().mediaPlayers().newMediaPlayer();
    
            mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
                @Override
                public void mediaPlayerReady(MediaPlayer mediaPlayer) {
                    mediaPlayer.controls().setTime(10000);
                }
            });
    
            mediaPlayer.media().play("/home/movies/whatever.mp4");
    
            Thread.currentThread().join();
        }
    
    

    With this first approach there is the small risk that you will see one or two video frames rendered before skipping occurs.

    1. Use media options to set the start time (in seconds, including fractions of seconds like 10.5):
        public static void main(String[] args) throws Exception {
            MediaPlayer mediaPlayer = new MediaPlayerFactory().mediaPlayers().newMediaPlayer();
    
            mediaPlayer.media().play("/home/movies/whatever.mp4", ":start-time=10");
    
            Thread.currentThread().join();
        }