Fix log viewer crash and improve bitrate controls

- Fix panic when closing log viewer (duplicate channel close)
- Improve CBR: Set bufsize to 2x bitrate for better encoder handling
- Improve VBR: Increase maxrate cap from 1.5x to 2x target bitrate
- Add bufsize to VBR at 4x target (2x maxrate) to enforce caps
- Update VBR hint to reflect 2x peak cap and 2-pass encoding

This eliminates runaway bitrates while maintaining quality peaks.
This commit is contained in:
Stu Leak 2025-12-18 10:30:55 -05:00
parent 0ebd442479
commit 3511d598f4

68
main.go
View File

@ -349,15 +349,18 @@ func (s *appState) openLogViewer(title, path string, live bool) {
}()
}
var d dialog.Dialog
closeBtn := widget.NewButton("Close", func() {
close(stop)
if d != nil {
d.Hide()
}
})
copyBtn := widget.NewButton("Copy All", func() {
s.window.Clipboard().SetContent(text.Text)
})
buttons := container.NewHBox(copyBtn, layout.NewSpacer(), closeBtn)
content := container.NewBorder(nil, buttons, nil, nil, scroll)
d := dialog.NewCustom(title, "Close", content, s.window)
d = dialog.NewCustom(title, "Close", content, s.window)
d.SetOnClosed(func() { close(stop) })
d.Show()
}
@ -863,17 +866,6 @@ Config:
detailsLabel := widget.NewLabel(details)
detailsLabel.Wrapping = fyne.TextWrapWord
// FFmpeg Command section
var ffmpegSection fyne.CanvasObject
if entry.FFmpegCmd != "" {
cmdWidget := ui.NewFFmpegCommandWidget(entry.FFmpegCmd, s.window)
ffmpegSection = container.NewVBox(
widget.NewSeparator(),
widget.NewLabel("FFmpeg Command:"),
cmdWidget,
)
}
// Buttons
var buttons []fyne.CanvasObject
@ -899,23 +891,36 @@ Config:
closeBtn := widget.NewButton("Close", nil)
buttons = append(buttons, layout.NewSpacer(), closeBtn)
// Layout
contentVBox := container.NewVBox(
container.NewVScroll(detailsLabel),
)
if ffmpegSection != nil {
contentVBox.Add(ffmpegSection)
// Job details in scrollable area
detailsScroll := container.NewVScroll(detailsLabel)
detailsScroll.SetMinSize(fyne.NewSize(650, 250))
// FFmpeg Command section at bottom
var ffmpegSection fyne.CanvasObject
if entry.FFmpegCmd != "" {
cmdWidget := ui.NewFFmpegCommandWidget(entry.FFmpegCmd, s.window)
cmdLabel := widget.NewLabel("FFmpeg Command:")
cmdLabel.TextStyle = fyne.TextStyle{Bold: true}
ffmpegSection = container.NewVBox(
widget.NewSeparator(),
cmdLabel,
cmdWidget,
)
}
// Layout: details at top (scrollable), FFmpeg at bottom (fixed)
content := container.NewBorder(
nil,
container.NewHBox(buttons...),
detailsScroll, // Top: job details (scrollable, takes priority)
container.NewVBox( // Bottom: FFmpeg command (fixed)
ffmpegSection,
container.NewHBox(buttons...),
),
nil, nil,
contentVBox,
nil, // No center content - top and bottom fill the space
)
d := dialog.NewCustom("Job Details", "Close", content, s.window)
d.Resize(fyne.NewSize(700, 600))
d.Resize(fyne.NewSize(750, 650))
closeBtn.OnTapped = func() { d.Hide() }
d.Show()
}
@ -5951,7 +5956,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
crfContainer.Hide()
bitrateContainer.Show()
targetSizeContainer.Hide()
hint = "VBR mode: Variable bitrate - targets average bitrate. More efficient than CBR. Use 2-pass for accuracy."
hint = "VBR mode: Variable bitrate - targets average bitrate with 2x peak cap. Efficient quality. Uses 2-pass encoding."
case "Target Size":
// Show only target size controls
crfContainer.Hide()
@ -9398,7 +9403,13 @@ func (s *appState) startConvert(status *widget.Label, btn, cancelBtn *widget.But
if vb == "" {
vb = defaultBitrate(cfg.VideoCodec, src.Width, sourceBitrate)
}
args = append(args, "-b:v", vb, "-minrate", vb, "-maxrate", vb, "-bufsize", vb)
// Set bufsize to 2x target for better encoder handling
bitrateVal, err := utils.ParseInt(strings.TrimSuffix(vb, "k"))
bufsize := vb
if err == nil {
bufsize = fmt.Sprintf("%dk", bitrateVal*2)
}
args = append(args, "-b:v", vb, "-minrate", vb, "-maxrate", vb, "-bufsize", bufsize)
} else if cfg.BitrateMode == "VBR" {
// Variable bitrate - use 2-pass for accuracy
vb := cfg.VideoBitrate
@ -9406,11 +9417,12 @@ func (s *appState) startConvert(status *widget.Label, btn, cancelBtn *widget.But
vb = defaultBitrate(cfg.VideoCodec, src.Width, sourceBitrate)
}
args = append(args, "-b:v", vb)
// VBR uses maxrate at ~1.5x target for quality peaks
// VBR uses maxrate at 2x target for quality peaks, bufsize at 2x maxrate to enforce cap
bitrateVal, err := utils.ParseInt(strings.TrimSuffix(vb, "k"))
if err == nil {
maxBitrate := fmt.Sprintf("%dk", int(float64(bitrateVal)*1.5))
args = append(args, "-maxrate", maxBitrate)
maxBitrate := fmt.Sprintf("%dk", bitrateVal*2)
bufsize := fmt.Sprintf("%dk", bitrateVal*4)
args = append(args, "-maxrate", maxBitrate, "-bufsize", bufsize)
}
// Force 2-pass for VBR accuracy
if !cfg.TwoPass {