From 407269b6c7c1d924b9c5cacceb6eaa304c34fe1c Mon Sep 17 00:00:00 2001 From: Stu Leak Date: Sat, 10 Jan 2026 03:08:18 -0500 Subject: [PATCH] Improve GStreamer frame stepping reliability --- internal/player/gstreamer_player.go | 26 ++++++++++++++++++++++++-- main.go | 6 ++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/internal/player/gstreamer_player.go b/internal/player/gstreamer_player.go index 9eb3b05..eb404a0 100644 --- a/internal/player/gstreamer_player.go +++ b/internal/player/gstreamer_player.go @@ -134,10 +134,18 @@ func (p *GStreamerPlayer) Load(path string, offset time.Duration) error { } C.free(unsafe.Pointer(syncName)) maxBuffers := C.CString("max-buffers") - C.vt_gst_set_int(appsink, maxBuffers, C.gint(2)) + if p.preview { + C.vt_gst_set_int(appsink, maxBuffers, C.gint(2)) + } else { + C.vt_gst_set_int(appsink, maxBuffers, C.gint(1)) + } C.free(unsafe.Pointer(maxBuffers)) dropName := C.CString("drop") - C.vt_gst_set_bool(appsink, dropName, C.gboolean(1)) + if p.preview { + C.vt_gst_set_bool(appsink, dropName, C.gboolean(1)) + } else { + C.vt_gst_set_bool(appsink, dropName, C.gboolean(0)) + } C.free(unsafe.Pointer(dropName)) var audioSink *C.GstElement @@ -366,6 +374,7 @@ func (p *GStreamerPlayer) primeAfterSeekLocked() { if p.appsink == nil { return } + p.drainPendingLocked() frame, err := p.readFrameLocked(C.GstClockTime(200 * 1000 * 1000)) if err != nil || frame == nil { return @@ -373,6 +382,19 @@ func (p *GStreamerPlayer) primeAfterSeekLocked() { p.queued = frame } +func (p *GStreamerPlayer) drainPendingLocked() { + if p.appsink == nil { + return + } + for i := 0; i < 5; i++ { + sample := C.gst_app_sink_try_pull_sample((*C.GstAppSink)(unsafe.Pointer(p.appsink)), C.GstClockTime(0)) + if sample == nil { + return + } + C.gst_sample_unref(sample) + } +} + func (p *GStreamerPlayer) SetVolume(level float64) error { p.mu.Lock() defer p.mu.Unlock() diff --git a/main.go b/main.go index 1765c56..c7630c6 100644 --- a/main.go +++ b/main.go @@ -11437,9 +11437,12 @@ func (p *playSession) frameDisplayLoop() { // Get current time from GStreamer currentTime := p.gstPlayer.GetCurrentTime() + p.mu.Lock() + isPaused := p.paused + p.mu.Unlock() // Skip if this is the same frame as last time (optimization) - if currentTime == lastFrameTime && frameCount > 0 { + if currentTime == lastFrameTime && frameCount > 0 && !isPaused { continue } lastFrameTime = currentTime @@ -11452,7 +11455,6 @@ func (p *playSession) frameDisplayLoop() { p.mu.Lock() p.frameN = actualFrameNumber p.current = currentTime.Seconds() - isPaused := p.paused p.mu.Unlock() // Update UI on main thread