- Add VTPlayer interface with microsecond precision seeking - Implement MPV controller for frame-accurate playback - Add VLC backend support for cross-platform compatibility - Create FFplay wrapper to bridge existing controller - Add factory pattern for automatic backend selection - Implement Fyne UI wrapper with real-time controls - Add frame extraction capabilities for preview system - Support preview mode for trim/upscale/filter modules - Include working demo and implementation documentation
166 lines
3.8 KiB
Go
166 lines
3.8 KiB
Go
package player
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
// Factory creates VTPlayer instances based on backend preference
|
|
type Factory struct {
|
|
config *Config
|
|
}
|
|
|
|
// NewFactory creates a new player factory with the given configuration
|
|
func NewFactory(config *Config) *Factory {
|
|
return &Factory{
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
// CreatePlayer creates a new VTPlayer instance based on the configured backend
|
|
func (f *Factory) CreatePlayer() (VTPlayer, error) {
|
|
if f.config == nil {
|
|
f.config = &Config{
|
|
Backend: BackendAuto,
|
|
Volume: 100.0,
|
|
}
|
|
}
|
|
|
|
backend := f.config.Backend
|
|
|
|
// Auto-select backend if needed
|
|
if backend == BackendAuto {
|
|
backend = f.selectBestBackend()
|
|
}
|
|
|
|
switch backend {
|
|
case BackendMPV:
|
|
return f.createMPVPlayer()
|
|
case BackendVLC:
|
|
return f.createVLCPlayer()
|
|
case BackendFFplay:
|
|
return f.createFFplayPlayer()
|
|
default:
|
|
return nil, fmt.Errorf("unsupported backend: %v", backend)
|
|
}
|
|
}
|
|
|
|
// selectBestBackend automatically chooses the best available backend
|
|
func (f *Factory) selectBestBackend() BackendType {
|
|
// Try MPV first (best for frame accuracy)
|
|
if f.isMPVAvailable() {
|
|
return BackendMPV
|
|
}
|
|
|
|
// Try VLC next (good cross-platform support)
|
|
if f.isVLCAvailable() {
|
|
return BackendVLC
|
|
}
|
|
|
|
// Fall back to FFplay (always available with ffmpeg)
|
|
if f.isFFplayAvailable() {
|
|
return BackendFFplay
|
|
}
|
|
|
|
// Default to MPV and let it fail with a helpful error
|
|
return BackendMPV
|
|
}
|
|
|
|
// isMPVAvailable checks if MPV is available on the system
|
|
func (f *Factory) isMPVAvailable() bool {
|
|
// Check for mpv executable
|
|
_, err := exec.LookPath("mpv")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// Additional platform-specific checks could be added here
|
|
// For example, checking for libmpv libraries on Linux/Windows
|
|
|
|
return true
|
|
}
|
|
|
|
// isVLCAvailable checks if VLC is available on the system
|
|
func (f *Factory) isVLCAvailable() bool {
|
|
_, err := exec.LookPath("vlc")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// Check for libvlc libraries
|
|
// This would be platform-specific
|
|
switch runtime.GOOS {
|
|
case "linux":
|
|
// Check for libvlc.so
|
|
_, err := exec.LookPath("libvlc.so.5")
|
|
if err != nil {
|
|
// Try other common library names
|
|
_, err := exec.LookPath("libvlc.so")
|
|
return err == nil
|
|
}
|
|
return true
|
|
case "windows":
|
|
// Check for VLC installation directory
|
|
_, err := exec.LookPath("libvlc.dll")
|
|
return err == nil
|
|
case "darwin":
|
|
// Check for VLC app or framework
|
|
_, err := exec.LookPath("/Applications/VLC.app/Contents/MacOS/VLC")
|
|
return err == nil
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// isFFplayAvailable checks if FFplay is available on the system
|
|
func (f *Factory) isFFplayAvailable() bool {
|
|
_, err := exec.LookPath("ffplay")
|
|
return err == nil
|
|
}
|
|
|
|
// createMPVPlayer creates an MPV-based player
|
|
func (f *Factory) createMPVPlayer() (VTPlayer, error) {
|
|
// Use the existing MPV controller
|
|
return NewMPVController(f.config)
|
|
}
|
|
|
|
// createVLCPlayer creates a VLC-based player
|
|
func (f *Factory) createVLCPlayer() (VTPlayer, error) {
|
|
// Use the existing VLC controller
|
|
return NewVLCController(f.config)
|
|
}
|
|
|
|
// createFFplayPlayer creates an FFplay-based player
|
|
func (f *Factory) createFFplayPlayer() (VTPlayer, error) {
|
|
// Wrap the existing FFplay controller to implement VTPlayer interface
|
|
return NewFFplayWrapper(f.config)
|
|
}
|
|
|
|
// GetAvailableBackends returns a list of available backends
|
|
func (f *Factory) GetAvailableBackends() []BackendType {
|
|
var backends []BackendType
|
|
|
|
if f.isMPVAvailable() {
|
|
backends = append(backends, BackendMPV)
|
|
}
|
|
if f.isVLCAvailable() {
|
|
backends = append(backends, BackendVLC)
|
|
}
|
|
if f.isFFplayAvailable() {
|
|
backends = append(backends, BackendFFplay)
|
|
}
|
|
|
|
return backends
|
|
}
|
|
|
|
// SetConfig updates the factory configuration
|
|
func (f *Factory) SetConfig(config *Config) {
|
|
f.config = config
|
|
}
|
|
|
|
// GetConfig returns the current factory configuration
|
|
func (f *Factory) GetConfig() *Config {
|
|
return f.config
|
|
}
|