feat(upscale): add blur control
This commit is contained in:
parent
f166680040
commit
3bc9a4137e
4
BUGS.md
4
BUGS.md
|
|
@ -93,12 +93,12 @@ None currently open.
|
||||||
## 🧭 Feature Requests (Planned)
|
## 🧭 Feature Requests (Planned)
|
||||||
|
|
||||||
### FEAT-003: Enhancement module blur control
|
### FEAT-003: Enhancement module blur control
|
||||||
- **Status**: 🧭 PLANNED
|
- **Status**: 🧭 IN PROGRESS
|
||||||
- **Reporter**: Jake (2026-01-06)
|
- **Reporter**: Jake (2026-01-06)
|
||||||
- **Module**: Enhancement
|
- **Module**: Enhancement
|
||||||
- **Description**: Enhancement panel should include a blur control in addition to sharpen/denoise.
|
- **Description**: Enhancement panel should include a blur control in addition to sharpen/denoise.
|
||||||
- **Impact**: Medium - expected control in enhancement workflow
|
- **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
|
### FEAT-004: Upscale output quality should use Bitrate Mode controls
|
||||||
- **Status**: 🧭 PLANNED
|
- **Status**: 🧭 PLANNED
|
||||||
|
|
|
||||||
34
internal/state/manager.go
Normal file
34
internal/state/manager.go
Normal 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
44
main.go
|
|
@ -1096,6 +1096,8 @@ type appState struct {
|
||||||
upscaleFilterChain []string // Transferred filters from Filters module
|
upscaleFilterChain []string // Transferred filters from Filters module
|
||||||
upscaleFrameRate string // Source, 24, 30, 60, or custom
|
upscaleFrameRate string // Source, 24, 30, 60, or custom
|
||||||
upscaleMotionInterpolation bool // Use motion interpolation for frame rate changes
|
upscaleMotionInterpolation bool // Use motion interpolation for frame rate changes
|
||||||
|
upscaleBlurEnabled bool // Apply blur in upscale pipeline
|
||||||
|
upscaleBlurSigma float64 // Blur strength (sigma)
|
||||||
|
|
||||||
// Snippet settings
|
// Snippet settings
|
||||||
snippetLength int // Length of snippet in seconds (default: 20)
|
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)
|
useMotionInterp, _ := cfg["useMotionInterpolation"].(bool)
|
||||||
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
|
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
|
||||||
qualityPreset, _ := cfg["qualityPreset"].(string)
|
qualityPreset, _ := cfg["qualityPreset"].(string)
|
||||||
|
blurEnabled, _ := cfg["blurEnabled"].(bool)
|
||||||
|
blurSigma := toFloat(cfg["blurSigma"])
|
||||||
|
|
||||||
if progressCallback != nil {
|
if progressCallback != nil {
|
||||||
progressCallback(0)
|
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 useAI {
|
||||||
if aiBackend != "ncnn" {
|
if aiBackend != "ncnn" {
|
||||||
return fmt.Errorf("AI upscaling backend not available")
|
return fmt.Errorf("AI upscaling backend not available")
|
||||||
|
|
@ -14934,6 +14942,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
state.upscaleAIThreadsProc = 2
|
state.upscaleAIThreadsProc = 2
|
||||||
state.upscaleAIThreadsSave = 2
|
state.upscaleAIThreadsSave = 2
|
||||||
}
|
}
|
||||||
|
if state.upscaleBlurSigma <= 0 {
|
||||||
|
state.upscaleBlurSigma = 1.5
|
||||||
|
}
|
||||||
|
|
||||||
// Check AI availability on first load
|
// Check AI availability on first load
|
||||||
if state.upscaleAIBackend == "" {
|
if state.upscaleAIBackend == "" {
|
||||||
|
|
@ -15069,6 +15080,36 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
widget.NewLabel("Lower CRF = higher quality/larger files"),
|
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
|
// Frame Rate Section
|
||||||
frameRateLabel := widget.NewLabel(fmt.Sprintf("Frame Rate: %s", state.upscaleFrameRate))
|
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) {
|
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,
|
"aiOutputFormat": state.upscaleAIOutputFormat,
|
||||||
"applyFilters": state.upscaleApplyFilters,
|
"applyFilters": state.upscaleApplyFilters,
|
||||||
"filterChain": state.upscaleFilterChain,
|
"filterChain": state.upscaleFilterChain,
|
||||||
|
"blurEnabled": state.upscaleBlurEnabled,
|
||||||
|
"blurSigma": state.upscaleBlurSigma,
|
||||||
"duration": state.upscaleFile.Duration,
|
"duration": state.upscaleFile.Duration,
|
||||||
"sourceFrameRate": state.upscaleFile.FrameRate,
|
"sourceFrameRate": state.upscaleFile.FrameRate,
|
||||||
"frameRate": state.upscaleFrameRate,
|
"frameRate": state.upscaleFrameRate,
|
||||||
|
|
@ -15490,6 +15533,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
traditionalSection,
|
traditionalSection,
|
||||||
resolutionSection,
|
resolutionSection,
|
||||||
qualitySection,
|
qualitySection,
|
||||||
|
blurSection,
|
||||||
frameRateSection,
|
frameRateSection,
|
||||||
aiSection,
|
aiSection,
|
||||||
filterIntegrationSection,
|
filterIntegrationSection,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user