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]
