fix: skip no-op zscale and round SAR width to nearest even

Bug #2: calculateZscaleWidth previously emitted a zscale filter even
when no rescale was needed (SAR 1:1, N/A, empty, or computed width
equal to the source). encodeVideo then unconditionally appended it to
-vf, forcing a pointless colorspace round-trip. Return an empty filter
string in those cases and build the -vf chain conditionally; omit -vf
entirely when no filters apply.

Bug #23: the SAR-to-width math used integer truncation, producing odd
or off-by-one widths (e.g. 853 instead of 854 for 32:27 at 1920), and
the guard accepted SAR 0:N which zeroed the output width. Reject
zero-numerator SARs and round to the nearest integer then mask to an
even width for AV1/H.264 mod-2 alignment.
This commit is contained in:
Esa Kataja
2026-05-16 20:07:50 +03:00
parent 5584bbca57
commit 71f7ef7bca
+25 -10
View File
@@ -195,16 +195,26 @@ func (e *Encoder) calculateZscaleWidth(path string, originalHeight int) (string,
newWidth := width
if sar != "1:1" && sar != "N/A" && sar != "" {
if sar == "1:1" || sar == "N/A" || sar == "" {
return "", newWidth, nil
}
parts := strings.Split(sar, ":")
if len(parts) == 2 {
if len(parts) != 2 {
return "", newWidth, nil
}
num, err1 := strconv.Atoi(parts[0])
den, err2 := strconv.Atoi(parts[1])
if err1 == nil && err2 == nil && den != 0 {
newWidth = (width * num) / den
if err1 != nil || err2 != nil || num == 0 || den == 0 {
return "", newWidth, nil
}
// Round to nearest, then snap down to even (mod-2 widths preferred by AV1/H.264).
newWidth = ((width*num + den/2) / den) &^ 1
fmt.Printf("DEBUG calculated new width: %d (sar=%s)\n", newWidth, sar)
}
}
if newWidth == width {
return "", newWidth, nil
}
zscale := fmt.Sprintf("zscale=w=%d:h=%d:filter=spline36", newWidth, height)
@@ -270,12 +280,15 @@ func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job,
fmt.Printf("DEBUG zscale: %s (newWidth=%d)\n", zscaleStr, newWidth)
vf := zscaleStr
var filters []string
if interlaced {
vf = "bwdif=mode=0:par=-1:-1," + vf
filters = append(filters, "bwdif=mode=0:par=-1:-1")
}
if zscaleStr != "" {
filters = append(filters, zscaleStr)
}
fmt.Printf("DEBUG final vf: %s\n", vf)
fmt.Printf("DEBUG final vf: %s\n", strings.Join(filters, ","))
args := []string{
"-y",
@@ -286,7 +299,9 @@ func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job,
args = append(args, "-i", opus)
}
args = append(args, "-vf", vf)
if len(filters) > 0 {
args = append(args, "-vf", strings.Join(filters, ","))
}
args = append(args, "-c:v", "libsvtav1")
args = append(args, "-crf", strconv.Itoa(job.CRF))
args = append(args, "-preset", strconv.Itoa(job.Preset))