perf(player): optimize frame display loop for smooth playback
Performance improvements to eliminate choppy playback: 1. Cap display FPS at 30fps: - Even 60fps videos display at max 30fps - Reduces UI update overhead significantly - Human eye can't distinguish >30fps in preview player - Video plays at full 60fps internally, display throttled 2. Skip duplicate frames: - Track lastFrameTime from GStreamer - Only update UI when currentTime changes - Prevents refreshing same frame multiple times - Eliminates the "Frame 389 updated 17 times" issue 3. Remove verbose frame logging: - Removed per-frame debug log (was slowing down UI) - Keep INFO logs for start/stop events - Still log errors when they occur 4. Cleaner logging: - Show both video fps and display fps at startup - Makes performance characteristics visible Results: - Before: Choppy playback, same frame updated repeatedly - After: Smooth 30fps display, no duplicate updates - 4K video (3840x2160) now plays smoothly
This commit is contained in:
parent
4f4504bae0
commit
e1fecbba06
22
main.go
22
main.go
|
|
@ -11356,12 +11356,18 @@ func (p *playSession) frameDisplayLoop() {
|
||||||
if p.fps <= 0 {
|
if p.fps <= 0 {
|
||||||
p.fps = 24
|
p.fps = 24
|
||||||
}
|
}
|
||||||
frameDuration := time.Second / time.Duration(p.fps)
|
// Use 30fps max for UI updates to reduce overhead (even for 60fps video)
|
||||||
|
displayFPS := p.fps
|
||||||
|
if displayFPS > 30 {
|
||||||
|
displayFPS = 30
|
||||||
|
}
|
||||||
|
frameDuration := time.Second / time.Duration(displayFPS)
|
||||||
ticker := time.NewTicker(frameDuration)
|
ticker := time.NewTicker(frameDuration)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
frameCount := 0
|
frameCount := 0
|
||||||
logging.Info(logging.CatPlayer, "playSession: frameDisplayLoop started (fps=%.2f, interval=%v)", p.fps, frameDuration)
|
lastFrameTime := time.Duration(0)
|
||||||
|
logging.Info(logging.CatPlayer, "playSession: frameDisplayLoop started (video fps=%.2f, display fps=%.2f, interval=%v)", p.fps, displayFPS, frameDuration)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
@ -11386,11 +11392,19 @@ func (p *playSession) frameDisplayLoop() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current time from GStreamer
|
||||||
|
currentTime := p.gstPlayer.GetCurrentTime()
|
||||||
|
|
||||||
|
// Skip if this is the same frame as last time (optimization)
|
||||||
|
if currentTime == lastFrameTime && frameCount > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lastFrameTime = currentTime
|
||||||
|
|
||||||
// Update frame counter
|
// Update frame counter
|
||||||
frameCount++
|
frameCount++
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
p.frameN = frameCount
|
p.frameN = frameCount
|
||||||
currentTime := p.gstPlayer.GetCurrentTime()
|
|
||||||
p.current = currentTime.Seconds()
|
p.current = currentTime.Seconds()
|
||||||
isPaused := p.paused
|
isPaused := p.paused
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
|
|
@ -11402,8 +11416,6 @@ func (p *playSession) frameDisplayLoop() {
|
||||||
p.img.File = ""
|
p.img.File = ""
|
||||||
p.img.Image = frame
|
p.img.Image = frame
|
||||||
p.img.Refresh()
|
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 && !isPaused {
|
if p.prog != nil && !isPaused {
|
||||||
p.prog(p.current)
|
p.prog(p.current)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user