PR #25360 opened by Marcos Ashton (MarcosAsh) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25360 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25360.patch
Fixes hardware decoding of VP9 streams that change size between keyframes. update_size() renegotiated the hwaccel on every frame size change, which throws away the decoder instance that holds the references. VP9 frames other than keyframes can change size and still predict from those references, so in vp90-2-05-resize.ivf every frame after the change came out wrong with Vulkan, and the validation layer reports the references as inactive slots. The decoder now remembers the size it negotiated the hwaccel for and keeps it on frames that fit. Keyframes still renegotiate, and so does a frame that grows past that size, which this doesn't fix. With Vulkan the resize stream is now bit-exact with the software decoder, with and without frame threads, and the other 225 VP9 conformance streams give the same result as before. fate-vp9 passes. Master also segfaults on this stream with -hwaccel vulkan -threads 1, that's the crash #24953 fixes. NVDEC gets most of the way. On master frames 3 to 9 of the resize stream are wrong. With this 6 to 9 are bit-exact, but the three 282x173 frames come out at 352x288, because nvdec creates the decoder with the target size set to the coded size and scales to it. I think that's better as a separate nvdec fix. VDPAU recreates its decoder on every size change in ff_vdpau_common_reinit() anyway, so nothing changes there. I couldn't test VAAPI, D3D or VideoToolbox. To reproduce, compare `ffmpeg -hwaccel vulkan -i vp90-2-05-resize.ivf -f framemd5 -` with `-c:v vp9`. I tested on Intel Arc (Meteor Lake) with Mesa 26.0.8 and an RTX 5070 Ti with NVIDIA 595.91.07. >From 24507a1ab28c77304427fa420e52f1ccfbe0cba1 Mon Sep 17 00:00:00 2001 From: Marcos Ashton Iglesias <[email protected]> Date: Thu, 22 Oct 2026 16:51:19 +0100 Subject: [PATCH] avcodec/vp9: keep the hwaccel on frame size changes that fit update_size() renegotiated the hwaccel on every frame size change, which creates a new decoder instance. Frames other than keyframes can change size and still predict from the reference frames and probability contexts, which the hwaccel keeps state for. With Vulkan, every frame after the first size change in vp90-2-05-resize.ivf came out wrong, and the reference slots were not active in the new video session (VUID-vkCmdBeginVideoCodingKHR-slotIndex-07239). Keep the hwaccel on frames other than keyframes whose size fits the one it was negotiated for. Keyframes still renegotiate, as does a frame that grows beyond that size, which stays broken. --- libavcodec/vp9.c | 15 +++++++++++++-- libavcodec/vp9dec.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index c20b1002c11..54aaf4c61f6 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -187,7 +187,14 @@ static int update_size(AVCodecContext *avctx, int w, int h) changed = 1; if ((ret = ff_set_dimensions(avctx, w, h)) < 0) return ret; + } + // Frames other than keyframes can change size and still use the reference + // frames and probability contexts, which the hwaccel keeps state for, so + // keep it as long as the new size fits its surfaces + if (changed && !(avctx->hwaccel && !s->s.h.keyframe && + s->pix_fmt == s->gf_fmt && + w <= s->hwaccel_w && h <= s->hwaccel_h)) { switch (s->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV420P10: @@ -270,9 +277,11 @@ static int update_size(AVCodecContext *avctx, int w, int h) avctx->pix_fmt = ret; s->gf_fmt = s->pix_fmt; - s->w = w; - s->h = h; + s->hwaccel_w = w; + s->hwaccel_h = h; } + s->w = w; + s->h = h; cols = (w + 7) >> 3; rows = (h + 7) >> 3; @@ -1935,6 +1944,8 @@ static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo s->gf_fmt = ssrc->gf_fmt; s->w = ssrc->w; s->h = ssrc->h; + s->hwaccel_w = ssrc->hwaccel_w; + s->hwaccel_h = ssrc->hwaccel_h; s->s.h.bpp = ssrc->s.h.bpp; s->bpp_index = ssrc->bpp_index; s->pix_fmt = ssrc->pix_fmt; diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h index fd33d03c2b4..921d013b3a5 100644 --- a/libavcodec/vp9dec.h +++ b/libavcodec/vp9dec.h @@ -124,6 +124,8 @@ typedef struct VP9Context { // and are therefore per-stream. pix_fmt represents the value in the header // of the currently processed frame. int w, h; + // size of the last get_format() negotiation, synced like w/h + int hwaccel_w, hwaccel_h; enum AVPixelFormat pix_fmt, last_fmt, gf_fmt; unsigned sb_cols, sb_rows, rows, cols; ProgressFrame next_refs[8]; -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
