Improve GStreamer seek responsiveness and allow disable toggle

This commit is contained in:
VideoTools CI 2026-01-18 06:43:36 -05:00
parent d14ca93560
commit 016d2a4f8a
3 changed files with 49 additions and 24 deletions

View File

@ -9,8 +9,16 @@ import (
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
)
// DisableGStreamer forces fallback to the stub controller even when the gstreamer build tag is set.
var DisableGStreamer bool
// newController creates a GStreamer-based controller for embedded video playback
func newController() Controller {
if DisableGStreamer {
logging.Info(logging.CatPlayer, "GStreamer disabled by settings; using stub controller")
return &stubController{}
}
config := Config{
Backend: BackendAuto,
WindowWidth: 640,
@ -132,5 +140,5 @@ func (s *stubController) SetVolume(level float64) error {
return fmt.Errorf("GStreamer player not available")
}
func (s *stubController) FullScreen() error { return fmt.Errorf("GStreamer player not available") }
func (s *stubController) Stop() error { return fmt.Errorf("GStreamer player not available") }
func (s *stubController) Close() {}
func (s *stubController) Stop() error { return fmt.Errorf("GStreamer player not available") }
func (s *stubController) Close() {}

View File

@ -2,6 +2,11 @@
package player
import "fmt"
func newFramePlayer(config Config) (framePlayer, error) {
if DisableGStreamer {
return nil, fmt.Errorf("gstreamer disabled by settings")
}
return NewGStreamerPlayer(config)
}

View File

@ -83,26 +83,37 @@ import (
var gstInitOnce sync.Once
type GStreamerPlayer struct {
mu sync.Mutex
seekMu sync.Mutex
pipeline *C.GstElement
appsink *C.GstElement
bus *C.GstBus
busQuit chan struct{}
busDone chan struct{}
events chan busEvent
paused bool
volume float64
preview bool
width int
height int
fps float64
queued *image.RGBA
lastErr string
eos bool
state C.GstState
appsink *C.GstElement
width int
height int
fps float64
mode PlayerState
paused bool
volume float64
queued *image.RGBA
lastErr string
backend Backend
config Config
seekMu sync.Mutex
events chan busEvent
mu sync.Mutex
// Cached duration
duration time.Duration
mode PlayerState
// Bus handling
busCh chan *C.GstMessage
// Bus loop controls
busStop chan struct{}
busDone chan struct{}
// Seek coalescing
lastSeekTarget time.Duration
}
type busEvent struct {
@ -163,9 +174,9 @@ func (p *GStreamerPlayer) Load(path string, offset time.Duration) error {
caps := C.gst_caps_from_string(capsStr)
C.free(unsafe.Pointer(capsStr))
if caps != nil {
capsName := C.CString("caps")
C.vt_gst_set_obj(appsink, capsName, C.gpointer(caps))
C.free(unsafe.Pointer(capsName))
capsName := C.CString("caps")
C.vt_gst_set_obj(appsink, capsName, C.gpointer(caps))
C.free(unsafe.Pointer(capsName))
C.gst_caps_unref(caps)
}
emitSignals := C.CString("emit-signals")
@ -309,7 +320,8 @@ func (p *GStreamerPlayer) Pause() error {
func (p *GStreamerPlayer) SeekToTime(offset time.Duration) error {
p.seekMu.Lock()
defer p.seekMu.Unlock()
p.lastSeekTarget = offset
p.seekMu.Unlock()
p.mu.Lock()
prevMode := p.mode
@ -471,7 +483,7 @@ func (p *GStreamerPlayer) primeAfterSeekLocked() {
return
}
p.drainPendingLocked()
frame, err := p.readFrameLocked(C.GstClockTime(200 * 1000 * 1000))
frame, err := p.readFrameLocked(C.GstClockTime(120 * 1000 * 1000))
if err != nil || frame == nil {
return
}