[PR] avcodec/decode: warn when native VP8/VP9 decoders drop WebM alpha data (PR #23672)

Wangnov via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178289999503.59.16517278632329028962@29965ddac10e>
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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.