diff --git a/DONE.md b/DONE.md index cc13c56..e7feff5 100644 --- a/DONE.md +++ b/DONE.md @@ -17,6 +17,16 @@ This file tracks completed features, fixes, and milestones. - Proper handling for videos without black bars - 30-second timeout protection for detection process +- ✅ **Frame Rate Conversion UI with Size Estimates** + - Comprehensive frame rate options: Source, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 + - Intelligent file size reduction estimates (40-50% for 60→30 fps) + - Real-time hints showing "Converting X → Y fps: ~Z% smaller file" + - Warning for upscaling attempts with judder notice + - Automatic calculation based on source and target frame rates + - Dynamic updates when video or frame rate changes + - Supports both film (24 fps) and broadcast standards (25/29.97/30) + - Uses FFmpeg fps filter for frame rate conversion + - ✅ **Compare Module** - Side-by-side video comparison interface - Load two videos and compare detailed metadata diff --git a/TODO.md b/TODO.md index 80d0c71..35a1d14 100644 --- a/TODO.md +++ b/TODO.md @@ -11,10 +11,10 @@ This file tracks upcoming features, improvements, and known issues. - 15-30% file size reduction with zero quality loss - Add manual crop override option -- [ ] **Frame rate conversion UI** - - Dropdown: Source, 24, 25, 29.97, 30, 50, 59.94, 60 fps +- [x] **Frame rate conversion UI** (v0.1.0-dev13 - COMPLETED) + - Dropdown: Source, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 fps - Auto-suggest 60→30fps conversion with size estimate - - Show file size impact (40-45% reduction for 60→30) + - Show file size impact (40-50% reduction for 60→30) - [ ] **HEVC/H.265 preset options** - Add preset dropdown: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow diff --git a/main.go b/main.go index ff471c3..a2b7ec5 100644 --- a/main.go +++ b/main.go @@ -1999,12 +1999,44 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { }) videoCodecSelect.SetSelected(state.convert.VideoCodec) - // Encoder Preset + // Encoder Preset with hint + encoderPresetHint := widget.NewLabel("") + encoderPresetHint.Wrapping = fyne.TextWrapWord + + updateEncoderPresetHint := func(preset string) { + var hint string + switch preset { + case "ultrafast": + hint = "⚡ Ultrafast: Fastest encoding, largest files (~10x faster than slow, ~30% larger files)" + case "superfast": + hint = "⚡ Superfast: Very fast encoding, large files (~7x faster than slow, ~20% larger files)" + case "veryfast": + hint = "⚡ Very Fast: Fast encoding, moderately large files (~5x faster than slow, ~15% larger files)" + case "faster": + hint = "⏩ Faster: Quick encoding, slightly large files (~3x faster than slow, ~10% larger files)" + case "fast": + hint = "⏩ Fast: Good speed, slightly large files (~2x faster than slow, ~5% larger files)" + case "medium": + hint = "⚖️ Medium (default): Balanced speed and quality (baseline for comparison)" + case "slow": + hint = "🎯 Slow (recommended): Best quality/size ratio (~2x slower than medium, ~5-10% smaller)" + case "slower": + hint = "🎯 Slower: Excellent compression (~3x slower than medium, ~10-15% smaller files)" + case "veryslow": + hint = "🐌 Very Slow: Maximum compression (~5x slower than medium, ~15-20% smaller files)" + default: + hint = "" + } + encoderPresetHint.SetText(hint) + } + encoderPresetSelect := widget.NewSelect([]string{"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"}, func(value string) { state.convert.EncoderPreset = value logging.Debug(logging.CatUI, "encoder preset set to %s", value) + updateEncoderPresetHint(value) }) encoderPresetSelect.SetSelected(state.convert.EncoderPreset) + updateEncoderPresetHint(state.convert.EncoderPreset) // Bitrate Mode bitrateModeSelect := widget.NewSelect([]string{"CRF", "CBR", "VBR", "Target Size"}, func(value string) { @@ -2198,6 +2230,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { videoCodecSelect, widget.NewLabelWithStyle("Encoder Preset (speed vs quality)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), encoderPresetSelect, + encoderPresetHint, widget.NewLabelWithStyle("Quality Preset", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), qualitySelect, widget.NewLabelWithStyle("Bitrate Mode", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),