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:
+29
-14
@@ -195,16 +195,26 @@ func (e *Encoder) calculateZscaleWidth(path string, originalHeight int) (string,
|
|||||||
|
|
||||||
newWidth := width
|
newWidth := width
|
||||||
|
|
||||||
if sar != "1:1" && sar != "N/A" && sar != "" {
|
if sar == "1:1" || sar == "N/A" || sar == "" {
|
||||||
parts := strings.Split(sar, ":")
|
return "", newWidth, nil
|
||||||
if len(parts) == 2 {
|
}
|
||||||
num, err1 := strconv.Atoi(parts[0])
|
|
||||||
den, err2 := strconv.Atoi(parts[1])
|
parts := strings.Split(sar, ":")
|
||||||
if err1 == nil && err2 == nil && den != 0 {
|
if len(parts) != 2 {
|
||||||
newWidth = (width * num) / den
|
return "", newWidth, nil
|
||||||
fmt.Printf("DEBUG calculated new width: %d (sar=%s)\n", newWidth, sar)
|
}
|
||||||
}
|
num, err1 := strconv.Atoi(parts[0])
|
||||||
}
|
den, err2 := strconv.Atoi(parts[1])
|
||||||
|
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)
|
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)
|
fmt.Printf("DEBUG zscale: %s (newWidth=%d)\n", zscaleStr, newWidth)
|
||||||
|
|
||||||
vf := zscaleStr
|
var filters []string
|
||||||
if interlaced {
|
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{
|
args := []string{
|
||||||
"-y",
|
"-y",
|
||||||
@@ -286,7 +299,9 @@ func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job,
|
|||||||
args = append(args, "-i", opus)
|
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, "-c:v", "libsvtav1")
|
||||||
args = append(args, "-crf", strconv.Itoa(job.CRF))
|
args = append(args, "-crf", strconv.Itoa(job.CRF))
|
||||||
args = append(args, "-preset", strconv.Itoa(job.Preset))
|
args = append(args, "-preset", strconv.Itoa(job.Preset))
|
||||||
|
|||||||
Reference in New Issue
Block a user