From 07f999a3388d30cb2424d9778c947098f77871f2 Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Sat, 16 May 2026 19:39:33 +0300 Subject: [PATCH] fix: correct interlace detection and reap idet child MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous detector substring-matched "TFF"/"BFF" against idet's own label text, so it returned true on every source, and `cmd.Start()` was never paired with `Wait()`, leaving a zombie ffmpeg per file. Run idet bounded with `-frames:v 400 -an -sn -f null -` so it completes, use CombinedOutput so the child is reaped, and parse the "Multi frame detection" summary line — interlaced only when TFF+BFF > Progressive. --- internal/encoder/encoder.go | 42 ++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 7b8ff61..685b8f5 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -6,12 +6,15 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" "strings" "videnc-vibe/pkg/types" ) +var idetSummaryRegex = regexp.MustCompile(`Multi frame detection:\s+TFF:\s*(\d+)\s+BFF:\s*(\d+)\s+Progressive:\s*(\d+)\s+Undetermined:\s*(\d+)`) + type Encoder struct { ffmpegPath string ffprobePath string @@ -122,20 +125,43 @@ func (e *Encoder) GetMediaInfo(path string) (width, height int, interlaced bool, } } - cmd = exec.Command(e.ffmpegPath, "-i", path, "-hide_banner", "-vf", "idet") - stderr, _ := cmd.StderrPipe() - cmd.Start() - buf := make([]byte, 16384) - n, _ := stderr.Read(buf) - stderr.Close() - outputStr := string(buf[:n]) - interlaced = strings.Contains(outputStr, "TFF") || strings.Contains(outputStr, "BFF") + cmd = exec.Command(e.ffmpegPath, + "-hide_banner", + "-nostats", + "-i", path, + "-vf", "idet", + "-frames:v", "400", + "-an", "-sn", + "-f", "null", "-", + ) + idetOut, _ := cmd.CombinedOutput() + interlaced = detectInterlaced(string(idetOut)) fmt.Printf("DEBUG interlaced: %v\n", interlaced) return width, height, interlaced, nil } +// detectInterlaced parses ffmpeg idet's "Multi frame detection" summary line +// and returns true when TFF+BFF clearly outnumber Progressive frames among +// the decided frames. Undetermined frames are ignored. If the summary line +// is missing, returns false (default to progressive). +func detectInterlaced(idetOutput string) bool { + m := idetSummaryRegex.FindStringSubmatch(idetOutput) + if m == nil { + return false + } + tff, _ := strconv.Atoi(m[1]) + bff, _ := strconv.Atoi(m[2]) + prog, _ := strconv.Atoi(m[3]) + interlaced := tff + bff + decided := interlaced + prog + if decided == 0 { + return false + } + return interlaced > prog +} + func (e *Encoder) calculateZscaleWidth(path string, originalHeight int) (string, int, error) { cmd := exec.Command(e.ffprobePath, "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height,sample_aspect_ratio", "-print_format", "json", path) output, err := cmd.CombinedOutput()