Improvements:
1. Track audio active state with atomic.Bool flag
2. Handle videos without audio track gracefully
- If audio fails to start, video plays at natural frame rate
- Clear error messages indicate "video-only playback"
3. Better A/V sync logging for debugging
- Log when video ahead/behind and actions taken
- Log good sync status periodically (every ~6 seconds at 30fps)
- More granular logging for different sync states
4. Proper cleanup when audio stream ends or fails
How it works:
- audioActive flag set to true when audio starts successfully
- Set to false when audio fails to start or ends
- Video checks audioActive before syncing to audio clock
- If no audio: video just paces at natural frame rate (no sync)
- If audio active: full A/V sync with adaptive timing
Expected improvements:
- Video-only files (GIFs, silent videos) play smoothly
- Better debugging info for sync quality
- Graceful degradation when audio missing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Priority 3 fix from PLAYER_PERFORMANCE_ISSUES.md - addresses the root
cause of A/V desync in player module.
Changes:
- Audio loop now tracks bytes written and updates master clock (audioTime)
- Audio clock calculation: bytesWritten / (sampleRate × channels × bytesPerSample)
- Video loop already syncs to audio master clock (from previous commit)
- Master clock updates happen after each audio chunk write
How it works:
- Audio is the timing master, plays at natural rate
- Video reads audio clock and adapts timing to stay in sync
- If video >3 frames behind: drop frame and resync
- If video >3 frames ahead: wait longer
- Otherwise: adjust sleep duration for gradual sync
Expected improvements:
- Rock-solid A/V sync maintained over extended playback
- No more drift between audio and video
- Adaptive recovery from temporary slowdowns
Combined with Priority 1 (larger audio buffers) and Priority 2 (FFmpeg
volume control), this completes the core A/V sync architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move showUpscaleView() from main.go to upscale_module.go
- Remove AI helper functions (detectAIUpscaleBackend, checkAIFaceEnhanceAvailable, etc.)
- Syntax passes, ready for further migration
- Build error is unrelated Fyne API issue in internal/ui
- Create thumb_module.go with showThumbView(), buildThumbView(), executeThumbJob()
- Remove showThumbView() from main.go
- buildThumbView() and executeThumbJob() still in main.go to be removed
- Syntax check passes
- Working on large function extraction
Priority 2: FFmpeg Volume Control
- Moved volume processing from Go to FFmpeg -af volume filter
- Eliminated CPU-intensive per-sample processing loop
- Removed ~40 lines of hot-path audio processing code
- Reduced CPU usage during playback significantly
- Dynamic volume changes restart audio seamlessly
Changes:
- Build FFmpeg command with volume filter
- Remove per-sample int16 processing loop
- Remove encoding/binary import (no longer needed)
- Add restartAudio() for dynamic volume changes
- Volume changes >5% trigger audio restart with new filter
Priority 5: Adaptive Frame Timing
- Implemented drift correction for smooth video playback
- Frame dropping when >3 frames behind schedule
- Gradual catchup when moderately behind
- Maintains smooth playback under system load
Frame Timing Logic:
- Behind < 0: Sleep until next frame (ahead of schedule)
- Behind > 3 frames: Drop frame and resync (way behind)
- Behind > 0.5 frames: Catch up gradually (moderately behind)
- Otherwise: Maintain normal pace
Performance Improvements:
- Audio: No more per-chunk volume processing overhead
- Video: Adaptive timing handles temporary slowdowns
- CPU: Significant reduction in audio processing load
- Smoothness: Better handling of system hiccups
Testing Notes:
- Audio stuttering should be greatly reduced
- Volume changes have ~200ms glitch during restart
- Frame drops logged every 30 frames to avoid spam
- Works with all frame rates (24/30/60 fps)
Still TODO (Priority 3):
- Single FFmpeg process for perfect A/V sync
- Currently separate video/audio processes can drift
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Refactoring:
- Create inspect_module.go (292 lines)
- Move showInspectView() and buildInspectView()
- Reduce main.go from 14,329 to 14,116 lines (-213 lines)
- Reduce main.go from 426KB to 420KB
This is the first step in modularizing main.go to improve:
- Windows build performance (currently 5+ minutes)
- Code maintainability and organization
- Following established pattern from author_module.go and subtitles_module.go
Remaining modules to extract:
- player, compare, thumb, filters, upscale, merge, convert, queue, benchmark
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Convert Module:
- Add "Add All to Queue" button when multiple videos loaded
- Batch-add all loaded videos to queue with one click
- Remove confirmation dialogs for faster workflow
- Queue button updates immediately to show new count
- Button only visible when 2+ videos are loaded
Workflow improvements:
- No more clicking through videos one by one to queue
- No "OK" confirmation clicks required
- Queue count updates instantly in View Queue button
- Auto-starts queue after adding jobs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Player Module Drag and Drop:
- Add handleDrop case for player module
- Drag video files onto player to load them
- Works the same way as convert module
- Auto-probe and load first video file from drop
Author Module:
- Enable Author module button in main menu
- Add "author" to enabled modules list (line 1525)
- Module is now clickable and functional
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Seeking Fixes:
- Remove debouncing delay for immediate response
- Progress bar now seeks instantly when clicked or dragged
- No more 150ms lag during playback navigation
Frame Stepping Fixes:
- Calculate current frame from time position (current * fps)
- Previously used frameN which resets to 0 on every seek
- Frame stepping now accurately moves ±1 frame from actual position
- Buttons now work correctly regardless of seek history
Technical Details:
- currentFrame = int(p.current * p.fps) instead of p.frameN
- Removed seekTimer and seekMutex debouncing logic
- Immediate Seek() call in slider.OnChanged for responsive UX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Frame Navigation:
- Add frame-by-frame stepping with Previous/Next frame buttons
- Implement StepFrame() method for precise frame control
- Auto-pause when frame stepping for accuracy
- Display real-time frame counter during playback
Responsive Scrubbing:
- Add 150ms debounce to progress bar seeking
- Prevents rapid FFmpeg restarts during drag operations
- Smoother user experience when scrubbing through video
Player Session Improvements:
- Track frame numbers accurately with frameFunc callback
- Add duration field for proper frame calculations
- Update frame counter in real-time during playback
- Display current frame number in UI (Frame: N)
UI Enhancements:
- Frame step buttons: ◀| (previous) and |▶ (next)
- Frame counter label with monospace styling
- Integrated into existing player controls layout
Technical Details:
- Frame calculation: targetFrame = currentFrame ± delta
- Time conversion: offset = frameNumber / fps
- Clamp frame numbers to valid range [0, maxFrame]
- Call frameFunc callback on each displayed frame
Foundation ready for future enhancements (keyboard shortcuts, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add authorClips, authorSubtitles, authorOutputType fields to appState
- Create authorClip struct for video clip management
- Implement drag-and-drop support for video clips and subtitles
- Add Settings tab with output type, region, aspect ratio options
- Create Video Clips tab with file management
- Add Subtitles tab for track management
- Prepare framework for DVD/ISO generation
- Update HandleAuthor to work with drag-and-drop system
- Add comprehensive file validation and error handling
- Support for multiple video clips compilation
- Ready for chapter detection and DVD authoring implementation
Queue UI:
- Fix pending job button labels - now shows "Remove" instead of "Cancel"
- Running/paused jobs still correctly show "Cancel" button
Log Viewer:
- Fix app hanging when viewing large conversion logs
- Make file reads asynchronous to prevent blocking UI thread
- Show "Loading log file..." message while reading
- Auto-scroll to bottom when log opens
Windows Console Flashing:
- Add ApplyNoWindow to all missing exec.Command calls
- Fixes command prompt windows flashing during module operations
- Applied to: hwaccel detection, encoder checks, Python backend detection
- Prevents console windows from appearing during upscale module usage
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Resolved issue where window would resize itself based on dynamic content
like progress bars and queue updates. Window now maintains the size that
the user sets, regardless of content changes.
**Problem:**
- When progress bars updated or queue content changed, the window would
automatically resize to fit the new content MinSize
- This caused the window to get larger or smaller unexpectedly
- User-set window size was not being preserved
**Solution:**
- Modified setContent() to capture current window size before setting new content
- Restore the window size after SetContent() completes
- This prevents Fyne from auto-resizing based on content MinSize changes
- Window only resizes when user manually drags edges or maximizes
**Impact:**
- Window maintains stable size through all content changes
- Progress bars, queue updates, and module switches no longer trigger resize
- User retains full control of window size via manual resize/maximize
- Improves professional appearance and user experience
Reported by: Jake
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Renamed "DVD Author" to "Author" for broader disc production workflow.
Created foundation for complete authoring pipeline with three main tasks:
**Module Structure:**
- Tabbed interface with Chapters, Rip DVD/ISO, and Author Disc tabs
- Added authorChapter struct (timestamp, title, auto-detected flag)
- Added author module state fields (file, chapters, threshold, detecting)
**Chapters Tab (Basic UI):**
- File selection with video probing integration
- Scene detection sensitivity slider (0.1-0.9 threshold)
- Placeholder UI for chapter list and controls
- Add Chapter and Export Chapters buttons (placeholders)
- Foundation for FFmpeg scdet scene detection
**Rip DVD/ISO Tab:**
- Placeholder for high-quality disc extraction
- Will support lossless ripping (like FLAC from CD)
- Preserve all audio/subtitle tracks
**Author Disc Tab:**
- Placeholder for VIDEO_TS/ISO creation
- Will support burn-ready output, NTSC/PAL, menus
Changes:
- Modified main.go: Added authorChapter struct, author state fields,
showAuthorView(), buildAuthorView(), buildChaptersTab(),
buildRipTab(), buildAuthorDiscTab()
- Modified internal/modules/handlers.go: Renamed HandleDVDAuthor to
HandleAuthor with updated comment
- Updated DONE.md with Author module skeleton details
Next steps: Implement FFmpeg scene detection, chapter list UI,
and DVD/ISO ripping functionality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Applied gofmt to fix code alignment and formatting consistency.
Changes are purely cosmetic (whitespace/alignment).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added advanced audio channel remixing features for videos with imbalanced
left/right audio channels (e.g., music in left ear, vocals in right ear).
New audio channel options using FFmpeg pan filter:
- Left to Stereo: Copy left channel to both speakers
- Right to Stereo: Copy right channel to both speakers
- Mix to Stereo: Downmix both channels together evenly
- Swap L/R: Swap left and right channels
Changes:
- Updated audioChannelsSelect dropdown with 8 options (was 4)
- Implemented pan filter logic in all 4 FFmpeg command builders:
- buildFFmpegCommandFromJob (main convert)
- DVD encoding function
- Convert command builder
- Snippet generation
- Removed unused "os" import from internal/convert/ffmpeg.go
- Updated DONE.md with audio channel remixing feature
The pan filter syntax allows precise channel routing:
- pan=stereo|c0=c0|c1=c0 (left to both)
- pan=stereo|c0=c1|c1=c1 (right to both)
- pan=stereo|c0=0.5*c0+0.5*c1|c1=0.5*c0+0.5*c1 (mix)
- pan=stereo|c0=c1|c1=c0 (swap)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Extract reset defaults logic to resetConvertDefaults function
- Add setTargetFileSize helper with syncing guard
- Add syncingTargetSize flag to prevent update loops
- Consolidate reset button handlers to call shared function
- Improves code organization and maintainability
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
UI Scaling Improvements:
- Reduce module tiles from 160x80 to 150x65
- Reduce title from 20 to 18
- Reduce queue tile from 140x50 to 120x40
- Reduce category labels to 12px
- Reduce padding from 8 to 4px
- Remove scrolling, everything fits in 800x600
Preset UX Improvements:
- Move "Manual" to bottom of all preset dropdowns
- Default bitrate preset: "2.5 Mbps - Medium Quality"
- Default target size: "100MB"
- Manual input fields hidden by default
- Show manual fields only when "Manual" selected
Encoding Preset Order:
- Reverse order: veryslow first, ultrafast last
- Better quality options now appear first
- Applied to both simple and advanced mode
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
UI Scaling:
- Reduce module tiles from 220x110 to 160x80
- Reduce title size from 28 to 20
- Reduce queue tile from 160x60 to 140x50 with smaller text
- Reduce section padding from 14 to 8 pixels
- Remove extra padding wrapper around tiles
Header Layout Improvements:
- Use border layout with title on left, controls on right
- Compact button labels: "☰ History" → "☰", "Run Benchmark" → "Benchmark"
- Eliminates wasted space in header
Queue Behavior Fix:
- "Clear Completed" always returns to main menu (not last module)
- "Clear All" always returns to main menu
- Prevents unwanted navigation to convert module after clearing
All changes work together to fit app within 800x600 default window
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
In Progress Tab Enhancements:
- Added animated striped progress bars to in-progress jobs
- Exported ModuleColor function for reuse across modules
- Shows real-time progress (0-100%) with module-specific colors
- Progress updates automatically as jobs run
- Maintains consistent visual style with queue view
Lossless Quality Preset Improvements:
- H.265 and AV1 now support all bitrate modes with lossless quality
- Lossless with Target Size mode now works for H.265/AV1
- H.264 and MPEG-2 no longer show "Lossless" option (codec limitation)
- Dynamic quality dropdown updates based on selected codec
- Automatic fallback to "Near-Lossless" when switching from lossless-capable
codec to non-lossless codec
Quality Options Logic:
- Base options: Draft, Standard, Balanced, High, Near-Lossless
- "Lossless" only appears for H.265 and AV1
- codecSupportsLossless() helper function checks compatibility
- updateQualityOptions() refreshes dropdown when codec changes
Lossless + Bitrate Mode Combinations:
- Lossless + CRF: Forces CRF 0 for perfect quality
- Lossless + CBR: Constant bitrate with lossless quality
- Lossless + VBR: Variable bitrate with lossless quality
- Lossless + Target Size: Calculates bitrate for exact file size with
best possible quality (now allowed for H.265/AV1)
Technical Implementation:
- Added Progress field to ui.HistoryEntry struct
- Exported StripedProgress widget and ModuleColor function
- updateQualityOptions() function dynamically filters quality presets
- updateEncodingControls() handles lossless modes per codec
- Descriptive hints explain each lossless+bitrate combination
This allows professional workflows where lossless quality is desired
but file size constraints still need to be met using Target Size mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Features:
- New "In Progress" tab shows running/pending jobs
- Displays active jobs without opening full queue
- Tab positioned first for quick visibility
- Shows "Running..." or "Pending" status
- No delete button on active jobs (only completed/failed)
Implementation:
- Updated BuildHistorySidebar to accept activeJobs parameter
- Converts queue.Job to ui.HistoryEntry for display
- Filters running/pending jobs from queue
- Conditional delete button (nil check)
- Dynamic status text based on job state
UX Improvements:
- Quick glance at current activity without queue view
- Three-tab layout: In Progress → Completed → Failed
- Consistent styling with existing history entries
- Tappable entries to view full job details
This allows users to monitor active conversions directly
from the history sidebar, reducing the need to constantly
check the full job queue view.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Bitrate Mode Options Now Show:
- CRF (Constant Rate Factor)
- CBR (Constant Bitrate)
- VBR (Variable Bitrate)
- Target Size (Calculate from file size)
Implementation:
- Added bidirectional mapping between short codes and full labels
- Internally still uses short codes (CRF, CBR, VBR, Target Size)
- Preserves compatibility with existing config files
- Maps display label to internal code on selection
- Maps internal code to display label when loading
Makes it immediately clear what each bitrate mode does without
needing to reference documentation or tooltips.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Command Preview Button:
- Disabled when no video source is loaded
- Shows "Show Preview" when preview is hidden
- Shows "Hide Preview" when preview is visible
- Makes it clear when and why the button can be used
Format Options Reorganization:
- Grouped formats by codec family for better readability
- Order: H.264 → H.265 → AV1 → VP9 → ProRes → MPEG-2
- Added comments explaining each codec family
- Makes it easier to find and compare similar codecs
This improves discoverability and reduces user confusion about
when the command preview is available and which format to choose.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Features:
- Add "×" delete button to each history entry in sidebar
- Click to remove individual entries from history
- Automatically saves and refreshes sidebar after deletion
Bug Fixes:
- Fix nil pointer crash when opening Convert module
- Fixed widget initialization order: bitrateContainer now created
AFTER bitratePresetSelect is initialized
- Prevented "invalid memory address" panic in tabs layout
Technical Details:
- Added deleteHistoryEntry() method to remove entries by ID
- Updated BuildHistorySidebar signature to accept onEntryDelete callback
- Moved bitrateContainer creation from line 5742 to 5794
- All Select widgets now properly initialized before container creation
The crash was caused by bitrateContainer containing a nil
bitratePresetSelect widget, which crashed when Fyne's layout system
called .Visible() during tab initialization.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix panic when closing log viewer (duplicate channel close)
- Improve CBR: Set bufsize to 2x bitrate for better encoder handling
- Improve VBR: Increase maxrate cap from 1.5x to 2x target bitrate
- Add bufsize to VBR at 4x target (2x maxrate) to enforce caps
- Update VBR hint to reflect 2x peak cap and 2-pass encoding
This eliminates runaway bitrates while maintaining quality peaks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>