Add upscale quality preset to prevent runaway bitrates

This commit is contained in:
Stu Leak 2025-12-21 16:09:01 -05:00
parent 93ec8c7b15
commit 1d18ab2db2
2 changed files with 38 additions and 4 deletions

View File

@ -49,7 +49,7 @@ The Upscale module raises video resolution using traditional FFmpeg scaling or A
## Traditional Scaling
- **Algorithms:** Lanczos, Bicubic, Spline, Bilinear.
- **Target:** Match Source, 2x/4x, or fixed resolutions (720p → 8K).
- **Output:** Lossless MKV by default (copy audio).
- **Output Quality:** Lossless (CRF 0), Near-lossless (CRF 16, default), High (CRF 18).
## Filters and Frame Rate
- Filters configured in the Filters module can be applied before upscaling.

40
main.go
View File

@ -824,6 +824,7 @@ type appState struct {
upscaleTargetRes string // 720p, 1080p, 1440p, 4K, 8K, Custom
upscaleCustomWidth int // For custom resolution
upscaleCustomHeight int // For custom resolution
upscaleQualityPreset string // Lossless, Near-lossless, High
upscaleAIEnabled bool // Use AI upscaling if available
upscaleAIModel string // realesrgan, realesrgan-anime, none
upscaleAIAvailable bool // Runtime detection
@ -4482,6 +4483,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
frameRate, _ := cfg["frameRate"].(string)
useMotionInterp, _ := cfg["useMotionInterpolation"].(bool)
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
qualityPreset, _ := cfg["qualityPreset"].(string)
if progressCallback != nil {
progressCallback(0)
@ -4502,6 +4504,16 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
}
}
crfValue := 16
switch qualityPreset {
case "Lossless (CRF 0)":
crfValue = 0
case "High (CRF 18)":
crfValue = 18
case "Near-lossless (CRF 16)":
crfValue = 16
}
// Build filter chain
var baseFilters []string
@ -4749,7 +4761,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
reassembleArgs = append(reassembleArgs,
"-c:v", "libx264",
"-preset", "slow",
"-crf", "0",
"-crf", strconv.Itoa(crfValue),
"-pix_fmt", "yuv420p",
"-c:a", "copy",
"-shortest",
@ -4808,7 +4820,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
args = append(args,
"-c:v", "libx264",
"-preset", "slow",
"-crf", "0", // lossless
"-crf", strconv.Itoa(crfValue),
"-pix_fmt", "yuv420p",
"-c:a", "copy",
outputPath,
@ -13152,7 +13164,7 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
settingsScroll.SetMinSize(fyne.NewSize(350, 400))
mainContent := container.NewHSplit(
container.NewVBox(leftPanel, videoContainer),
container.NewVBox(leftPanel, container.NewCenter(videoContainer)),
settingsScroll,
)
mainContent.SetOffset(0.55) // 55% for video preview, 45% for settings
@ -13201,6 +13213,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
if state.upscaleFrameRate == "" {
state.upscaleFrameRate = "Source"
}
if state.upscaleQualityPreset == "" {
state.upscaleQualityPreset = "Near-lossless (CRF 16)"
}
if state.upscaleAIPreset == "" {
state.upscaleAIPreset = "Balanced"
state.upscaleAIScale = 4.0
@ -13332,6 +13347,23 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
sourceResLabel,
))
qualitySelect := widget.NewSelect([]string{
"Lossless (CRF 0)",
"Near-lossless (CRF 16)",
"High (CRF 18)",
}, func(s string) {
state.upscaleQualityPreset = s
})
qualitySelect.SetSelected(state.upscaleQualityPreset)
qualitySection := widget.NewCard("Output Quality", "", container.NewVBox(
container.NewGridWithColumns(2,
widget.NewLabel("Quality:"),
qualitySelect,
),
widget.NewLabel("Lower CRF = higher quality/larger files"),
))
// 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) {
@ -13682,6 +13714,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
"preserveAR": preserveAspect,
"useAI": state.upscaleAIEnabled && state.upscaleAIAvailable,
"aiModel": state.upscaleAIModel,
"qualityPreset": state.upscaleQualityPreset,
"aiBackend": state.upscaleAIBackend,
"aiPreset": state.upscaleAIPreset,
"aiScale": state.upscaleAIScale,
@ -13751,6 +13784,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
settingsPanel := container.NewVBox(
traditionalSection,
resolutionSection,
qualitySection,
frameRateSection,
aiSection,
filterIntegrationSection,