[PR] avcodec/cuviddec: honor application-selected software output (PR #24020)
Diego de Souza via ffmpeg-devel <[email protected]> Wed, 05 Aug 2026 14:46:53 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178594121383.59.4179501197199562945@29965ddac10e> |
PR #24020 opened by Diego de Souza (ddesouza) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24020 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24020.patch The CUARRAY output option made the decoder override a software format selected by get_format() with CUDA. This broke ordinary CUVID decoding to software consumers. Default output_format to auto and only override get_format() when the user explicitly requests cuda/cuarray or enables zero_copy. Keep the internal frames context in the corresponding hardware format and reject opaque/non-opaque transitions during decoder reinitialization. >From 4246a9d70d76115402fbc3c3b5c28d8253148eee Mon Sep 17 00:00:00 2001 From: Diego de Souza <[email protected]> Date: Wed, 5 Aug 2026 16:37:28 +0200 Subject: [PATCH] avcodec/cuviddec: honor application-selected software output The CUARRAY output option made the decoder override a software format selected by get_format() with CUDA. This broke ordinary CUVID decoding to software consumers. Default output_format to auto and only override get_format() when the user explicitly requests cuda/cuarray or enables zero_copy. Keep the internal frames context in the corresponding hardware format and reject opaque/non-opaque transitions during decoder reinitialization. Signed-off-by: Diego de Souza <[email protected]> --- libavcodec/cuviddec.c | 78 +++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index 3c8faae3c8..14744cf067 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -152,17 +152,18 @@ static int cuvid_get_requested_hw_format(AVCodecContext *avctx, CuvidContext *ct { enum AVPixelFormat requested = ctx->output_format; - if (requested == AV_PIX_FMT_NONE) - requested = AV_PIX_FMT_CUDA; - - if (ctx->zero_copy && requested != AV_PIX_FMT_CUARRAY) { - av_log(avctx, AV_LOG_WARNING, - "zero_copy requires cuarray output format; " - "overriding -output_format %s -> cuarray\n", - av_get_pix_fmt_name(requested) ? av_get_pix_fmt_name(requested) : "unknown"); + if (ctx->zero_copy) { + if (requested != AV_PIX_FMT_NONE && requested != AV_PIX_FMT_CUARRAY) + av_log(avctx, AV_LOG_WARNING, + "zero_copy requires cuarray output format; " + "overriding -output_format %s -> cuarray\n", + av_get_pix_fmt_name(requested) ? av_get_pix_fmt_name(requested) : "unknown"); requested = AV_PIX_FMT_CUARRAY; } + if (requested == AV_PIX_FMT_NONE) + requested = AV_PIX_FMT_CUDA; + switch (requested) { case AV_PIX_FMT_CUDA: break; @@ -185,6 +186,26 @@ static int cuvid_get_requested_hw_format(AVCodecContext *avctx, CuvidContext *ct return 0; } +static int cuvid_output_format_is_forced(const CuvidContext *ctx) +{ + return ctx->zero_copy || ctx->output_format != AV_PIX_FMT_NONE; +} + +static enum AVPixelFormat cuvid_apply_forced_output_format(AVCodecContext *avctx, + const CuvidContext *ctx, + enum AVPixelFormat selected, + enum AVPixelFormat requested) +{ + if (cuvid_output_format_is_forced(ctx) && selected != requested) { + av_log(avctx, AV_LOG_VERBOSE, + "ff_get_format returned %s, overriding to explicitly requested %s\n", + av_get_pix_fmt_name(selected), av_get_pix_fmt_name(requested)); + selected = requested; + } + + return selected; +} + static void cuvid_prepare_format_list(enum AVPixelFormat *pix_fmts, enum AVPixelFormat hw_format, enum AVPixelFormat sw_format) @@ -254,8 +275,9 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form CUVIDDECODECREATEINFO cuinfo; int surface_fmt; int chroma_444; - int old_nb_surfaces, fifo_size_inc, fifo_size_mul = 1; - enum AVPixelFormat requested_hw_format; + int old_nb_surfaces, old_opaque_output = ctx->opaque_output; + int fifo_size_inc, fifo_size_mul = 1; + enum AVPixelFormat requested_hw_format, internal_hw_format; int old_width = avctx->width; int old_height = avctx->height; @@ -369,13 +391,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form return 0; } - if (surface_fmt != AV_PIX_FMT_CUDA && surface_fmt != AV_PIX_FMT_CUARRAY) { - av_log(avctx, AV_LOG_VERBOSE, - "ff_get_format returned %s, overriding to %s\n", - av_get_pix_fmt_name(surface_fmt), - av_get_pix_fmt_name(requested_hw_format)); - surface_fmt = requested_hw_format; - } + surface_fmt = cuvid_apply_forced_output_format(avctx, ctx, surface_fmt, + requested_hw_format); av_log(avctx, AV_LOG_VERBOSE, "Formats: Original: %s | HW: %s | SW: %s\n", av_get_pix_fmt_name(avctx->pix_fmt), @@ -384,6 +401,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form ctx->opaque_output = (surface_fmt == AV_PIX_FMT_CUARRAY); avctx->pix_fmt = surface_fmt; + internal_hw_format = ctx->opaque_output ? AV_PIX_FMT_CUARRAY + : AV_PIX_FMT_CUDA; if (ctx->opaque_output) { switch (avctx->sw_pix_fmt) { @@ -442,6 +461,13 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form avctx->framerate.den = format->frame_rate.denominator; } + if (ctx->cudecoder && ctx->opaque_output != old_opaque_output) { + av_log(avctx, AV_LOG_ERROR, + "Changing between opaque and non-opaque output is not supported\n"); + ctx->internal_error = AVERROR(EINVAL); + return 0; + } + if (ctx->cudecoder && avctx->coded_width == format->coded_width && avctx->coded_height == format->coded_height @@ -462,13 +488,13 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form if (hwframe_ctx->pool && ( hwframe_ctx->width < avctx->width || hwframe_ctx->height < avctx->height || - (hwframe_ctx->format != AV_PIX_FMT_CUDA && hwframe_ctx->format != AV_PIX_FMT_CUARRAY) || + hwframe_ctx->format != internal_hw_format || hwframe_ctx->sw_format != avctx->sw_pix_fmt)) { av_log(avctx, AV_LOG_ERROR, "AVHWFramesContext is already initialized with incompatible parameters\n"); av_log(avctx, AV_LOG_DEBUG, "width: %d <-> %d\n", hwframe_ctx->width, avctx->width); av_log(avctx, AV_LOG_DEBUG, "height: %d <-> %d\n", hwframe_ctx->height, avctx->height); av_log(avctx, AV_LOG_DEBUG, "format: %s <-> %s\n", av_get_pix_fmt_name(hwframe_ctx->format), - av_get_pix_fmt_name(avctx->pix_fmt)); + av_get_pix_fmt_name(internal_hw_format)); av_log(avctx, AV_LOG_DEBUG, "sw_format: %s <-> %s\n", av_get_pix_fmt_name(hwframe_ctx->sw_format), av_get_pix_fmt_name(avctx->sw_pix_fmt)); ctx->internal_error = AVERROR(EINVAL); @@ -679,7 +705,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form #endif if (!hwframe_ctx->pool) { - hwframe_ctx->format = avctx->pix_fmt; + hwframe_ctx->format = internal_hw_format; hwframe_ctx->sw_format = avctx->sw_pix_fmt; hwframe_ctx->width = avctx->width; hwframe_ctx->height = avctx->height; @@ -1433,13 +1459,8 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) return ret; } - if (ret != AV_PIX_FMT_CUDA && ret != AV_PIX_FMT_CUARRAY) { - av_log(avctx, AV_LOG_VERBOSE, - "ff_get_format returned %s, overriding to %s\n", - av_get_pix_fmt_name(ret), - av_get_pix_fmt_name(requested_hw_format)); - ret = requested_hw_format; - } + ret = cuvid_apply_forced_output_format(avctx, ctx, ret, + requested_hw_format); ctx->opaque_output = (ret == AV_PIX_FMT_CUARRAY); avctx->pix_fmt = ret; @@ -1756,7 +1777,8 @@ static const AVOption options[] = { { "drop_second_field", "Drop second field when deinterlacing", OFFSET(drop_second_field), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, { "crop", "Crop (top)x(bottom)x(left)x(right)", OFFSET(crop_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, { "resize", "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, - { "output_format", "Hardware output format", OFFSET(output_format), AV_OPT_TYPE_INT, { .i64 = AV_PIX_FMT_CUDA }, 0, INT_MAX, VD, .unit = "output_format" }, + { "output_format", "Hardware output format", OFFSET(output_format), AV_OPT_TYPE_INT, { .i64 = AV_PIX_FMT_NONE }, AV_PIX_FMT_NONE, INT_MAX, VD, .unit = "output_format" }, + { "auto", "Honor the application output format selection", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_NONE }, 0, 0, VD, .unit = "output_format" }, { "cuda", "CUDA pitch-linear output", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_CUDA }, 0, 0, VD, .unit = "output_format" }, #ifdef NVDEC_HAVE_OPAQUE_OUTPUT_SUPPORT { "cuarray", "CUDA block-linear opaque output", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_CUARRAY }, 0, 0, VD, .unit = "output_format" }, -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]