Add frame interpolation presets in Filters
This commit is contained in:
parent
2f9995d8f1
commit
28e2f40b75
1
DONE.md
1
DONE.md
|
|
@ -835,6 +835,7 @@ This file tracks completed features, fixes, and milestones.
|
||||||
- ✅ Reduced module video pane minimum sizes to allow GNOME window snapping
|
- ✅ Reduced module video pane minimum sizes to allow GNOME window snapping
|
||||||
- ✅ Added cache/temp directory setting with SSD recommendation and override
|
- ✅ Added cache/temp directory setting with SSD recommendation and override
|
||||||
- ✅ Snippet defaults now use conversion settings (not Match Source)
|
- ✅ Snippet defaults now use conversion settings (not Match Source)
|
||||||
|
- ✅ Added frame interpolation presets to Filters and wired filter chain to Upscale
|
||||||
- ✅ Stabilized video seeking and embedded rendering
|
- ✅ Stabilized video seeking and embedded rendering
|
||||||
- ✅ Improved player window positioning
|
- ✅ Improved player window positioning
|
||||||
- ✅ Fixed clear video functionality
|
- ✅ Fixed clear video functionality
|
||||||
|
|
|
||||||
1
TODO.md
1
TODO.md
|
|
@ -67,6 +67,7 @@ This file tracks upcoming features, improvements, and known issues.
|
||||||
- Snippet UI rearranged into Convert Snippet / Batch / Options with context-sensitive visibility
|
- Snippet UI rearranged into Convert Snippet / Batch / Options with context-sensitive visibility
|
||||||
- Reduce module video pane min sizes to allow GNOME snapping
|
- Reduce module video pane min sizes to allow GNOME snapping
|
||||||
- Cache/temp directory setting with SSD recommendation
|
- Cache/temp directory setting with SSD recommendation
|
||||||
|
- Frame interpolation presets in Filters with Upscale linkage
|
||||||
|
|
||||||
*Last Updated: 2025-12-20*
|
*Last Updated: 2025-12-20*
|
||||||
|
|
||||||
|
|
|
||||||
82
main.go
82
main.go
|
|
@ -801,6 +801,9 @@ type appState struct {
|
||||||
filterFlipV bool
|
filterFlipV bool
|
||||||
filterGrayscale bool
|
filterGrayscale bool
|
||||||
filterActiveChain []string // Active filter chain
|
filterActiveChain []string // Active filter chain
|
||||||
|
filterInterpEnabled bool
|
||||||
|
filterInterpPreset string
|
||||||
|
filterInterpFPS string
|
||||||
|
|
||||||
// Upscale module state
|
// Upscale module state
|
||||||
upscaleFile *videoSource
|
upscaleFile *videoSource
|
||||||
|
|
@ -12563,6 +12566,37 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
||||||
state.filterSharpness = 0.0 // 0.0 to 5.0
|
state.filterSharpness = 0.0 // 0.0 to 5.0
|
||||||
state.filterDenoise = 0.0 // 0.0 to 10.0
|
state.filterDenoise = 0.0 // 0.0 to 10.0
|
||||||
}
|
}
|
||||||
|
if state.filterInterpPreset == "" {
|
||||||
|
state.filterInterpPreset = "Balanced"
|
||||||
|
}
|
||||||
|
if state.filterInterpFPS == "" {
|
||||||
|
state.filterInterpFPS = "60"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFilterChain := func() {
|
||||||
|
var chain []string
|
||||||
|
if state.filterInterpEnabled {
|
||||||
|
fps := state.filterInterpFPS
|
||||||
|
if fps == "" {
|
||||||
|
fps = "60"
|
||||||
|
}
|
||||||
|
var filter string
|
||||||
|
switch state.filterInterpPreset {
|
||||||
|
case "Ultra Fast":
|
||||||
|
filter = fmt.Sprintf("minterpolate=fps=%s:mi_mode=blend", fps)
|
||||||
|
case "Fast":
|
||||||
|
filter = fmt.Sprintf("minterpolate=fps=%s:mi_mode=duplicate", fps)
|
||||||
|
case "High Quality":
|
||||||
|
filter = fmt.Sprintf("minterpolate=fps=%s:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1:search_param=32", fps)
|
||||||
|
case "Maximum Quality":
|
||||||
|
filter = fmt.Sprintf("minterpolate=fps=%s:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1:search_param=64", fps)
|
||||||
|
default: // Balanced
|
||||||
|
filter = fmt.Sprintf("minterpolate=fps=%s:mi_mode=mci:mc_mode=obmc:me_mode=bidir:me=epzs:search_param=16:vsbmc=0", fps)
|
||||||
|
}
|
||||||
|
chain = append(chain, filter)
|
||||||
|
}
|
||||||
|
state.filterActiveChain = chain
|
||||||
|
}
|
||||||
|
|
||||||
// File label
|
// File label
|
||||||
fileLabel := widget.NewLabel("No file loaded")
|
fileLabel := widget.NewLabel("No file loaded")
|
||||||
|
|
@ -12607,8 +12641,8 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
||||||
upscaleNavBtn := widget.NewButton("Send to Upscale →", func() {
|
upscaleNavBtn := widget.NewButton("Send to Upscale →", func() {
|
||||||
if state.filtersFile != nil {
|
if state.filtersFile != nil {
|
||||||
state.upscaleFile = state.filtersFile
|
state.upscaleFile = state.filtersFile
|
||||||
// TODO: Transfer active filter chain to upscale
|
buildFilterChain()
|
||||||
// state.upscaleFilterChain = state.filterActiveChain
|
state.upscaleFilterChain = append([]string{}, state.filterActiveChain...)
|
||||||
}
|
}
|
||||||
state.showUpscaleView()
|
state.showUpscaleView()
|
||||||
})
|
})
|
||||||
|
|
@ -12656,14 +12690,50 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
||||||
widget.NewCheck("Grayscale", func(b bool) { state.filterGrayscale = b }),
|
widget.NewCheck("Grayscale", func(b bool) { state.filterGrayscale = b }),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// Frame Interpolation Section
|
||||||
|
interpEnabledCheck := widget.NewCheck("Enable Frame Interpolation", func(checked bool) {
|
||||||
|
state.filterInterpEnabled = checked
|
||||||
|
buildFilterChain()
|
||||||
|
})
|
||||||
|
interpEnabledCheck.SetChecked(state.filterInterpEnabled)
|
||||||
|
|
||||||
|
interpPresetSelect := widget.NewSelect([]string{"Ultra Fast", "Fast", "Balanced", "High Quality", "Maximum Quality"}, func(val string) {
|
||||||
|
state.filterInterpPreset = val
|
||||||
|
buildFilterChain()
|
||||||
|
})
|
||||||
|
interpPresetSelect.SetSelected(state.filterInterpPreset)
|
||||||
|
|
||||||
|
interpFPSSelect := widget.NewSelect([]string{"24", "30", "50", "59.94", "60"}, func(val string) {
|
||||||
|
state.filterInterpFPS = val
|
||||||
|
buildFilterChain()
|
||||||
|
})
|
||||||
|
interpFPSSelect.SetSelected(state.filterInterpFPS)
|
||||||
|
|
||||||
|
interpHint := widget.NewLabel("Balanced preset is recommended; higher presets are CPU-intensive.")
|
||||||
|
interpHint.TextStyle = fyne.TextStyle{Italic: true}
|
||||||
|
interpHint.Wrapping = fyne.TextWrapWord
|
||||||
|
|
||||||
|
interpSection := widget.NewCard("Frame Interpolation (Minterpolate)", "", container.NewVBox(
|
||||||
|
widget.NewLabel("Generate smoother motion by interpolating new frames"),
|
||||||
|
interpEnabledCheck,
|
||||||
|
container.NewGridWithColumns(2,
|
||||||
|
widget.NewLabel("Preset:"),
|
||||||
|
interpPresetSelect,
|
||||||
|
widget.NewLabel("Target FPS:"),
|
||||||
|
interpFPSSelect,
|
||||||
|
),
|
||||||
|
interpHint,
|
||||||
|
))
|
||||||
|
buildFilterChain()
|
||||||
|
|
||||||
// Apply button
|
// Apply button
|
||||||
applyBtn := widget.NewButton("Apply Filters", func() {
|
applyBtn := widget.NewButton("Apply Filters", func() {
|
||||||
if state.filtersFile == nil {
|
if state.filtersFile == nil {
|
||||||
dialog.ShowInformation("No Video", "Please load a video first.", state.window)
|
dialog.ShowInformation("No Video", "Please load a video first.", state.window)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: Implement filter application
|
buildFilterChain()
|
||||||
dialog.ShowInformation("Coming Soon", "Filter application will be implemented soon.", state.window)
|
dialog.ShowInformation("Filters", "Filters are now configured and will be applied when sent to Upscale.", state.window)
|
||||||
})
|
})
|
||||||
applyBtn.Importance = widget.HighImportance
|
applyBtn.Importance = widget.HighImportance
|
||||||
|
|
||||||
|
|
@ -12680,6 +12750,7 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
||||||
colorSection,
|
colorSection,
|
||||||
enhanceSection,
|
enhanceSection,
|
||||||
transformSection,
|
transformSection,
|
||||||
|
interpSection,
|
||||||
creativeSection,
|
creativeSection,
|
||||||
applyBtn,
|
applyBtn,
|
||||||
)
|
)
|
||||||
|
|
@ -12743,6 +12814,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
if !state.upscaleAIAvailable {
|
if !state.upscaleAIAvailable {
|
||||||
state.upscaleAIAvailable = checkAIUpscaleAvailable()
|
state.upscaleAIAvailable = checkAIUpscaleAvailable()
|
||||||
}
|
}
|
||||||
|
if len(state.filterActiveChain) > 0 {
|
||||||
|
state.upscaleFilterChain = append([]string{}, state.filterActiveChain...)
|
||||||
|
}
|
||||||
|
|
||||||
// File label
|
// File label
|
||||||
fileLabel := widget.NewLabel("No file loaded")
|
fileLabel := widget.NewLabel("No file loaded")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user