Seek time is not accurate

226 views
Skip to first unread message

Phong Tran

unread,
Aug 20, 2020, 5:12:02 AM8/20/20
to gstreamer-java
Hi gstreamer.

I use your gstreamer and all working. But i have problem with seek time when i play with m3u8 media that stream from server.

The seek time go back few seconds. Example i seek time at 30s but video go back at 27s.
I use gstreamer 1.16.2 for javafx 14 on window 10.
 
Can you help me in this case. Thanks you so much.

Neil C Smith

unread,
Aug 20, 2020, 5:18:38 AM8/20/20
to gstream...@googlegroups.com
On Thu, 20 Aug 2020 at 10:12, Phong Tran <baoph...@gmail.com> wrote:
> I use your gstreamer and all working. But i have problem with seek time when i play with m3u8 media that stream from server.
>
> The seek time go back few seconds. Example i seek time at 30s but video go back at 27s.
> I use gstreamer 1.16.2 for javafx 14 on window 10.

What exactly does that mean? gst1-java-core? gst1-java-fx?

What is your code to seek? This might be due to missing use of
SeekFlags.ACCURATE -
https://javadoc.io/static/org.freedesktop.gstreamer/gst1-java-core/1.2.0/org/freedesktop/gstreamer/event/SeekFlags.html#ACCURATE

Bear in mind, this is the mailing list for the Java bindings to
GStreamer, not GStreamer itself. This question might be better
answered on their mailing list if the above doesn't help. See
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

Best wishes,

Neil

--
Neil C Smith
Codelerity Ltd.
www.codelerity.com

Codelerity Ltd. is a company registered in England and Wales
Registered company number : 12063669
Registered office address : Office 4 219 Kensington High Street,
Kensington, London, England, W8 6BD

Phong Tran

unread,
Aug 20, 2020, 5:47:42 AM8/20/20
to gstreamer-java
Thanks for your reply.

I use  gst1-java-core and  gst1-java-fx .
I play video by PlayBin
This is my code to seek time

playbin.seek((long) (position * dur), TimeUnit.MILLISECONDS);

Best wishes.





Vào lúc 16:18:38 UTC+7 ngày Thứ Năm, 20 tháng 8, 2020, neil đã viết:

Phong Tran

unread,
Aug 20, 2020, 5:55:15 AM8/20/20
to gstreamer-java
Dear Neil,
That is my full code:

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteOrder;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import org.freedesktop.gstreamer.Bin;
import org.freedesktop.gstreamer.Bus;
import org.freedesktop.gstreamer.Caps;
import org.freedesktop.gstreamer.Element;
import org.freedesktop.gstreamer.ElementFactory;
import org.freedesktop.gstreamer.Gst;
import org.freedesktop.gstreamer.Pipeline;
import org.freedesktop.gstreamer.elements.AppSink;
import org.freedesktop.gstreamer.elements.PlayBin;
import org.freedesktop.gstreamer.message.Message;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 * Hello world!
 *
 */
//@Slf4j
public class VlcjJavaFxApplication extends Application
{
    private ImageView imageView;
    private AppSink videosink;
    private Pipeline pipe;
    //private Bin bin;
    Bus bus;
    private StringBuilder caps;
    ProgressBar pgBar;
    PlayBin playbin;
    public VlcjJavaFxApplication() {
        Gst.init();
        videosink = new AppSink("GstVideoComponent");
        videosink.set("emit-signals", true);
        caps = new StringBuilder("video/x-raw, ");
        // JNA creates ByteBuffer using native byte order, set masks according to that.
        if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
            caps.append("format=BGRx");
        } else {
            caps.append("format=xRGB");
        }
        videosink.setCaps(new Caps(caps.toString()));
        videosink.set("max-buffers", 5000);
        videosink.set("drop", true);
        imageView = new ImageView();
        FXImageSink fxImageSink = new FXImageSink(videosink);
        fxImageSink.imageProperty().addListener(new ChangeListener<Image>() {

            @Override
            public void changed(ObservableValue<? extends Image> observable, Image oldValue,
                    Image newValue) {
                // TODO Auto-generated method stub
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImage(newValue);
                    }
                });
            }
        });
        
        pipe.play();
        
        // Create a PlayBin element and set the AppSink from the Swing component
        // as the video sink.
        playbin = new PlayBin("playbin");
        playbin.setVideoSink(videosink);
        Element level = ElementFactory.make("level", "level");
        playbin.set("audio-filter", level);
        bus = playbin.getBus();
        bus.connect(new Bus.MESSAGE() {
          @Override
          public void busMessage(Bus bus, Message message) {
                // TODO Auto-generated method stub
                
          }
        });
        
        
        
        playbin.stop();
        URI uri;
        
        try {
            playbin.setURI(uri);
            playbin.play();
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            //log.error("Exception", e);
        }
        
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Drawing Operations Test");
        BorderPane grid = new BorderPane();
        grid.setCenter(imageView);
        //grid.setBottom(pgBar);
        //grid.setStyle("-fx-background-color: black;");
        pgBar = new ProgressBar();
        pgBar.setPrefHeight(40);
        pgBar.setPrefWidth(460);
        pgBar.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                // TODO Auto-generated method stub
                double position = event.getX() / pgBar.getPrefWidth();
                double dur = playbin.queryDuration(TimeUnit.MILLISECONDS);
                System.out.println(position * dur);
                if (dur > 0) {
                    playbin.seek((long) (position * dur), TimeUnit.MILLISECONDS);
                } 
            }
        });
        
        Timer timer = new Timer();
        
        TimerTask task = new TimerTask()
        {
            public void run()
            {
                long dur = playbin.queryDuration(TimeUnit.MILLISECONDS);
                long pos = playbin.queryPosition(TimeUnit.MILLISECONDS);
                System.out.println(pos);
                if (dur > 0) {
                    double relPos = (double) pos / dur;
                    pgBar.setProgress(relPos);
                }  
            }

        };
        
        timer.scheduleAtFixedRate(task, 0, 50);
        imageView.fitWidthProperty().bind(grid.widthProperty()); 
        //imageView.fitHeightProperty().bind(grid.heightProperty());
        imageView.setFitHeight(460);
        pgBar.prefWidthProperty().bind(grid.widthProperty()); 
        imageView.setPreserveRatio(true);
        grid.setBottom(pgBar);
        primaryStage.setScene(new Scene(grid, 460, 500));
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        
        launch(args);
    }
    
    
}

Thanks you so much.


Vào lúc 16:47:42 UTC+7 ngày Thứ Năm, 20 tháng 8, 2020, Phong Tran đã viết:

Neil C Smith

unread,
Aug 20, 2020, 6:08:50 AM8/20/20
to gstream...@googlegroups.com
On Thu, 20 Aug 2020 at 10:47, Phong Tran <baoph...@gmail.com> wrote:
> playbin.seek((long) (position * dur), TimeUnit.MILLISECONDS);

Ah, OK, that explains it. Sorry, forgot for legacy reasons that
short-form method uses KEY_FRAME seeking. Although this is similar to
GStreamer recommendation.

See the code at
https://github.com/gstreamer-java/gst1-java-core/blob/master/src/org/freedesktop/gstreamer/Pipeline.java#L236

Call the long form of seek() directly but change the flags - try
removing KEY_FRAME and also try replacing with ACCURATE.

seek(1.0, Format.TIME, EnumSet.of(SeekFlags.FLUSH), SeekType.SET,
TimeUnit.NANOSECONDS.convert(time, unit), SeekType.NONE, -1);

OR

seek(1.0, Format.TIME, EnumSet.of(SeekFlags.FLUSH,
SeekFlags.ACCURATE), SeekType.SET, TimeUnit.NANOSECONDS.convert(time,
unit), SeekType.NONE, -1);

We really should deprecate the form of seek() you're using and add in
a seekSimple(..) mapping instead -
https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#gst_element_seek_simple

Phong Tran

unread,
Aug 20, 2020, 6:31:12 AM8/20/20
to gstreamer-java
Dear Neil,

I have try and it work correctly. 

Thanks you so much.

Vào lúc 17:08:50 UTC+7 ngày Thứ Năm, 20 tháng 8, 2020, neil đã viết:

Neil C Smith

unread,
Aug 20, 2020, 6:52:34 AM8/20/20
to gstream...@googlegroups.com
On Thu, 20 Aug 2020 at 11:31, Phong Tran <baoph...@gmail.com> wrote:
> I have try and it work correctly.
>
> Thanks you so much.

Great! Always good to hear back when something works.

Thomas Hartwig

unread,
Mar 30, 2021, 4:24:57 AM3/30/21
to gstreamer-java
I tried the suggested form however I am only able to seek in 1 second steps but not below this,  below is my call, timeStamp is the current position and difference is the gap I want to seek, if this is below 1 it is not seeking:

playbin.seek(1, Format.TIME, EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
SeekType.SET, TimeUnit.MILLISECONDS.toNanos(timeStamp) + TimeUnit.SECONDS.toNanos(difference), SeekType.NONE, -1);

Neil C Smith

unread,
Mar 30, 2021, 9:30:36 AM3/30/21
to gstream...@googlegroups.com
Hi Thomas,

On Tue, 30 Mar 2021 at 09:24, Thomas Hartwig <thomas....@gmail.com> wrote:
> I tried the suggested form however I am only able to seek in 1 second steps but not below this, below is my call, timeStamp is the current position and difference is the gap I want to seek, if this is below 1 it is not seeking:
>
> playbin.seek(1, Format.TIME, EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
> SeekType.SET, TimeUnit.MILLISECONDS.toNanos(timeStamp) + TimeUnit.SECONDS.toNanos(difference), SeekType.NONE, -1);

Is it a local file?

Try without SeekFlags.ACCURATE.
Try your code with a different codec, something like MJPEG (ie.
discrete frames) to check.
Where is timestamp coming from? Are you sure you're getting an accurate value?

If a file, what about the same video in the Swing player example -
does it seek correctly there?

Thomas Hartwig

unread,
Mar 31, 2021, 3:19:24 AM3/31/21
to gstreamer-java
Sorry, there was an error in the code. The gap was not correct. It is working well.
Reply all
Reply to author
Forward
0 new messages