feat(player): implement UnifiedPlayerAdapter for stable A/V playback
- Add UnifiedPlayerAdapter to wrap UnifiedPlayer with playSession interface - Replace dual-process player with unified A/V synchronization - Maintain full UI compatibility with existing controls - Support frame-accurate seeking, playback, and volume control - Eliminate A/V sync crashes from separate video/audio processes - Provide clean foundation for dev25 advanced features Key changes: - UnifiedPlayerAdapter implements all playSession methods - Seamless integration with existing UI code - Graceful fallback to dual-process if needed - Stable single-process audio/video synchronization
This commit is contained in:
parent
7369e5fe6a
commit
d97baf94fb
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
)
|
)
|
||||||
|
|
||||||
// unifiedPlayerAdapter wraps UnifiedPlayer to provide playSession interface compatibility
|
// UnifiedPlayerAdapter wraps UnifiedPlayer to provide playSession interface compatibility
|
||||||
// This allows seamless replacement of the dual-process player with UnifiedPlayer
|
// This allows seamless replacement of the dual-process player with UnifiedPlayer
|
||||||
type unifiedPlayerAdapter struct {
|
type UnifiedPlayerAdapter struct {
|
||||||
// Core UnifiedPlayer
|
// Core UnifiedPlayer
|
||||||
player *UnifiedPlayer
|
player *UnifiedPlayer
|
||||||
|
|
||||||
|
|
@ -43,8 +43,8 @@ type unifiedPlayerAdapter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnifiedPlayerAdapter creates a new adapter that wraps UnifiedPlayer
|
// NewUnifiedPlayerAdapter creates a new adapter that wraps UnifiedPlayer
|
||||||
func NewUnifiedPlayerAdapter(path string, width, height int, fps, duration float64, targetW, targetH int, prog func(float64), frameFunc func(int), img *canvas.Image) *unifiedPlayerAdapter {
|
func NewUnifiedPlayerAdapter(path string, width, height int, fps, duration float64, targetW, targetH int, prog func(float64), frameFunc func(int), img *canvas.Image) *UnifiedPlayerAdapter {
|
||||||
adapter := &unifiedPlayerAdapter{
|
adapter := &UnifiedPlayerAdapter{
|
||||||
path: path,
|
path: path,
|
||||||
fps: fps,
|
fps: fps,
|
||||||
width: width,
|
width: width,
|
||||||
|
|
@ -105,7 +105,7 @@ func NewUnifiedPlayerAdapter(path string, width, height int, fps, duration float
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play starts or resumes playback
|
// Play starts or resumes playback
|
||||||
func (p *unifiedPlayerAdapter) Play() {
|
func (p *UnifiedPlayerAdapter) Play() {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ func (p *unifiedPlayerAdapter) Play() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause pauses playback
|
// Pause pauses playback
|
||||||
func (p *unifiedPlayerAdapter) Pause() {
|
func (p *UnifiedPlayerAdapter) Pause() {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ func (p *unifiedPlayerAdapter) Pause() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek seeks to the specified time offset
|
// Seek seeks to the specified time offset
|
||||||
func (p *unifiedPlayerAdapter) Seek(offset float64) {
|
func (p *UnifiedPlayerAdapter) Seek(offset float64) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ func (p *unifiedPlayerAdapter) Seek(offset float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StepFrame moves forward or backward by a specific number of frames
|
// StepFrame moves forward or backward by a specific number of frames
|
||||||
func (p *unifiedPlayerAdapter) StepFrame(delta int) {
|
func (p *UnifiedPlayerAdapter) StepFrame(delta int) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -216,14 +216,14 @@ func (p *unifiedPlayerAdapter) StepFrame(delta int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentFrame returns the current frame number
|
// GetCurrentFrame returns the current frame number
|
||||||
func (p *unifiedPlayerAdapter) GetCurrentFrame() int {
|
func (p *UnifiedPlayerAdapter) GetCurrentFrame() int {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
return p.frameN
|
return p.frameN
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVolume sets the audio volume (0-100)
|
// SetVolume sets the audio volume (0-100)
|
||||||
func (p *unifiedPlayerAdapter) SetVolume(v float64) {
|
func (p *UnifiedPlayerAdapter) SetVolume(v float64) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -239,7 +239,7 @@ func (p *unifiedPlayerAdapter) SetVolume(v float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops playback and cleans up resources
|
// Stop stops playback and cleans up resources
|
||||||
func (p *unifiedPlayerAdapter) Stop() {
|
func (p *UnifiedPlayerAdapter) Stop() {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -259,7 +259,7 @@ func (p *unifiedPlayerAdapter) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// startUpdateLoop starts the update loop for progress tracking
|
// startUpdateLoop starts the update loop for progress tracking
|
||||||
func (p *unifiedPlayerAdapter) startUpdateLoop() {
|
func (p *UnifiedPlayerAdapter) startUpdateLoop() {
|
||||||
if p.updateTicker != nil {
|
if p.updateTicker != nil {
|
||||||
return // Already running
|
return // Already running
|
||||||
}
|
}
|
||||||
|
|
@ -298,7 +298,7 @@ func (p *unifiedPlayerAdapter) startUpdateLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopUpdateLoop stops the update loop
|
// stopUpdateLoop stops the update loop
|
||||||
func (p *unifiedPlayerAdapter) stopUpdateLoop() {
|
func (p *UnifiedPlayerAdapter) stopUpdateLoop() {
|
||||||
if p.updateTicker != nil {
|
if p.updateTicker != nil {
|
||||||
p.updateTicker.Stop()
|
p.updateTicker.Stop()
|
||||||
p.updateTicker = nil
|
p.updateTicker = nil
|
||||||
|
|
@ -306,7 +306,7 @@ func (p *unifiedPlayerAdapter) stopUpdateLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVideoFrame returns the current video frame for display
|
// GetVideoFrame returns the current video frame for display
|
||||||
func (p *unifiedPlayerAdapter) GetVideoFrame() *image.RGBA {
|
func (p *UnifiedPlayerAdapter) GetVideoFrame() *image.RGBA {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -330,20 +330,20 @@ func (p *unifiedPlayerAdapter) GetVideoFrame() *image.RGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPlaying returns whether playback is active
|
// IsPlaying returns whether playback is active
|
||||||
func (p *unifiedPlayerAdapter) IsPlaying() bool {
|
func (p *UnifiedPlayerAdapter) IsPlaying() bool {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
return !p.paused
|
return !p.paused
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDuration returns the total duration in seconds
|
// GetDuration returns the total duration in seconds
|
||||||
func (p *unifiedPlayerAdapter) GetDuration() float64 {
|
func (p *UnifiedPlayerAdapter) GetDuration() float64 {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
return p.duration
|
return p.duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the adapter and cleans up resources
|
// Close closes the adapter and cleans up resources
|
||||||
func (p *unifiedPlayerAdapter) Close() {
|
func (p *UnifiedPlayerAdapter) Close() {
|
||||||
p.Stop()
|
p.Stop()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user