Re: review
"Kumar, Pradeep via ffmpeg-devel" <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <PH7PR11MB8597A3B6C9D5E2207A1CCA76F6D22@PH7PR11MB8597.namprd11.prod.outlook.com> |
Hi Team, Please review this. This is done in context to save time for customer when flush is happened. -thanks Pradeep Kumar ________________________________ From: Kumar, Pradeep via ffmpeg-devel <[email protected]> Sent: Thursday, March 5, 2026 4:08 PM To: [email protected] <[email protected]> Cc: Kumar, Pradeep <[email protected]> Subject: [FFmpeg-devel] review Hi Team, Please review this. This is done in context to save time for customer when flush is happened. -thanks Pradeep Kumar _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
0001-avcodec-qsvdec-use-MFXVideoDECODE_Reset-on-flush-for.patch
(application/octet-stream, 5 KB)
From a7449f432d1cdeadf7a85e7ebb8d2850f65ad68d Mon Sep 17 00:00:00 2001 From: Pradeep Kumar <[email protected]> Date: Thu, 30 Jul 2026 14:39:34 +0530 Subject: [PATCH] avcodec/qsvdec: use MFXVideoDECODE_Reset on flush for fast keyframe decode path The existing flush implementation always performs a full teardown and reinitialization of the MFX session, which takes ~40-100 ms per call. This is a critical regression for applications that decode only keyframes and must flush the decoder between every frame (e.g. video management software seeking and displaying I-frames). Replace the unconditional reinit in qsv_decode_flush() with an in-place MFXVideoDECODE_Reset() call when a live session exists. Reset is sufficient to clear the decoder state and is ~20x faster than a full teardown+reinit cycle on ADL/RPL/PTL integrated graphics. New flush logic: - Call qsv_clear_async() only on the fast-reset path, immediately before MFXVideoDECODE_Reset(). This is the only place it is needed: Intel MediaSDK/VPL requires all outstanding async operations to be drained before Reset is called. - On the full-reinit fallback (no session, or Reset fails), call qsv_decode_close_qsvcontext() which already drains the async fifo, frees the work-frame list and uninits pool/session. A separate qsv_clear_async() call there was therefore redundant. - After a full teardown, explicitly null q->session so the reinit guard in qsv_process_data() (if !q->session) correctly triggers instead of dereferencing the freed handle. Signed-off-by: Pradeep <[email protected]> --- libavcodec/qsvdec.c | 73 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index a85c1785cf..58457dd23a 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -572,6 +572,33 @@ static void qsv_clear_unused_frames(QSVContext *q) } } +static void qsv_clear_async(QSVContext *q) +{ + QSVAsyncFrame aframe; + QSVFrame *cur; + + if (q->async_fifo) { + while (av_fifo_read(q->async_fifo, &aframe, 1) >= 0) { + if (aframe.frame && aframe.frame->queued > 0) + aframe.frame->queued -= 1; + av_freep(&aframe.sync); + } + } + + cur = q->work_frames; + while (cur) { + cur->queued = 0; + if (cur->used && !cur->surface.Data.Locked) { + cur->used = 0; + av_frame_unref(cur->frame); + } + cur = cur->next; + } + + q->zero_consume_run = 0; + q->reinit_flag = 0; +} + static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 **surf) { QSVFrame *frame, **last; @@ -1207,11 +1234,55 @@ static int qsv_decode_frame(AVCodecContext *avctx, AVFrame *frame, static void qsv_decode_flush(AVCodecContext *avctx) { QSVDecContext *s = avctx->priv_data; + mfxStatus sts; + mfxVideoParam param = { { { 0 } } }; qsv_clear_buffers(s); + // Fast path: reset the decoder in-place without tearing down the session. + // qsv_clear_async() is only needed here because MFXVideoDECODE_Reset + // requires all outstanding async operations to be drained first. + // On the full-reinit path below, qsv_decode_close_qsvcontext() already + // handles async/frame/pool cleanup, so calling qsv_clear_async() there + // would be redundant. + if (s->qsv.session && s->qsv.initialized) { + qsv_clear_async(&s->qsv); + + sts = MFXVideoDECODE_GetVideoParam(s->qsv.session, ¶m); + if (sts < 0) { + av_log(avctx, AV_LOG_WARNING, + "MFXVideoDECODE_GetVideoParam failed (%d), forcing full reinit\n", sts); + goto full_reinit; + } + + param.AsyncDepth = s->qsv.async_depth; + param.IOPattern = s->qsv.iopattern; + param.ExtParam = s->qsv.ext_buffers; + param.NumExtParam = s->qsv.nb_ext_buffers; + + sts = MFXVideoDECODE_Reset(s->qsv.session, ¶m); + if (sts < 0) { + av_log(avctx, AV_LOG_WARNING, + "MFXVideoDECODE_Reset failed (%d), forcing full reinit\n", sts); + goto full_reinit; + } + + s->qsv.frame_info = param.mfx.FrameInfo; + return; + } + +full_reinit: + // Full teardown: session missing, not yet initialized, or reset failed. + // qsv_decode_close_qsvcontext() clears async frames, the work-frame list, + // pool and session state, so no separate qsv_clear_async() is needed. + qsv_decode_close_qsvcontext(&s->qsv); + // qsv_decode_close_qsvcontext() does not null q->session (it doesn't need + // to on codec close). Since the QSVContext lives on across flush(), clear + // the dangling handle so the reinit path in qsv_process_data() takes the + // "no session" branch instead of dereferencing freed memory. + s->qsv.session = NULL; s->qsv.orig_pix_fmt = AV_PIX_FMT_NONE; - s->qsv.initialized = 0; + s->qsv.initialized = 0; } #define OFFSET(x) offsetof(QSVDecContext, x) -- 2.53.0.windows.1