Fix CRF UI sync and stabilize player
This commit is contained in:
parent
6ad6e8ef54
commit
57f2076f9f
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/utils"
|
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
|
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
|
||||||
|
"git.leaktechnologies.dev/stu/VideoTools/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnifiedPlayer implements rock-solid video playback with proper A/V synchronization
|
// UnifiedPlayer implements rock-solid video playback with proper A/V synchronization
|
||||||
|
|
@ -555,7 +555,6 @@ func (p *UnifiedPlayer) detectVideoProperties() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if p.frameRate > 0 && p.duration > 0 {
|
if p.frameRate > 0 && p.duration > 0 {
|
||||||
p.videoInfo = &VideoInfo{
|
p.videoInfo = &VideoInfo{
|
||||||
Width: p.windowW,
|
Width: p.windowW,
|
||||||
|
|
@ -589,13 +588,18 @@ func (p *UnifiedPlayer) writeStringToStdin(cmd string) {
|
||||||
|
|
||||||
// updateAVSync maintains synchronization between audio and video
|
// updateAVSync maintains synchronization between audio and video
|
||||||
func (p *UnifiedPlayer) updateAVSync() {
|
func (p *UnifiedPlayer) updateAVSync() {
|
||||||
// Simple drift correction using master clock reference
|
// PTS-based drift correction with adaptive timing
|
||||||
|
p.mu.RLock()
|
||||||
|
defer p.mu.RUnlock()
|
||||||
|
|
||||||
if p.audioPTS > 0 && p.videoPTS > 0 {
|
if p.audioPTS > 0 && p.videoPTS > 0 {
|
||||||
drift := p.audioPTS - p.videoPTS
|
drift := p.audioPTS - p.videoPTS
|
||||||
if abs(drift) > 1000 { // More than 1 frame of drift
|
if abs(drift) > 900 { // More than 10ms of drift (at 90kHz)
|
||||||
|
logging.Debug(logging.CatPlayer, "A/V sync drift: %d PTS", drift)
|
||||||
|
// Gradual adjustment to avoid audio glitches
|
||||||
|
p.ptsOffset += drift / 10 // 10% correction per frame
|
||||||
|
} else {
|
||||||
logging.Debug(logging.CatPlayer, "A/V sync drift: %d PTS", drift)
|
logging.Debug(logging.CatPlayer, "A/V sync drift: %d PTS", drift)
|
||||||
// Adjust sync clock gradually
|
|
||||||
p.ptsOffset += drift / 100
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ var (
|
||||||
// Audio Codec Colors (Secondary but Distinct)
|
// Audio Codec Colors (Secondary but Distinct)
|
||||||
var (
|
var (
|
||||||
ColorOpus = utils.MustHex("#8B5CF6") // Violet - Modern audio
|
ColorOpus = utils.MustHex("#8B5CF6") // Violet - Modern audio
|
||||||
ColorAAC = utils.MustHex("#7C3AED") // Purple-Blue - Common audio
|
ColorAAC = utils.MustHex("#06B6D4") // Cyan - Common audio (distinct from purple codecs)
|
||||||
ColorFLAC = utils.MustHex("#EC4899") // Magenta - Lossless audio
|
ColorFLAC = utils.MustHex("#EC4899") // Magenta - Lossless audio
|
||||||
ColorMP3 = utils.MustHex("#F43F5E") // Rose - Legacy audio
|
ColorMP3 = utils.MustHex("#F43F5E") // Rose - Legacy audio
|
||||||
ColorAC3 = utils.MustHex("#F97316") // Orange-Red - Surround audio
|
ColorAC3 = utils.MustHex("#F97316") // Orange-Red - Surround audio
|
||||||
|
|
|
||||||
34
main.go
34
main.go
|
|
@ -6883,6 +6883,22 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
manualQualityOption := "Manual (CRF)"
|
manualQualityOption := "Manual (CRF)"
|
||||||
var crfEntry *widget.Entry
|
var crfEntry *widget.Entry
|
||||||
var manualCrfRow *fyne.Container
|
var manualCrfRow *fyne.Container
|
||||||
|
var crfContainer *fyne.Container
|
||||||
|
|
||||||
|
normalizeBitrateMode := func(mode string) string {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(mode, "CRF"):
|
||||||
|
return "CRF"
|
||||||
|
case strings.HasPrefix(mode, "CBR"):
|
||||||
|
return "CBR"
|
||||||
|
case strings.HasPrefix(mode, "VBR"):
|
||||||
|
return "VBR"
|
||||||
|
case strings.HasPrefix(mode, "Target Size"):
|
||||||
|
return "Target Size"
|
||||||
|
default:
|
||||||
|
return mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// State setters with automatic widget synchronization
|
// State setters with automatic widget synchronization
|
||||||
setQuality := func(val string) {
|
setQuality := func(val string) {
|
||||||
|
|
@ -6898,6 +6914,17 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
crfEntry.SetText("23")
|
crfEntry.SetText("23")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if normalizeBitrateMode(state.convert.BitrateMode) == "CRF" {
|
||||||
|
if manualCrfRow != nil {
|
||||||
|
manualCrfRow.Show()
|
||||||
|
}
|
||||||
|
if crfEntry != nil {
|
||||||
|
crfEntry.Enable()
|
||||||
|
}
|
||||||
|
if crfContainer != nil {
|
||||||
|
crfContainer.Show()
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if state.convert.CRF != "" {
|
if state.convert.CRF != "" {
|
||||||
state.convert.CRF = ""
|
state.convert.CRF = ""
|
||||||
|
|
@ -7214,7 +7241,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
qualitySectionSimple fyne.CanvasObject
|
qualitySectionSimple fyne.CanvasObject
|
||||||
qualitySectionAdv fyne.CanvasObject
|
qualitySectionAdv fyne.CanvasObject
|
||||||
simpleBitrateSelect *widget.Select
|
simpleBitrateSelect *widget.Select
|
||||||
crfContainer *fyne.Container
|
|
||||||
bitrateContainer *fyne.Container
|
bitrateContainer *fyne.Container
|
||||||
targetSizeContainer *fyne.Container
|
targetSizeContainer *fyne.Container
|
||||||
resetConvertDefaults func()
|
resetConvertDefaults func()
|
||||||
|
|
@ -7913,12 +7939,6 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
"VBR": "VBR (Variable Bitrate)",
|
"VBR": "VBR (Variable Bitrate)",
|
||||||
"Target Size": "Target Size (Calculate from file size)",
|
"Target Size": "Target Size (Calculate from file size)",
|
||||||
}
|
}
|
||||||
normalizeBitrateMode := func(mode string) string {
|
|
||||||
if shortCode, ok := bitrateModeMap[mode]; ok {
|
|
||||||
return shortCode
|
|
||||||
}
|
|
||||||
return mode
|
|
||||||
}
|
|
||||||
bitrateModeSelect = widget.NewSelect(bitrateModeOptions, func(value string) {
|
bitrateModeSelect = widget.NewSelect(bitrateModeOptions, func(value string) {
|
||||||
// Extract short code from label
|
// Extract short code from label
|
||||||
if shortCode, ok := bitrateModeMap[value]; ok {
|
if shortCode, ok := bitrateModeMap[value]; ok {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user