Replace CRF preset with manual quality option
This commit is contained in:
parent
bca6e6f4c3
commit
4dcc96c6e1
114
main.go
114
main.go
|
|
@ -6839,6 +6839,24 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
}
|
}
|
||||||
uiState.quality = val
|
uiState.quality = val
|
||||||
state.convert.Quality = val
|
state.convert.Quality = val
|
||||||
|
if val == manualQualityOption {
|
||||||
|
if strings.TrimSpace(state.convert.CRF) == "" {
|
||||||
|
state.convert.CRF = "23"
|
||||||
|
if crfEntry != nil {
|
||||||
|
crfEntry.SetText("23")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if state.convert.CRF != "" {
|
||||||
|
state.convert.CRF = ""
|
||||||
|
}
|
||||||
|
if crfEntry != nil && crfEntry.Text != "" {
|
||||||
|
crfEntry.SetText("")
|
||||||
|
}
|
||||||
|
if manualCrfRow != nil {
|
||||||
|
manualCrfRow.Hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update all registered widgets silently (no callback loops)
|
// Update all registered widgets silently (no callback loops)
|
||||||
for _, w := range uiState.qualityWidgets {
|
for _, w := range uiState.qualityWidgets {
|
||||||
|
|
@ -7099,7 +7117,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
var (
|
var (
|
||||||
bitrateModeSelect *widget.Select
|
bitrateModeSelect *widget.Select
|
||||||
bitratePresetSelect *widget.Select
|
bitratePresetSelect *widget.Select
|
||||||
crfPresetSelect *widget.Select
|
|
||||||
crfEntry *widget.Entry
|
crfEntry *widget.Entry
|
||||||
manualCrfRow *fyne.Container
|
manualCrfRow *fyne.Container
|
||||||
videoBitrateEntry *widget.Entry
|
videoBitrateEntry *widget.Entry
|
||||||
|
|
@ -7128,7 +7145,8 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
updateQualityOptions func() // Update quality dropdown based on codec
|
updateQualityOptions func() // Update quality dropdown based on codec
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base quality options (without lossless)
|
manualQualityOption := "Manual (CRF)"
|
||||||
|
// Base quality options (without lossless or manual)
|
||||||
baseQualityOptions := []string{
|
baseQualityOptions := []string{
|
||||||
"Draft (CRF 28)",
|
"Draft (CRF 28)",
|
||||||
"Standard (CRF 23)",
|
"Standard (CRF 23)",
|
||||||
|
|
@ -7143,10 +7161,11 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current quality options (dynamic based on codec)
|
// Current quality options (dynamic based on codec)
|
||||||
qualityOptions := baseQualityOptions
|
qualityOptions := append([]string{}, baseQualityOptions...)
|
||||||
if codecSupportsLossless(state.convert.VideoCodec) {
|
if codecSupportsLossless(state.convert.VideoCodec) {
|
||||||
qualityOptions = append(qualityOptions, "Lossless")
|
qualityOptions = append(qualityOptions, "Lossless")
|
||||||
}
|
}
|
||||||
|
qualityOptions = append(qualityOptions, manualQualityOption)
|
||||||
|
|
||||||
// Quality select widgets - use state manager to eliminate sync flags
|
// Quality select widgets - use state manager to eliminate sync flags
|
||||||
// Convert quality selects to ColoredSelect and register with state manager
|
// Convert quality selects to ColoredSelect and register with state manager
|
||||||
|
|
@ -7182,15 +7201,17 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
var newOptions []string
|
var newOptions []string
|
||||||
if codecSupportsLossless(state.convert.VideoCodec) {
|
if codecSupportsLossless(state.convert.VideoCodec) {
|
||||||
// H.265 and AV1 support lossless
|
// H.265 and AV1 support lossless
|
||||||
newOptions = append(baseQualityOptions, "Lossless")
|
newOptions = append([]string{}, baseQualityOptions...)
|
||||||
|
newOptions = append(newOptions, "Lossless")
|
||||||
} else {
|
} else {
|
||||||
// H.264, MPEG-2, etc. don't support lossless
|
// H.264, MPEG-2, etc. don't support lossless
|
||||||
newOptions = baseQualityOptions
|
newOptions = append([]string{}, baseQualityOptions...)
|
||||||
// If currently set to Lossless, fall back to Near-Lossless
|
// If currently set to Lossless, fall back to Near-Lossless
|
||||||
if state.convert.Quality == "Lossless" {
|
if state.convert.Quality == "Lossless" {
|
||||||
state.convert.Quality = "Near-Lossless (CRF 16)"
|
state.convert.Quality = "Near-Lossless (CRF 16)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
newOptions = append(newOptions, manualQualityOption)
|
||||||
|
|
||||||
// Update options and color map for all registered quality widgets
|
// Update options and color map for all registered quality widgets
|
||||||
qualityColorMap := ui.BuildQualityColorMap(newOptions)
|
qualityColorMap := ui.BuildQualityColorMap(newOptions)
|
||||||
|
|
@ -7826,62 +7847,13 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
widget.NewLabelWithStyle("Manual CRF (overrides Quality preset)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
widget.NewLabelWithStyle("Manual CRF (overrides Quality preset)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
crfEntry,
|
crfEntry,
|
||||||
)
|
)
|
||||||
manualCrfRow.Hide()
|
if state.convert.Quality == manualQualityOption {
|
||||||
|
if strings.TrimSpace(state.convert.CRF) == "" {
|
||||||
crfPresetOptions := []string{
|
|
||||||
"Auto (from Quality preset)",
|
|
||||||
"18 (High)",
|
|
||||||
"20 (Balanced)",
|
|
||||||
"23 (Standard)",
|
|
||||||
"28 (Draft)",
|
|
||||||
"Manual",
|
|
||||||
}
|
|
||||||
crfPresetSelect = widget.NewSelect(crfPresetOptions, func(value string) {
|
|
||||||
switch value {
|
|
||||||
case "Auto (from Quality preset)":
|
|
||||||
state.convert.CRF = ""
|
|
||||||
crfEntry.SetText("")
|
|
||||||
manualCrfRow.Hide()
|
|
||||||
case "18 (High)":
|
|
||||||
state.convert.CRF = "18"
|
|
||||||
crfEntry.SetText("18")
|
|
||||||
manualCrfRow.Hide()
|
|
||||||
case "20 (Balanced)":
|
|
||||||
state.convert.CRF = "20"
|
|
||||||
crfEntry.SetText("20")
|
|
||||||
manualCrfRow.Hide()
|
|
||||||
case "23 (Standard)":
|
|
||||||
state.convert.CRF = "23"
|
state.convert.CRF = "23"
|
||||||
crfEntry.SetText("23")
|
crfEntry.SetText("23")
|
||||||
manualCrfRow.Hide()
|
|
||||||
case "28 (Draft)":
|
|
||||||
state.convert.CRF = "28"
|
|
||||||
crfEntry.SetText("28")
|
|
||||||
manualCrfRow.Hide()
|
|
||||||
case "Manual":
|
|
||||||
manualCrfRow.Show()
|
|
||||||
}
|
}
|
||||||
if updateQualityVisibility != nil {
|
} else {
|
||||||
updateQualityVisibility()
|
manualCrfRow.Hide()
|
||||||
}
|
|
||||||
if buildCommandPreview != nil {
|
|
||||||
buildCommandPreview()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
switch state.convert.CRF {
|
|
||||||
case "":
|
|
||||||
crfPresetSelect.SetSelected("Auto (from Quality preset)")
|
|
||||||
case "18":
|
|
||||||
crfPresetSelect.SetSelected("18 (High)")
|
|
||||||
case "20":
|
|
||||||
crfPresetSelect.SetSelected("20 (Balanced)")
|
|
||||||
case "23":
|
|
||||||
crfPresetSelect.SetSelected("23 (Standard)")
|
|
||||||
case "28":
|
|
||||||
crfPresetSelect.SetSelected("28 (Draft)")
|
|
||||||
default:
|
|
||||||
crfPresetSelect.SetSelected("Manual")
|
|
||||||
manualCrfRow.Show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video Bitrate entry (for CBR/VBR) with validation
|
// Video Bitrate entry (for CBR/VBR) with validation
|
||||||
|
|
@ -8038,12 +8010,8 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
setManualBitrate(state.convert.VideoBitrate)
|
setManualBitrate(state.convert.VideoBitrate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create CRF container (crfEntry already initialized)
|
// Create CRF container (manual entry shown when quality is Manual)
|
||||||
crfContainer = container.NewVBox(
|
crfContainer = container.NewVBox(manualCrfRow)
|
||||||
widget.NewLabelWithStyle("CRF Preset", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
|
||||||
crfPresetSelect,
|
|
||||||
manualCrfRow,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Note: bitrateContainer creation moved below after bitratePresetSelect is initialized
|
// Note: bitrateContainer creation moved below after bitratePresetSelect is initialized
|
||||||
|
|
||||||
|
|
@ -8405,6 +8373,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
showCRF := mode == "CRF" || mode == ""
|
showCRF := mode == "CRF" || mode == ""
|
||||||
showBitrate := mode == "CBR" || mode == "VBR"
|
showBitrate := mode == "CBR" || mode == "VBR"
|
||||||
showTarget := mode == "Target Size"
|
showTarget := mode == "Target Size"
|
||||||
|
showManualCRF := strings.EqualFold(state.convert.Quality, manualQualityOption)
|
||||||
|
|
||||||
if isLossless && supportsLossless {
|
if isLossless && supportsLossless {
|
||||||
// Lossless with H.265/AV1: Allow all bitrate modes
|
// Lossless with H.265/AV1: Allow all bitrate modes
|
||||||
|
|
@ -8416,12 +8385,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
}
|
}
|
||||||
state.convert.CRF = "0"
|
state.convert.CRF = "0"
|
||||||
crfEntry.Disable()
|
crfEntry.Disable()
|
||||||
if crfPresetSelect != nil {
|
|
||||||
crfPresetSelect.SetSelected("Manual")
|
|
||||||
}
|
|
||||||
if manualCrfRow != nil {
|
|
||||||
manualCrfRow.Show()
|
|
||||||
}
|
|
||||||
hint = "Lossless mode with CRF 0. Perfect quality preservation for H.265/AV1."
|
hint = "Lossless mode with CRF 0. Perfect quality preservation for H.265/AV1."
|
||||||
case "CBR":
|
case "CBR":
|
||||||
hint = "Lossless quality with constant bitrate. May achieve smaller file size than pure lossless CRF."
|
hint = "Lossless quality with constant bitrate. May achieve smaller file size than pure lossless CRF."
|
||||||
|
|
@ -8448,7 +8411,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if showCRF {
|
if showCRF && showManualCRF {
|
||||||
crfContainer.Show()
|
crfContainer.Show()
|
||||||
} else {
|
} else {
|
||||||
crfContainer.Hide()
|
crfContainer.Hide()
|
||||||
|
|
@ -8788,12 +8751,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
hide := strings.Contains(strings.ToLower(state.convert.SelectedFormat.Label), "h.265") ||
|
hide := strings.Contains(strings.ToLower(state.convert.SelectedFormat.Label), "h.265") ||
|
||||||
strings.EqualFold(state.convert.VideoCodec, "H.265")
|
strings.EqualFold(state.convert.VideoCodec, "H.265")
|
||||||
hideQuality := state.convert.BitrateMode != "" && state.convert.BitrateMode != "CRF"
|
hideQuality := state.convert.BitrateMode != "" && state.convert.BitrateMode != "CRF"
|
||||||
if !hideQuality && strings.EqualFold(state.convert.BitrateMode, "CRF") && strings.TrimSpace(state.convert.CRF) != "" {
|
|
||||||
hideQuality = true
|
|
||||||
}
|
|
||||||
if !hideQuality && crfPresetSelect != nil && crfPresetSelect.Selected != "Auto (from Quality preset)" {
|
|
||||||
hideQuality = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if qualitySectionSimple != nil {
|
if qualitySectionSimple != nil {
|
||||||
if hide || hideQuality {
|
if hide || hideQuality {
|
||||||
|
|
@ -9075,9 +9032,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
bitratePresetSelect.SetSelected(state.convert.BitratePreset)
|
bitratePresetSelect.SetSelected(state.convert.BitratePreset)
|
||||||
simpleBitrateSelect.SetSelected(state.convert.BitratePreset)
|
simpleBitrateSelect.SetSelected(state.convert.BitratePreset)
|
||||||
crfEntry.SetText(state.convert.CRF)
|
crfEntry.SetText(state.convert.CRF)
|
||||||
if crfPresetSelect != nil {
|
|
||||||
crfPresetSelect.SetSelected("Auto (from Quality preset)")
|
|
||||||
}
|
|
||||||
if manualCrfRow != nil {
|
if manualCrfRow != nil {
|
||||||
manualCrfRow.Hide()
|
manualCrfRow.Hide()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user