Skip to content

render: fix WebM overlay alpha and ffmpeg 8 subtitles filter syntax#102

Open
wdeynes wants to merge 1 commit into
browser-use:mainfrom
wdeynes:fix/webm-alpha-ass-subtitles
Open

render: fix WebM overlay alpha and ffmpeg 8 subtitles filter syntax#102
wdeynes wants to merge 1 commit into
browser-use:mainfrom
wdeynes:fix/webm-alpha-ass-subtitles

Conversation

@wdeynes

@wdeynes wdeynes commented Jul 4, 2026

Copy link
Copy Markdown

Two small rendering bugfixes in helpers/render.py, independent of each other and of #62:

1. WebM overlay transparency is lost (composites as opaque black).
ffmpeg's built-in vp9 decoder ignores the alpha side-channel in WebM/VP9, so any transparent overlay rendered to .webm composites as a solid black box. Fix: pass -c:v libvpx-vp9 for .webm overlay inputs so the alpha plane is actually decoded.

2. Subtitle burns fail to parse on ffmpeg 8.
ffmpeg 8's filtergraph parser rejects the positional quoted form subtitles='/abs/path' whenever the path needs quoting; the render dies with a filter parse error. Fix: use the filename= named-option syntax, which works on ffmpeg 5–8. While here: .ass inputs now skip force_style — ASS files carry their own embedded styles, and force_style was clobbering them.

Both found in production use editing 4K talking-head videos with transparent motion-graphic overlays and burned captions on ffmpeg 8.1/macOS.

🤖 Generated with Claude Code


Summary by cubic

Fixes two rendering issues: transparent .webm overlays now keep alpha, and subtitle burns work on ffmpeg 8 while preserving .ass styles.

  • Bug Fixes
    • WebM overlays: force -c:v libvpx-vp9 for .webm overlay inputs so the alpha channel is decoded.
    • Subtitles: use subtitles=filename='...' to avoid ffmpeg 8 parse errors; skip force_style for .ass to keep embedded styles.

Written for commit 532446e. Summary will update on new commits.

Review in cubic

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 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="helpers/render.py">

<violation number="1" location="helpers/render.py:521">
P2: Forcing the `libvpx-vp9` decoder on every `.webm` overlay based only on file extension introduces a codec-compatibility regression. WebM is a container that can hold VP8 as well as VP9, and `libvpx-vp9` is registered in FFmpeg exclusively for VP9 (`AV_CODEC_ID_VP9`)—it cannot decode VP8 streams. If a `.webm` overlay happens to contain VP8 (or another codec), ffmpeg will fail to open the input and abort compositing. Previously ffmpeg auto-selected the correct decoder, so this change narrows acceptable inputs and could break existing workflows. Consider probing the actual codec (e.g., via `ffprobe`) before selecting the decoder, or constraining the forced decoder to files verified as VP9.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread helpers/render.py
Comment on lines +521 to +522
if ov_path.suffix.lower() == ".webm":
inputs += ["-c:v", "libvpx-vp9"]

@cubic-dev-ai cubic-dev-ai Bot Jul 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Forcing the libvpx-vp9 decoder on every .webm overlay based only on file extension introduces a codec-compatibility regression. WebM is a container that can hold VP8 as well as VP9, and libvpx-vp9 is registered in FFmpeg exclusively for VP9 (AV_CODEC_ID_VP9)—it cannot decode VP8 streams. If a .webm overlay happens to contain VP8 (or another codec), ffmpeg will fail to open the input and abort compositing. Previously ffmpeg auto-selected the correct decoder, so this change narrows acceptable inputs and could break existing workflows. Consider probing the actual codec (e.g., via ffprobe) before selecting the decoder, or constraining the forced decoder to files verified as VP9.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At helpers/render.py, line 521:

<comment>Forcing the `libvpx-vp9` decoder on every `.webm` overlay based only on file extension introduces a codec-compatibility regression. WebM is a container that can hold VP8 as well as VP9, and `libvpx-vp9` is registered in FFmpeg exclusively for VP9 (`AV_CODEC_ID_VP9`)—it cannot decode VP8 streams. If a `.webm` overlay happens to contain VP8 (or another codec), ffmpeg will fail to open the input and abort compositing. Previously ffmpeg auto-selected the correct decoder, so this change narrows acceptable inputs and could break existing workflows. Consider probing the actual codec (e.g., via `ffprobe`) before selecting the decoder, or constraining the forced decoder to files verified as VP9.</comment>

<file context>
@@ -515,6 +515,11 @@ def build_final_composite(
+        # 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)]
</file context>
Suggested change
if ov_path.suffix.lower() == ".webm":
inputs += ["-c:v", "libvpx-vp9"]
if ov_path.suffix.lower() == ".webm":
# Probe to ensure we only force libvpx-vp9 for actual VP9 streams.
probe = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=codec_name", "-of",
"default=noprint_wrappers=1:nokey=1", str(ov_path)],
capture_output=True, text=True,
)
if probe.returncode == 0 and probe.stdout.strip() == "vp9":
inputs += ["-c:v", "libvpx-vp9"]
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant