feat(upscale): add blur control

This commit is contained in:
Stu Leak 2026-01-06 17:01:06 -05:00
parent 3ba3deab8b
commit 895c696b88
3 changed files with 80 additions and 2 deletions

View File

@ -93,12 +93,12 @@ None currently open.
## 🧭 Feature Requests (Planned)
### FEAT-003: Enhancement module blur control
- **Status**: 🧭 PLANNED
- **Status**: 🧭 IN PROGRESS
- **Reporter**: Jake (2026-01-06)
- **Module**: Enhancement
- **Description**: Enhancement panel should include a blur control in addition to sharpen/denoise.
- **Impact**: Medium - expected control in enhancement workflow
- **Notes**: Add to enhancement UI alongside existing sliders.
- **Notes**: Implemented blur controls in Upscale first; Enhancement UI still pending.
### FEAT-004: Upscale output quality should use Bitrate Mode controls
- **Status**: 🧭 PLANNED

34
internal/state/manager.go Normal file
View File

@ -0,0 +1,34 @@
package state
import (
"fyne.io/fyne/v2/widget"
"sync"
)
type StateManager struct {
mu sync.RWMutex
// Current mode settings
crfMode CRFMode
vbrMode VBRMode
currentQuality string
currentBitrate string
currentCRFValue int64
currentVBRValue int64
// Registered widgets for synchronization
qualityWidgets []*widget.Select
bitrateWidgets []*widget.Select
}
type CRFMode string
type VBRMode string
const (
CRFManual CRFMode = "manual"
CRFQuality CRFMode = "quality"
CRFBitrate CRFMode = "bitrate"
VBRStandard VBRMode = "standard"
VBRHQ VBRMode = "hq"
VBRConstrained VBRMode = "constrained"
)

44
main.go
View File

@ -1096,6 +1096,8 @@ type appState struct {
upscaleFilterChain []string // Transferred filters from Filters module
upscaleFrameRate string // Source, 24, 30, 60, or custom
upscaleMotionInterpolation bool // Use motion interpolation for frame rate changes
upscaleBlurEnabled bool // Apply blur in upscale pipeline
upscaleBlurSigma float64 // Blur strength (sigma)
// Snippet settings
snippetLength int // Length of snippet in seconds (default: 20)
@ -5556,6 +5558,8 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
useMotionInterp, _ := cfg["useMotionInterpolation"].(bool)
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
qualityPreset, _ := cfg["qualityPreset"].(string)
blurEnabled, _ := cfg["blurEnabled"].(bool)
blurSigma := toFloat(cfg["blurSigma"])
if progressCallback != nil {
progressCallback(0)
@ -5613,6 +5617,10 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
}
}
if blurEnabled && blurSigma > 0 {
baseFilters = append(baseFilters, fmt.Sprintf("gblur=sigma=%.2f", blurSigma))
}
if useAI {
if aiBackend != "ncnn" {
return fmt.Errorf("AI upscaling backend not available")
@ -14934,6 +14942,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
state.upscaleAIThreadsProc = 2
state.upscaleAIThreadsSave = 2
}
if state.upscaleBlurSigma <= 0 {
state.upscaleBlurSigma = 1.5
}
// Check AI availability on first load
if state.upscaleAIBackend == "" {
@ -15069,6 +15080,36 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
widget.NewLabel("Lower CRF = higher quality/larger files"),
))
blurLabel := widget.NewLabel(fmt.Sprintf("Blur Strength: %.2f", state.upscaleBlurSigma))
blurSlider := widget.NewSlider(0.0, 8.0)
blurSlider.Step = 0.1
blurSlider.Value = state.upscaleBlurSigma
blurSlider.OnChanged = func(v float64) {
state.upscaleBlurSigma = v
blurLabel.SetText(fmt.Sprintf("Blur Strength: %.2f", v))
}
blurCheck := widget.NewCheck("Enable Blur", func(checked bool) {
state.upscaleBlurEnabled = checked
if checked {
blurSlider.Enable()
} else {
blurSlider.Disable()
}
})
blurCheck.SetChecked(state.upscaleBlurEnabled)
if state.upscaleBlurEnabled {
blurSlider.Enable()
} else {
blurSlider.Disable()
}
blurSection := widget.NewCard("Blur (Optional)", "", container.NewVBox(
widget.NewLabel("Apply a soft blur during upscale processing"),
blurCheck,
container.NewVBox(blurLabel, blurSlider),
))
// Frame Rate Section
frameRateLabel := widget.NewLabel(fmt.Sprintf("Frame Rate: %s", state.upscaleFrameRate))
frameRateSelect := widget.NewSelect([]string{"Source", "23.976", "24", "25", "29.97", "30", "50", "59.94", "60"}, func(s string) {
@ -15437,6 +15478,8 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
"aiOutputFormat": state.upscaleAIOutputFormat,
"applyFilters": state.upscaleApplyFilters,
"filterChain": state.upscaleFilterChain,
"blurEnabled": state.upscaleBlurEnabled,
"blurSigma": state.upscaleBlurSigma,
"duration": state.upscaleFile.Duration,
"sourceFrameRate": state.upscaleFile.FrameRate,
"frameRate": state.upscaleFrameRate,
@ -15490,6 +15533,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
traditionalSection,
resolutionSection,
qualitySection,
blurSection,
frameRateSection,
aiSection,
filterIntegrationSection,