PR #23672 opened by Wangnov
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23672
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23672.patch

WebM VP8/VP9 streams can carry an alpha channel as a second bitstream attached 
via a Matroska BlockAdditional element with BlockAddID 1 (the WebM Alpha 
extension). Only the libvpx-wrapped decoders know how to decode and merge this 
side stream (see libvpxdec.c); the native vp8 and vp9 decoders have no code 
path for it and silently produce a fully opaque frame instead, with no 
diagnostic of any kind.

This is easy to run into and hard to debug: users see a black/opaque background 
from files that decode correctly with alpha in browsers, with no indication 
that anything went wrong. Trac ticket https://trac.ffmpeg.org/ticket/11165 
reports the same symptom, and an independent downstream project hit and 
eventually gave up debugging the exact same issue: 
https://github.com/renpy/renpy/issues/1402

Detect this decoder-side, generically in ff_decode_frame_props() (VP8/VP9 codec 
IDs only, gated on the id==1 alpha BlockAdditional discriminator that 
lavf/libvpx already use), and emit a one-time warning pointing at the decoder 
that actually supports it. This does not add alpha decoding support to the 
native decoders themselves; that would require a second full bitstream decode 
pass merged into a different internal frame-buffer architecture, which is out 
of scope here. It only turns an existing silent failure into a diagnosable one.

## Testing

- `./configure --disable-everything --enable-libvpx 
--enable-decoder=vp8,vp9,libvpx_vp8,libvpx_vp9 
--enable-demuxer=matroska,rawvideo ...` and `make` build cleanly; `decode.c` 
recompiles with zero warnings.
- `tools/check_commit_msg.sh` on this commit message: OK.
- Functional test against a real yuva420p VP8/VP9-in-WebM file (chromakeyed, 
encoded with `-c:v libvpx-vp9 -pix_fmt yuva420p`):
  - Default decoder selection (native `vp9`): warning fires exactly once for 
the whole stream, pointing at `-c:v libvpx`/`libvpx-vp9`.
  - Forced `-c:v libvpx-vp9` on the same file: no warning (alpha is correctly 
decoded and merged, `AV_PIX_FMT_FLAG_ALPHA` is set).
  - A plain VP9 WebM with no alpha side data: no warning (no false positive).

Signed-off-by: wangnov <[email protected]>


>From 03d70d206c6d614a093814c100e97974e2e7f2ec Mon Sep 17 00:00:00 2001
From: wangnov <[email protected]>
Date: Wed, 1 Jul 2026 15:10:00 +0800
Subject: [PATCH] avcodec/decode: warn when native VP8/VP9 decoders drop WebM
 alpha data

WebM VP8/VP9 streams can carry an alpha channel as a second bitstream
attached via a Matroska BlockAdditional element with BlockAddID 1 (the
WebM Alpha extension). Only the libvpx-wrapped decoders know how to
decode and merge this side stream (see libvpxdec.c); the native vp8
and vp9 decoders have no code path for it and silently produce a fully
opaque frame instead, with no diagnostic of any kind.

This is easy to run into and hard to debug: users see a black/opaque
background from files that decode correctly with alpha in browsers,
with no indication that anything went wrong. Trac ticket 
https://trac.ffmpeg.org/ticket/11165
reports the same symptom, and an independent downstream project hit
and eventually gave up debugging the exact same issue:
https://github.com/renpy/renpy/issues/1402

Detect this decoder-side, generically in ff_decode_frame_props()
(VP8/VP9 codec IDs only, gated on the id==1 alpha BlockAdditional
discriminator that lavf/libvpx already use), and emit a one-time
warning pointing at the decoder that actually supports it. This does
not add alpha decoding support to the native decoders themselves;
that would require a second full bitstream decode pass merged into a
different internal frame-buffer architecture, which is out of scope
here. It only turns an existing silent failure into a diagnosable one.

Signed-off-by: wangnov <[email protected]>
---
 libavcodec/decode.c | 51 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 6f85e5f514..e440cd4e33 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -96,6 +96,13 @@ typedef struct DecodeContext {
      */
     uint64_t side_data_pref_mask;
 
+    /**
+     * State for av_log_once(): whether we have already warned that this
+     * decoder is dropping Matroska/WebM alpha channel (BlockAdditional)
+     * side data it does not know how to merge into the output frame.
+     */
+    int webm_alpha_side_data_warned;
+
 #if CONFIG_LIBLCEVC_DEC
     struct {
         FFLCEVCContext *ctx;
@@ -175,6 +182,48 @@ fail2:
     return 0;
 }
 
+/**
+ * VP8/VP9-in-Matroska/WebM can carry an alpha channel as a second,
+ * independently encoded bitstream attached to each block via a Matroska
+ * BlockAdditional element with BlockAddID 1 (see the WebM Alpha extension).
+ * lavf exposes it to decoders as AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL side
+ * data (an 8-byte big-endian BlockAddID header followed by the payload).
+ *
+ * Only the libvpx-wrapped decoders (libvpxdec.c) know how to decode and
+ * merge this side stream into a yuva420p AVFrame; the native vp8/vp9
+ * decoders have no code path for it at all and will silently produce a
+ * fully opaque frame. Warn once so users are not left debugging a "black
+ * background" with no diagnostic, and point them at the decoder that
+ * actually supports it.
+ */
+static void check_webm_alpha_side_data(AVCodecContext *avctx, const AVPacket 
*pkt)
+{
+    DecodeContext *dc = decode_ctx(avctx->internal);
+    const AVPixFmtDescriptor *desc;
+    const uint8_t *sd;
+    size_t sd_size;
+
+    if (avctx->codec_id != AV_CODEC_ID_VP8 && avctx->codec_id != 
AV_CODEC_ID_VP9)
+        return;
+
+    sd = av_packet_get_side_data(pkt, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, 
&sd_size);
+    if (!sd || sd_size < 8 || AV_RB64(sd) != 1)
+        return;
+
+    desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+    if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA))
+        return;
+
+    av_log_once(avctx, AV_LOG_WARNING, AV_LOG_DEBUG,
+                &dc->webm_alpha_side_data_warned,
+                "Stream contains WebM alpha channel data (Matroska "
+                "BlockAdditional) that decoder '%s' does not support; the "
+                "alpha channel will be dropped and the output will be fully "
+                "opaque. Use the libvpx/libvpx-vp9 decoder wrapper "
+                "(-c:v libvpx or -c:v libvpx-vp9) to decode it correctly.\n",
+                avctx->codec->name);
+}
+
 static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt)
 {
     int ret = 0;
@@ -1613,6 +1662,8 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame 
*frame)
         ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt);
         if (ret < 0)
             return ret;
+
+        check_webm_alpha_side_data(avctx, pkt);
     }
 
     ret = fill_frame_props(avctx, frame);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to