This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit a127ad2da64e7337efa850a5186ead9ee70b546d Author: Diego de Souza <[email protected]> AuthorDate: Sat Mar 14 01:34:43 2026 +0100 Commit: Timo Rothenpieler <[email protected]> CommitDate: Tue Jul 14 19:45:02 2026 +0000 avcodec/nvenc: add CUARRAY (block-linear) input support Allow NVENC to accept AV_PIX_FMT_CUARRAY frames by registering them as NV_ENC_INPUT_RESOURCE_TYPE_CUDAARRAY. This enables zero-copy transcode when paired with NVDEC CUARRAY output, avoiding the pitched-linear intermediate copy. Also accept semi-planar 444 formats (NV24, P410, P412, P416) and map them to the corresponding NVENC buffer formats when registered as CUarray input resources. Guarded by NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT (SDK 13.1+). Signed-off-by: Diego de Souza <[email protected]> --- libavcodec/nvenc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++-------- libavcodec/nvenc.h | 1 + libavcodec/version.h | 2 +- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 1c931d43af..dffbb67652 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -56,6 +56,7 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_P010, AV_PIX_FMT_YUV444P, AV_PIX_FMT_P012, // Truncated to 10bits + AV_PIX_FMT_NV24, AV_PIX_FMT_P016, // Truncated to 10bits #ifdef NVENC_HAVE_422_SUPPORT AV_PIX_FMT_NV16, @@ -66,6 +67,9 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_YUV444P10MSB, AV_PIX_FMT_YUV444P12MSB, // Truncated to 10bits AV_PIX_FMT_YUV444P16, // Truncated to 10bits + AV_PIX_FMT_P410, + AV_PIX_FMT_P412, // Truncated to 10bits + AV_PIX_FMT_P416, // Truncated to 10bits AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, AV_PIX_FMT_0BGR32, @@ -76,6 +80,9 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_GBRP10MSB, AV_PIX_FMT_GBRP16, // Truncated to 10bits AV_PIX_FMT_CUDA, +#ifdef NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT + AV_PIX_FMT_CUARRAY, +#endif #if CONFIG_D3D11VA AV_PIX_FMT_D3D11, #endif @@ -84,6 +91,9 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(CUDA, CUDA), +#ifdef NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT + HW_CONFIG_ENCODER_FRAMES(CUARRAY, CUDA), +#endif HW_CONFIG_ENCODER_DEVICE(NONE, CUDA), #if CONFIG_D3D11VA HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA), @@ -101,6 +111,9 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ pix_fmt == AV_PIX_FMT_YUV444P12MSB || \ pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_P410 || \ + pix_fmt == AV_PIX_FMT_P412 || \ + pix_fmt == AV_PIX_FMT_P416 || \ pix_fmt == AV_PIX_FMT_X2RGB10 || \ pix_fmt == AV_PIX_FMT_X2BGR10 || \ pix_fmt == AV_PIX_FMT_GBRP10MSB || \ @@ -114,9 +127,13 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { pix_fmt == AV_PIX_FMT_X2BGR10) #define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ + pix_fmt == AV_PIX_FMT_NV24 || \ pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ pix_fmt == AV_PIX_FMT_YUV444P12MSB || \ pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_P410 || \ + pix_fmt == AV_PIX_FMT_P412 || \ + pix_fmt == AV_PIX_FMT_P416 || \ pix_fmt == AV_PIX_FMT_GBRP || \ pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16 || \ @@ -127,6 +144,10 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { pix_fmt == AV_PIX_FMT_P212 || \ pix_fmt == AV_PIX_FMT_P216) +#define IS_HWACCEL(pix_fmt) (pix_fmt == AV_PIX_FMT_CUDA || \ + pix_fmt == AV_PIX_FMT_CUARRAY || \ + pix_fmt == AV_PIX_FMT_D3D11) + #define IS_GBRP(pix_fmt) (pix_fmt == AV_PIX_FMT_GBRP || \ pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16) @@ -712,7 +733,8 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) nvenc_map_preset(ctx); - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) { + if (IS_HWACCEL(avctx->pix_fmt) || + avctx->hw_frames_ctx || avctx->hw_device_ctx) { AVHWFramesContext *frames_ctx; AVHWDeviceContext *hwdev_ctx; AVCUDADeviceContext *cuda_device_hwctx = NULL; @@ -723,7 +745,7 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) if (avctx->hw_frames_ctx) { frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - if (frames_ctx->format == AV_PIX_FMT_CUDA) + if (frames_ctx->format == AV_PIX_FMT_CUDA || frames_ctx->format == AV_PIX_FMT_CUARRAY) cuda_device_hwctx = frames_ctx->device_ctx->hwctx; #if CONFIG_D3D11VA else if (frames_ctx->format == AV_PIX_FMT_D3D11) @@ -1883,7 +1905,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 }; allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (IS_HWACCEL(avctx->pix_fmt)) { ctx->surfaces[idx].in_ref = av_frame_alloc(); if (!ctx->surfaces[idx].in_ref) return AVERROR(ENOMEM); @@ -1915,7 +1937,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) nv_status = p_nvenc->nvEncCreateBitstreamBuffer(ctx->nvencoder, &allocOut); if (nv_status != NV_ENC_SUCCESS) { int err = nvenc_print_error(avctx, nv_status, "CreateBitstreamBuffer failed"); - if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) + if (!IS_HWACCEL(avctx->pix_fmt)) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[idx].input_surface); av_frame_free(&ctx->surfaces[idx].in_ref); return err; @@ -2038,7 +2060,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) av_freep(&ctx->frame_data_array); } - if (ctx->surfaces && (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11)) { + if (ctx->surfaces && IS_HWACCEL(avctx->pix_fmt)) { for (i = 0; i < ctx->nb_registered_frames; i++) { if (ctx->registered_frames[i].mapped) p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[i].in_map.mappedResource); @@ -2050,7 +2072,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) if (ctx->surfaces) { for (i = 0; i < ctx->nb_surfaces; ++i) { - if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) + if (!IS_HWACCEL(avctx->pix_fmt)) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[i].input_surface); av_frame_free(&ctx->surfaces[i].in_ref); p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->surfaces[i].output_surface); @@ -2098,7 +2120,7 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; int ret; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (IS_HWACCEL(avctx->pix_fmt)) { AVHWFramesContext *frames_ctx; if (!avctx->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, @@ -2231,7 +2253,9 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) int i, idx, ret; for (i = 0; i < ctx->nb_registered_frames; i++) { - if (avctx->pix_fmt == AV_PIX_FMT_CUDA && ctx->registered_frames[i].ptr == frame->data[0]) + if ((avctx->pix_fmt == AV_PIX_FMT_CUDA || + avctx->pix_fmt == AV_PIX_FMT_CUARRAY) && + ctx->registered_frames[i].ptr == frame->data[0]) return i; else if (avctx->pix_fmt == AV_PIX_FMT_D3D11 && ctx->registered_frames[i].ptr == frame->data[0] && ctx->registered_frames[i].ptr_index == (intptr_t)frame->data[1]) return i; @@ -2249,6 +2273,12 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; +#ifdef NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT + } else if (avctx->pix_fmt == AV_PIX_FMT_CUARRAY) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frames_ctx->sw_format); + reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDAARRAY; + reg.pitch = frames_ctx->width * (desc && desc->comp[0].depth > 8 ? 2 : 1); +#endif } else if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX; @@ -2256,6 +2286,23 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) } reg.bufferFormat = nvenc_map_buffer_format(frames_ctx->sw_format); +#ifdef NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT + if (reg.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED && + reg.resourceType == NV_ENC_INPUT_RESOURCE_TYPE_CUDAARRAY) { + switch (frames_ctx->sw_format) { + case AV_PIX_FMT_NV24: + reg.bufferFormat = NV_ENC_BUFFER_FORMAT_YUV444; + break; + case AV_PIX_FMT_P410: + case AV_PIX_FMT_P412: + case AV_PIX_FMT_P416: + reg.bufferFormat = NV_ENC_BUFFER_FORMAT_YUV444_10BIT; + break; + default: + break; + } + } +#endif if (reg.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED) { av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format: %s\n", av_get_pix_fmt_name(frames_ctx->sw_format)); @@ -2271,6 +2318,7 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) ctx->registered_frames[idx].ptr = frame->data[0]; ctx->registered_frames[idx].ptr_index = reg.subResourceIndex; ctx->registered_frames[idx].regptr = reg.registeredResource; + return idx; } @@ -2284,7 +2332,7 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, int res; NVENCSTATUS nv_status; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (IS_HWACCEL(avctx->pix_fmt)) { int reg_idx = nvenc_register_frame(avctx, frame); if (reg_idx < 0) { av_log(avctx, AV_LOG_ERROR, "Could not register an input HW frame\n"); @@ -2602,7 +2650,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur } - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (IS_HWACCEL(avctx->pix_fmt)) { ctx->registered_frames[tmpoutsurf->reg_idx].mapped -= 1; if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped == 0) { nv_status = p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].in_map.mappedResource); diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index ad6ddaa434..acde2a42c1 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -78,6 +78,7 @@ typedef void ID3D11Device; #if NVENCAPI_CHECK_VERSION(13, 1) #define NVENC_NEW_COUNTING_TYPE #define NVENC_HAVE_AV1_HGOP_SUPPORT +#define NVENC_HAVE_CUDA_ARRAY_INPUT_SUPPORT #endif typedef struct NvencSurface diff --git a/libavcodec/version.h b/libavcodec/version.h index da54f87887..39dbec0208 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -30,7 +30,7 @@ #include "version_major.h" #define LIBAVCODEC_VERSION_MINOR 6 -#define LIBAVCODEC_VERSION_MICRO 100 +#define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
