Add upscale quality preset to prevent runaway bitrates
This commit is contained in:
parent
93ec8c7b15
commit
1d18ab2db2
|
|
@ -49,7 +49,7 @@ The Upscale module raises video resolution using traditional FFmpeg scaling or A
|
||||||
## Traditional Scaling
|
## Traditional Scaling
|
||||||
- **Algorithms:** Lanczos, Bicubic, Spline, Bilinear.
|
- **Algorithms:** Lanczos, Bicubic, Spline, Bilinear.
|
||||||
- **Target:** Match Source, 2x/4x, or fixed resolutions (720p → 8K).
|
- **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 and Frame Rate
|
||||||
- Filters configured in the Filters module can be applied before upscaling.
|
- Filters configured in the Filters module can be applied before upscaling.
|
||||||
|
|
|
||||||
40
main.go
40
main.go
|
|
@ -824,6 +824,7 @@ type appState struct {
|
||||||
upscaleTargetRes string // 720p, 1080p, 1440p, 4K, 8K, Custom
|
upscaleTargetRes string // 720p, 1080p, 1440p, 4K, 8K, Custom
|
||||||
upscaleCustomWidth int // For custom resolution
|
upscaleCustomWidth int // For custom resolution
|
||||||
upscaleCustomHeight int // For custom resolution
|
upscaleCustomHeight int // For custom resolution
|
||||||
|
upscaleQualityPreset string // Lossless, Near-lossless, High
|
||||||
upscaleAIEnabled bool // Use AI upscaling if available
|
upscaleAIEnabled bool // Use AI upscaling if available
|
||||||
upscaleAIModel string // realesrgan, realesrgan-anime, none
|
upscaleAIModel string // realesrgan, realesrgan-anime, none
|
||||||
upscaleAIAvailable bool // Runtime detection
|
upscaleAIAvailable bool // Runtime detection
|
||||||
|
|
@ -4482,6 +4483,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
|
||||||
frameRate, _ := cfg["frameRate"].(string)
|
frameRate, _ := cfg["frameRate"].(string)
|
||||||
useMotionInterp, _ := cfg["useMotionInterpolation"].(bool)
|
useMotionInterp, _ := cfg["useMotionInterpolation"].(bool)
|
||||||
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
|
sourceFrameRate := toFloat(cfg["sourceFrameRate"])
|
||||||
|
qualityPreset, _ := cfg["qualityPreset"].(string)
|
||||||
|
|
||||||
if progressCallback != nil {
|
if progressCallback != nil {
|
||||||
progressCallback(0)
|
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
|
// Build filter chain
|
||||||
var baseFilters []string
|
var baseFilters []string
|
||||||
|
|
||||||
|
|
@ -4749,7 +4761,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
|
||||||
reassembleArgs = append(reassembleArgs,
|
reassembleArgs = append(reassembleArgs,
|
||||||
"-c:v", "libx264",
|
"-c:v", "libx264",
|
||||||
"-preset", "slow",
|
"-preset", "slow",
|
||||||
"-crf", "0",
|
"-crf", strconv.Itoa(crfValue),
|
||||||
"-pix_fmt", "yuv420p",
|
"-pix_fmt", "yuv420p",
|
||||||
"-c:a", "copy",
|
"-c:a", "copy",
|
||||||
"-shortest",
|
"-shortest",
|
||||||
|
|
@ -4808,7 +4820,7 @@ func (s *appState) executeUpscaleJob(ctx context.Context, job *queue.Job, progre
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-c:v", "libx264",
|
"-c:v", "libx264",
|
||||||
"-preset", "slow",
|
"-preset", "slow",
|
||||||
"-crf", "0", // lossless
|
"-crf", strconv.Itoa(crfValue),
|
||||||
"-pix_fmt", "yuv420p",
|
"-pix_fmt", "yuv420p",
|
||||||
"-c:a", "copy",
|
"-c:a", "copy",
|
||||||
outputPath,
|
outputPath,
|
||||||
|
|
@ -13152,7 +13164,7 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
||||||
settingsScroll.SetMinSize(fyne.NewSize(350, 400))
|
settingsScroll.SetMinSize(fyne.NewSize(350, 400))
|
||||||
|
|
||||||
mainContent := container.NewHSplit(
|
mainContent := container.NewHSplit(
|
||||||
container.NewVBox(leftPanel, videoContainer),
|
container.NewVBox(leftPanel, container.NewCenter(videoContainer)),
|
||||||
settingsScroll,
|
settingsScroll,
|
||||||
)
|
)
|
||||||
mainContent.SetOffset(0.55) // 55% for video preview, 45% for settings
|
mainContent.SetOffset(0.55) // 55% for video preview, 45% for settings
|
||||||
|
|
@ -13201,6 +13213,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
if state.upscaleFrameRate == "" {
|
if state.upscaleFrameRate == "" {
|
||||||
state.upscaleFrameRate = "Source"
|
state.upscaleFrameRate = "Source"
|
||||||
}
|
}
|
||||||
|
if state.upscaleQualityPreset == "" {
|
||||||
|
state.upscaleQualityPreset = "Near-lossless (CRF 16)"
|
||||||
|
}
|
||||||
if state.upscaleAIPreset == "" {
|
if state.upscaleAIPreset == "" {
|
||||||
state.upscaleAIPreset = "Balanced"
|
state.upscaleAIPreset = "Balanced"
|
||||||
state.upscaleAIScale = 4.0
|
state.upscaleAIScale = 4.0
|
||||||
|
|
@ -13332,6 +13347,23 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
sourceResLabel,
|
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
|
// 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) {
|
||||||
|
|
@ -13682,6 +13714,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
"preserveAR": preserveAspect,
|
"preserveAR": preserveAspect,
|
||||||
"useAI": state.upscaleAIEnabled && state.upscaleAIAvailable,
|
"useAI": state.upscaleAIEnabled && state.upscaleAIAvailable,
|
||||||
"aiModel": state.upscaleAIModel,
|
"aiModel": state.upscaleAIModel,
|
||||||
|
"qualityPreset": state.upscaleQualityPreset,
|
||||||
"aiBackend": state.upscaleAIBackend,
|
"aiBackend": state.upscaleAIBackend,
|
||||||
"aiPreset": state.upscaleAIPreset,
|
"aiPreset": state.upscaleAIPreset,
|
||||||
"aiScale": state.upscaleAIScale,
|
"aiScale": state.upscaleAIScale,
|
||||||
|
|
@ -13751,6 +13784,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
||||||
settingsPanel := container.NewVBox(
|
settingsPanel := container.NewVBox(
|
||||||
traditionalSection,
|
traditionalSection,
|
||||||
resolutionSection,
|
resolutionSection,
|
||||||
|
qualitySection,
|
||||||
frameRateSection,
|
frameRateSection,
|
||||||
aiSection,
|
aiSection,
|
||||||
filterIntegrationSection,
|
filterIntegrationSection,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user