From 532446e8a0f829b21f988200147bb35897d19e9b Mon Sep 17 00:00:00 2001 From: wdeynes Date: Sat, 4 Jul 2026 12:50:48 -0500 Subject: [PATCH] render: fix WebM overlay alpha and ffmpeg 8 subtitles filter syntax Two rendering bugfixes: 1. WebM/VP9 overlay transparency: ffmpeg's built-in vp9 decoder ignores the alpha side-channel, so transparent WebM overlays composite as opaque black boxes. Select libvpx-vp9 explicitly for .webm overlay inputs. 2. Subtitles filter on ffmpeg 8: the filtergraph parser rejects the positional quoted form (subtitles='/path...') when the path needs quoting - burns fail with a parse error. Use the filename= named-option syntax. Also skip force_style for .ass inputs, which carry their own embedded styles that force_style would clobber. Co-Authored-By: Claude Fable 5 --- helpers/render.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/helpers/render.py b/helpers/render.py index 0d02cffa..fbdfa0a3 100644 --- a/helpers/render.py +++ b/helpers/render.py @@ -515,6 +515,11 @@ def build_final_composite( inputs: list[str] = ["-i", str(base_path)] for ov in overlays: ov_path = resolve_path(ov["file"], edit_dir) + # WebM/VP9 alpha lives in a side-channel that ffmpeg's native vp9 + # decoder ignores; force libvpx-vp9 so transparent overlays stay + # transparent instead of compositing as opaque black. + if ov_path.suffix.lower() == ".webm": + inputs += ["-c:v", "libvpx-vp9"] inputs += ["-i", str(ov_path)] filter_parts: list[str] = [] @@ -538,9 +543,15 @@ def build_final_composite( # Subtitles LAST — Rule 1 if has_subs: subs_abs = str(subtitles_path.resolve()).replace(":", r"\:").replace("'", r"\'") - filter_parts.append( - f"{current}subtitles='{subs_abs}':force_style='{SUB_FORCE_STYLE}'[outv]" - ) + # filename= (named option) is required: ffmpeg 8's filtergraph parser + # rejects the positional quoted form when the path needs quoting. + if subtitles_path.suffix.lower() == ".ass": + # ASS files carry their own styles — force_style would clobber them. + filter_parts.append(f"{current}subtitles=filename='{subs_abs}'[outv]") + else: + filter_parts.append( + f"{current}subtitles=filename='{subs_abs}':force_style='{SUB_FORCE_STYLE}'[outv]" + ) out_label = "[outv]" else: # Rename the last overlay output to [outv] for consistency