Improve GStreamer seek responsiveness and allow disable toggle
This commit is contained in:
parent
d14ca93560
commit
016d2a4f8a
|
|
@ -9,8 +9,16 @@ import (
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
|
"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
|
// newController creates a GStreamer-based controller for embedded video playback
|
||||||
func newController() Controller {
|
func newController() Controller {
|
||||||
|
if DisableGStreamer {
|
||||||
|
logging.Info(logging.CatPlayer, "GStreamer disabled by settings; using stub controller")
|
||||||
|
return &stubController{}
|
||||||
|
}
|
||||||
|
|
||||||
config := Config{
|
config := Config{
|
||||||
Backend: BackendAuto,
|
Backend: BackendAuto,
|
||||||
WindowWidth: 640,
|
WindowWidth: 640,
|
||||||
|
|
@ -132,5 +140,5 @@ func (s *stubController) SetVolume(level float64) error {
|
||||||
return fmt.Errorf("GStreamer player not available")
|
return fmt.Errorf("GStreamer player not available")
|
||||||
}
|
}
|
||||||
func (s *stubController) FullScreen() 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) Stop() error { return fmt.Errorf("GStreamer player not available") }
|
||||||
func (s *stubController) Close() {}
|
func (s *stubController) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
package player
|
package player
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
func newFramePlayer(config Config) (framePlayer, error) {
|
func newFramePlayer(config Config) (framePlayer, error) {
|
||||||
|
if DisableGStreamer {
|
||||||
|
return nil, fmt.Errorf("gstreamer disabled by settings")
|
||||||
|
}
|
||||||
return NewGStreamerPlayer(config)
|
return NewGStreamerPlayer(config)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,26 +83,37 @@ import (
|
||||||
var gstInitOnce sync.Once
|
var gstInitOnce sync.Once
|
||||||
|
|
||||||
type GStreamerPlayer struct {
|
type GStreamerPlayer struct {
|
||||||
mu sync.Mutex
|
|
||||||
seekMu sync.Mutex
|
|
||||||
pipeline *C.GstElement
|
pipeline *C.GstElement
|
||||||
appsink *C.GstElement
|
|
||||||
bus *C.GstBus
|
bus *C.GstBus
|
||||||
busQuit chan struct{}
|
appsink *C.GstElement
|
||||||
busDone chan struct{}
|
|
||||||
events chan busEvent
|
width int
|
||||||
paused bool
|
height int
|
||||||
volume float64
|
fps float64
|
||||||
preview bool
|
mode PlayerState
|
||||||
width int
|
paused bool
|
||||||
height int
|
volume float64
|
||||||
fps float64
|
queued *image.RGBA
|
||||||
queued *image.RGBA
|
lastErr string
|
||||||
lastErr string
|
backend Backend
|
||||||
eos bool
|
config Config
|
||||||
state C.GstState
|
seekMu sync.Mutex
|
||||||
|
events chan busEvent
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
|
||||||
|
// Cached duration
|
||||||
duration time.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 {
|
type busEvent struct {
|
||||||
|
|
@ -163,9 +174,9 @@ func (p *GStreamerPlayer) Load(path string, offset time.Duration) error {
|
||||||
caps := C.gst_caps_from_string(capsStr)
|
caps := C.gst_caps_from_string(capsStr)
|
||||||
C.free(unsafe.Pointer(capsStr))
|
C.free(unsafe.Pointer(capsStr))
|
||||||
if caps != nil {
|
if caps != nil {
|
||||||
capsName := C.CString("caps")
|
capsName := C.CString("caps")
|
||||||
C.vt_gst_set_obj(appsink, capsName, C.gpointer(caps))
|
C.vt_gst_set_obj(appsink, capsName, C.gpointer(caps))
|
||||||
C.free(unsafe.Pointer(capsName))
|
C.free(unsafe.Pointer(capsName))
|
||||||
C.gst_caps_unref(caps)
|
C.gst_caps_unref(caps)
|
||||||
}
|
}
|
||||||
emitSignals := C.CString("emit-signals")
|
emitSignals := C.CString("emit-signals")
|
||||||
|
|
@ -309,7 +320,8 @@ func (p *GStreamerPlayer) Pause() error {
|
||||||
|
|
||||||
func (p *GStreamerPlayer) SeekToTime(offset time.Duration) error {
|
func (p *GStreamerPlayer) SeekToTime(offset time.Duration) error {
|
||||||
p.seekMu.Lock()
|
p.seekMu.Lock()
|
||||||
defer p.seekMu.Unlock()
|
p.lastSeekTarget = offset
|
||||||
|
p.seekMu.Unlock()
|
||||||
|
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
prevMode := p.mode
|
prevMode := p.mode
|
||||||
|
|
@ -471,7 +483,7 @@ func (p *GStreamerPlayer) primeAfterSeekLocked() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.drainPendingLocked()
|
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 {
|
if err != nil || frame == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user