fix(player): ensure GStreamer produces and displays frames properly
Critical fixes for GStreamer playback: 1. Add preroll waiting in GStreamer.Load(): - Wait for ASYNC_DONE message after setting to PAUSED - Ensures first frame is ready before playback - Prevents black screen on load 2. Fix frameDisplayLoop to always pull frames: - Remove paused check that blocked frame extraction - Frames now pulled even when paused (enables scrubbing) - Only update progress bar when playing 3. Add comprehensive logging: - Log each frame update with size and timestamp - Debug frame pull errors - Track paused state during updates 4. Fix initial paused state: - Explicitly set paused=true after load - Matches GStreamer's PAUSED state These changes fix: - Black screen issue (no frames displaying) - Scrubbing not working (frames not available when paused) - Fast duration counting (progress only updates when playing)
This commit is contained in:
parent
00df0b3b31
commit
6a604dbb35
|
|
@ -153,7 +153,20 @@ func (p *GStreamerPlayer) Load(path string, offset time.Duration) error {
|
|||
p.appsink = appsink
|
||||
p.paused = true
|
||||
|
||||
// Set to PAUSED to preroll (loads first frame)
|
||||
C.gst_element_set_state(playbin, C.GST_STATE_PAUSED)
|
||||
|
||||
// Wait for preroll to complete (first frame ready)
|
||||
bus := C.gst_element_get_bus(playbin)
|
||||
if bus != nil {
|
||||
defer C.gst_object_unref(C.gpointer(bus))
|
||||
// Wait up to 5 seconds for preroll
|
||||
msg := C.gst_bus_timed_pop_filtered(bus, 5000000000, C.GST_MESSAGE_ASYNC_DONE|C.GST_MESSAGE_ERROR)
|
||||
if msg != nil {
|
||||
C.gst_message_unref(msg)
|
||||
}
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
_ = p.seekLocked(offset)
|
||||
}
|
||||
|
|
|
|||
22
main.go
22
main.go
|
|
@ -11247,9 +11247,14 @@ func newPlaySession(path string, w, h int, fps, duration float64, targetW, targe
|
|||
return nil
|
||||
}
|
||||
|
||||
logging.Info(logging.CatPlayer, "GStreamer loaded video: %s (%.2f fps, %dx%d)", path, fps, targetW, targetH)
|
||||
|
||||
// Start frame display loop
|
||||
go sess.frameDisplayLoop()
|
||||
|
||||
// Pause initially (GStreamer is already paused after Load)
|
||||
sess.paused = true
|
||||
|
||||
return sess
|
||||
}
|
||||
|
||||
|
|
@ -11356,12 +11361,12 @@ func (p *playSession) frameDisplayLoop() {
|
|||
defer ticker.Stop()
|
||||
|
||||
frameCount := 0
|
||||
logging.Debug(logging.CatPlayer, "playSession: frameDisplayLoop started (fps=%.2f)", p.fps)
|
||||
logging.Info(logging.CatPlayer, "playSession: frameDisplayLoop started (fps=%.2f, interval=%v)", p.fps, frameDuration)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-p.stop:
|
||||
logging.Debug(logging.CatPlayer, "playSession: frameDisplayLoop stopped")
|
||||
logging.Info(logging.CatPlayer, "playSession: frameDisplayLoop stopped")
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
|
|
@ -11369,12 +11374,7 @@ func (p *playSession) frameDisplayLoop() {
|
|||
continue
|
||||
}
|
||||
|
||||
// Skip frame updates when paused
|
||||
if p.paused {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get current frame from GStreamer
|
||||
// Get current frame from GStreamer (even when paused, for seeking)
|
||||
frame, err := p.gstPlayer.GetFrameImage()
|
||||
if err != nil {
|
||||
logging.Debug(logging.CatPlayer, "Frame read error: %v", err)
|
||||
|
|
@ -11382,6 +11382,7 @@ func (p *playSession) frameDisplayLoop() {
|
|||
}
|
||||
|
||||
if frame == nil {
|
||||
// No frame available yet - pipeline may be buffering
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -11391,6 +11392,7 @@ func (p *playSession) frameDisplayLoop() {
|
|||
p.frameN = frameCount
|
||||
currentTime := p.gstPlayer.GetCurrentTime()
|
||||
p.current = currentTime.Seconds()
|
||||
isPaused := p.paused
|
||||
p.mu.Unlock()
|
||||
|
||||
// Update UI on main thread
|
||||
|
|
@ -11398,8 +11400,10 @@ func (p *playSession) frameDisplayLoop() {
|
|||
if p.img != nil {
|
||||
p.img.Image = frame
|
||||
p.img.Refresh()
|
||||
logging.Debug(logging.CatPlayer, "Frame %d updated (%.2fs, paused=%v, size=%dx%d)",
|
||||
frameCount, p.current, isPaused, frame.Bounds().Dx(), frame.Bounds().Dy())
|
||||
}
|
||||
if p.prog != nil {
|
||||
if p.prog != nil && !isPaused {
|
||||
p.prog(p.current)
|
||||
}
|
||||
if p.frameFunc != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user