Question

I have written a code using vlcj which is intended to take screenshots of a video periodically. When I try to output the length of the video, it prints 0. What is the issue ?

import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;

import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;

public class ScreenShotCapture {

    public static void main(String[] args){
        NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "C:\\Program Files\\VideoLAN\\VLC");
        Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
        MediaPlayerFactory mediaPlayerFactory = new MediaPlayerFactory();
        final EmbeddedMediaPlayer mediaPlayer =mediaPlayerFactory.newEmbeddedMediaPlayer();
        mediaPlayer.playMedia("E:\\videos\\Avenged Sevenfold - So Far Away [Music Video].mp4");
        mediaPlayer.setSnapshotDirectory("E:\\vidoes");
        long length = mediaPlayer.getTime();
        long interval = length / 21;
        for(long  i = 1;i <= length;i+= interval){
            mediaPlayer.setTime(i);
            mediaPlayer.saveSnapshot();
        }
    }
}
Was it helpful?

Solution

The media length is not immediately available, it will become available some time after the media has started playing when the decoder works out what the length is. That is just inherently how VLC works.

Just about everything works asynchronously, which means you must base your code on events rather than writing code in only a procedural way.

When the length changes a native event gets generated, ultimately causing a MediaPlayerEventListener#lengthChanged event to fire. When that event has fired, the call to mediaPlayer.getLength() should return a non-zero value.

The next issue is that you invoke saveSnapshot immediately after you invoke setTime. Again, setTime works asynchronously so you can not assume that the media player has reached the desired time when that method returns. You have to wait for a timeChanged event and check if your time has been reached (actually passed) yet or not.

The final issue, that may or may not be important depending on your use-case, is that the call to saveSnapshot is itself asynchronous so essentially you have requested a snapshot but it has not been generated yet. This time you need to wait for the snapshotTaken event. Only when that event has been received has the snapshot actually been saved to disk.

So basically you need to think differently and implement an event-based approach instead.

One example of that is in this vlcj example that generates snapshots: https://github.com/caprica/vlcj/blob/vlcj-3.0.1/src/test/java/uk/co/caprica/vlcj/test/condition/ConditionTest.java

If you don't like that example, then you can implement it just by responding to the events in your own MediaPlayerEventListener implementation.

An aside: you can also use the VLC "Scene" filter to generate snapshots in a reliable way.

OTHER TIPS

I assume it's not caused by your spelling mistake in setting the snapshot directory?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top