PR #23212 opened by skidder URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23212 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23212.patch
## What this fixes Chromium calls `avcodec_flush_buffers()` on every `<video>` seek, and on the implicit seek-to-zero that the `<video loop>` attribute performs at EOF. Without a `.flush` callback registered, the libopenh264 wrapper passes the flush through to nothing — Cisco's `ISVCDecoder` keeps its DPB and reference frames from the prior GOP. The next IDR is accepted but subsequent P-frames reference the now-stale state and fail. In Chromium's media pipeline this surfaces as `Failed to send video packet for decoding` from `media/filters/ffmpeg_video_decoder.cc` and a frozen `<video>` element on the second loop iteration. Linux desktop builds where libopenh264 is the only H.264 decode path are affected; macOS/Windows take other paths. ## Approaches tried 1. `FlushFrame()` alone — drains output buffers but leaves reference state intact. Bug persists. 2. `FlushFrame()` + clearing `DECODER_OPTION_END_OF_STREAM` — same. The EOS flag isn't the corrupt state. 3. Destroy + recreate via `svc_decode_close` + `svc_decode_init` — reliable. Cisco's public API exposes no non-destructive reset, so this is the only correct option. Flush is a rare event (per seek / per loop boundary), so the overhead is negligible. The `s->decoder = NULL` line added to `svc_decode_close` is defensive hardening so any future caller running close → init twice (which the new flush does) can't double-free. ## Testing - `make` builds clean on macOS arm64 and Linux x86_64. - `make fate SAMPLES=~/fate-suite` passes (no regressions vs. master). - Manual repro: standalone ## Reproducer Reproducer artifacts for reviewers: - `repro_flush.c` — standalone C program. Models Chromium's `<video loop>` pipeline: decode all packets, `avcodec_flush_buffers()`, decode the same packets again, compare frame counts. - `input_bf.h264` — 90-frame raw Annex-B stream with B-frames (`-bf 3 -profile:v high`). B-frames are required to trigger the bug; reordering is what causes Cisco's DPB to retain stale references across the flush. Build and run: ``` clang -O2 -o repro_flush repro_flush.c \ $(pkg-config --cflags --libs libavformat libavcodec libavutil) ./repro_flush input_bf.h264 ``` Expected on master (unpatched): ``` iter1: 90 frames decoded [libopenh264] PrefetchPic ERROR, pSps->iNumRefFrames:4 [libopenh264] DecodeFrame failed iter2: 4 frames decoded RESULT: BUG ``` Expected with this patch: ``` iter1: 90 frames decoded iter2: 90 frames decoded RESULT: OK ``` From 066e391ae34bb59b524a40c2ef420b8148618235 Mon Sep 17 00:00:00 2001 From: Scott Kidder <[email protected]> Date: Wed, 20 May 2026 17:17:24 -0700 Subject: [PATCH] avcodec/libopenh264dec: implement flush callback Cisco's ISVCDecoder retains DPB and reference state across avcodec_flush_buffers(), causing the next IDR to be accepted but subsequent P-frames to fail decode after a seek or loop. Cisco's API does not expose a non-destructive reset; tear down and rebuild the decoder via the existing close/init callbacks. Signed-off-by: Scott Kidder <[email protected]> --- libavcodec/libopenh264dec.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index b6a9bba2dc..e26b554ece 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -42,12 +42,22 @@ static av_cold int svc_decode_close(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; - if (s->decoder) + if (s->decoder) { WelsDestroyDecoder(s->decoder); + s->decoder = NULL; + } return 0; } +static av_cold int svc_decode_init(AVCodecContext *avctx); + +static void svc_decode_flush(AVCodecContext *avctx) +{ + svc_decode_close(avctx); + svc_decode_init(avctx); +} + static av_cold int svc_decode_init(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; @@ -162,6 +172,7 @@ const FFCodec ff_libopenh264_decoder = { .init = svc_decode_init, FF_CODEC_DECODE_CB(svc_decode_frame), .close = svc_decode_close, + .flush = svc_decode_flush, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
