- Add GStreamer as mandatory core dependency in install.sh - Create controller_gstreamer.go wrapping GStreamerPlayer - Add missing methods to GStreamerPlayer (SetWindow, Stop, SetFullScreen) - Fix GstSeekFlags type casting issue - Update build scripts to always use -tags gstreamer - Update controller_linux.go build tag to exclude when gstreamer enabled - Add comprehensive migration documentation GStreamer replaces the broken FFmpeg pipe-based UnifiedPlayer. GStreamer 1.26+ provides frame-accurate seeking and reliable A/V sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
9.1 KiB
GStreamer Player Migration Plan
Goal: Replace the broken FFmpeg pipe-based player with the robust GStreamer implementation.
Timeline: 1-2 days (vs. weeks of debugging pipes)
Phase 1: Make GStreamer a Core Dependency ✅ COMPLETE
What We Did
- Updated
install.shto always install GStreamer dev libraries - Added verification checks for GStreamer presence
- Updated
build-linux.shto require GStreamer and fail if missing - Updated
build.shto always use-tags gstreamer
Verification
# Check GStreamer is installed
pkg-config --modversion gstreamer-1.0
# Should show version like: 1.24.x
Status
✅ COMPLETE - Scripts updated, GStreamer is now mandatory
Phase 2: Build and Verify GStreamer Works
Tasks
-
Install GStreamer (if not already done)
sudo dnf install -y \ gstreamer1-devel \ gstreamer1-plugins-base-devel \ gstreamer1-plugins-good \ gstreamer1-plugins-bad-free \ gstreamer1-plugins-ugly-free \ gstreamer1-libav -
Build with GStreamer
cd /home/stu/Projects/VideoTools ./scripts/build.shExpected output:
Checking for GStreamer (required for player)... GStreamer found (1.24.x) Building VideoTools with GStreamer player... Build successful! -
Test basic playback
./VideoTools # Go to Player module # Load a test video # Click Play
Success Criteria
- ✅ Build completes without GStreamer errors
- ✅ VideoTools launches without crashes
- ✅ Player module loads without errors
- ✅ Can load a video file
- ✅ Basic play/pause works
Troubleshooting
Build Error: "Package gstreamer-1.0 was not found"
- Solution: Run
./scripts/install.shto install GStreamer
Runtime Error: "gstreamer playbin unavailable"
- Solution: Install GStreamer plugins:
sudo dnf install gstreamer1-plugins-base
Phase 3: Remove UnifiedPlayer Completely
Tasks
-
Delete broken FFmpeg pipe player
git rm internal/player/unified_ffmpeg_player.go git rm internal/player/unified_player_adapter.go -
Update frame_player_default.go
// Remove build tag (GStreamer is now always used) package player func newFramePlayer(config Config) (framePlayer, error) { return NewGStreamerPlayer(config) } -
Remove unused VTPlayer interface (if applicable)
- Check if
vtplayer.gointerface is still needed - If not, remove it
- Check if
-
Clean up imports
- Remove any references to UnifiedPlayer
- Run
gofmtand verify build still works
Success Criteria
- ✅ UnifiedPlayer files deleted
- ✅ No references to UnifiedPlayer in codebase
- ✅ Build still succeeds
- ✅ Player still works
Verification
# Search for any remaining UnifiedPlayer references
grep -r "UnifiedPlayer" internal/player/
# Should return nothing (or only comments)
# Rebuild and test
./scripts/build.sh
./VideoTools
Phase 4: Fill Gaps in GStreamer Implementation
Your GStreamer player is already 90% complete, but let's verify and add missing pieces.
Current Status (from gstreamer_player.go)
| Feature | Status | Line # |
|---|---|---|
| Load video | ✅ Complete | 73-162 |
| Play/Pause | ✅ Complete | 164-186 |
| SeekToTime | ✅ Complete | 188-204 |
| SeekToFrame | ✅ Complete | 206-214 |
| GetFrameImage | ✅ Complete | 229-289 |
| SetVolume | ✅ Complete | 291-301 |
| GetCurrentTime | ✅ Complete | 216-227 |
| Close/cleanup | ✅ Complete | 303-319 |
Missing Features to Add
4.1: Add GetDuration()
func (p *GStreamerPlayer) GetDuration() time.Duration {
p.mu.Lock()
defer p.mu.Unlock()
if p.pipeline == nil {
return 0
}
var dur C.gint64
if C.gst_element_query_duration(p.pipeline, C.GST_FORMAT_TIME, &dur) == 0 {
return 0
}
return time.Duration(dur)
}
4.2: Add GetFrameRate()
func (p *GStreamerPlayer) GetFrameRate() float64 {
p.mu.Lock()
defer p.mu.Unlock()
return p.fps
}
4.3: Add Stop() method
func (p *GStreamerPlayer) Stop() error {
p.mu.Lock()
defer p.mu.Unlock()
if p.pipeline != nil {
C.gst_element_set_state(p.pipeline, C.GST_STATE_NULL)
}
return nil
}
Tasks
- Add missing methods above to
gstreamer_player.go - Ensure
framePlayerinterface inframe_player.gomatches - Update
UnifiedPlayerAdapterif needed (or remove it - see Phase 3) - Test each new method
Success Criteria
- ✅ All interface methods implemented
- ✅ Duration displays correctly in UI
- ✅ Frame rate is accurate
- ✅ Stop button works properly
Phase 5: Test and Validate All Player Features
Test Matrix
| Feature | Test Case | Expected Result |
|---|---|---|
| Load | Drop video file | Video loads, shows duration |
| Play | Click play | Smooth playback, no stuttering |
| Pause | Click pause | Video freezes, audio stops |
| Seek | Drag timeline | Jumps to position accurately |
| Frame Step | Use arrow keys | Advances 1 frame at a time |
| Volume | Adjust slider | Volume changes smoothly |
| Mute | Click mute | Audio cuts off completely |
| Fullscreen | Press F | Video fills screen |
| Multiple Formats | Load MP4, MKV, AVI | All play correctly |
| High Resolution | Load 4K video | Plays without freezing |
| Long Videos | Load 2+ hour file | Seeking still accurate |
Performance Tests
- CPU Usage - Should be <20% during playback (check with
htop) - Memory Leaks - Run for 30 minutes, memory should stay stable
- Frame Drops - Monitor for dropped frames during playback
Integration Tests
- Trim Module - Load video, use frame-accurate seeking
- Filters Module - Apply filter, see real-time preview
- Preview System - Generate thumbnails quickly
Success Criteria
- ✅ All test cases pass
- ✅ No crashes during extended playback
- ✅ Frame-accurate seeking works perfectly
- ✅ CPU/Memory usage is reasonable
- ✅ All video formats supported
Timeline Estimate
| Phase | Time | Blockers |
|---|---|---|
| Phase 1 ✅ | Done | None |
| Phase 2 | 30 minutes | Installing GStreamer |
| Phase 3 | 15 minutes | None (just deleting code) |
| Phase 4 | 1-2 hours | Testing each method |
| Phase 5 | 2-3 hours | Thorough testing |
| Total | 4-6 hours | vs. weeks on pipes |
What Changed vs. Old Approach
Old Way (UnifiedPlayer with FFmpeg pipes)
❌ Manual pipe management
❌ Manual A/V sync (never worked right)
❌ Audio disabled to "fix" issues
❌ Frame reading blocks UI
❌ Seeking requires process restart
❌ Weeks of debugging
New Way (GStreamer)
✅ GStreamer handles pipes internally
✅ Built-in A/V synchronization
✅ Audio works out of the box
✅ Non-blocking frame extraction
✅ Native frame-accurate seeking
✅ Hours of implementation
Rollback Plan (If Needed)
If GStreamer has issues (unlikely):
-
Keep old code temporarily
git mv internal/player/unified_ffmpeg_player.go internal/player/unified_ffmpeg_player.go.bak -
Revert build scripts
git checkout HEAD -- scripts/build*.sh -
File issue with details
- GStreamer version:
pkg-config --modversion gstreamer-1.0 - Error message
- Test video format
- GStreamer version:
But honestly, your GStreamer code is solid. You won't need this.
Key Decision Points
Should We Keep UnifiedPlayerAdapter?
Recommendation: DELETE IT
- It's a compatibility shim for the old player
- GStreamerPlayer already implements the
framePlayerinterface - Extra layer adds complexity and bugs
- Clean break is better
What About VTPlayer Interface?
Recommendation: SIMPLIFY
Current:
framePlayer interface (8 methods) ✅ Used by GStreamer
VTPlayer interface (30+ methods) ❓ Overly complex
Keep framePlayer, remove or simplify VTPlayer.
Post-Migration Cleanup
Once everything works:
-
Update PROJECT_STATUS.md
| Player | ✅ **Implemented** | GStreamer-based, stable playback | -
Update README.md
- Add GStreamer to requirements
- Note improved player stability
-
Archive old commits
git tag archive/ffmpeg-pipe-player HEAD~20 git push origin archive/ffmpeg-pipe-player -
Unblock dependent modules
- Start Trim module implementation
- Start Filters module implementation
Emergency Contacts / Resources
- GStreamer Docs: https://gstreamer.freedesktop.org/documentation/
- Go CGO Guide: https://golang.org/cmd/cgo/
- Similar Projects:
- Kdenlive (uses GStreamer with Qt)
- Pitivi (uses GStreamer with Python)
Success Definition
You'll know this migration is complete when:
- ✅ Build always uses GStreamer (no fallback)
- ✅ All player features work correctly
- ✅ No UnifiedPlayer code remains
- ✅ You can implement Trim module without player bugs
- ✅ PROJECT_STATUS.md shows Player as "Implemented"
Estimated completion: Tomorrow (vs. weeks fighting pipes)