From 485f1956908ae3281b2f5e1c6298f5ee061bcfd9 Mon Sep 17 00:00:00 2001 From: Dmitrii Gershenkop Date: Tue, 16 Jun 2026 15:33:25 +0200 Subject: [PATCH] avutil/hwcontext_amf: Implement AMF hardware memory mapping support. --- Changelog | 1 + libavutil/hwcontext_amf.c | 72 +++++++++++++++++++++++++++++++++++++++ libavutil/version.h | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 3c48005026..2ad3ee255f 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ version : - Remove CELT decoding support (doesn't affect Opus CELT) - Remove ogg/celt parsing - Bitstream filter to split Dolby Vision multi-layer HEVC +- Add AMF hardware memory mapping support. version 8.1: diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c index 754b1c60a2..7d877683b4 100644 --- a/libavutil/hwcontext_amf.c +++ b/libavutil/hwcontext_amf.c @@ -819,6 +819,77 @@ static int amf_device_derive(AVHWDeviceContext *device_ctx, } } +static void amf_unmap_frame(av_unused AVHWFramesContext *unused, HWMapDescriptor *hwmap) +{ + AMFSurface1 *surface1 = hwmap->priv; + AMF_IFACE_CALL(surface1, Unmap); + AMF_IFACE_CALL(surface1, Release); +} + +static int amf_map_frame(AVHWFramesContext *device_ctx, AVFrame *dst, const AVFrame *src, int flags) +{ + AMFSurface *surface = (AMFSurface *)src->data[0]; + AMFSurface1 *surface1 = NULL; + size_t *linesizes = NULL; + uint8_t **map = NULL; + int amf_mem_flags = AMF_MEMORY_CPU_NONE; + const AMFGuid guid = IID_AMFSurface1(); + AMF_RESULT res = AMF_FAIL; + size_t plane_count = 0; + int ret = -1; + + AMF_RETURN_IF_FALSE(device_ctx, surface != NULL, AVERROR(EINVAL) , "Source surface is null"); + + res = AMF_IFACE_CALL(surface, QueryInterface, &guid, (void**)&surface1); + AMF_RETURN_IF_FALSE(device_ctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface(AMFSurface1) failed with error %d\n", res); + + if (flags & AV_HWFRAME_MAP_READ) + amf_mem_flags |= AMF_MEMORY_CPU_READ; + + if (flags & AV_HWFRAME_MAP_WRITE) + amf_mem_flags |= AMF_MEMORY_CPU_WRITE; + + plane_count = AMF_IFACE_CALL(surface, GetPlanesCount); + linesizes = av_malloc_array(sizeof(size_t), plane_count); + AMF_GOTO_FAIL_IF_FALSE(device_ctx, linesizes, AVERROR(ENOMEM), "Unable to allocate line sizes array\n"); + + map = av_malloc_array(sizeof(uint8_t *), plane_count); + AMF_GOTO_FAIL_IF_FALSE(device_ctx, map, AVERROR(ENOMEM), "Unable to allocate mapping buffer\n"); + + dst->format = av_amf_to_av_format(AMF_IFACE_CALL(surface, GetFormat)); + + res = AMF_IFACE_CALL(surface1, Map, amf_mem_flags, plane_count, linesizes, (void**)map); + AMF_GOTO_FAIL_IF_FALSE(device_ctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFSurface1->Map() failed with error %d\n", res); + + ret = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &amf_unmap_frame, surface1); + AMF_GOTO_FAIL_IF_FALSE(device_ctx, ret >= 0, ret, "ff_hwframe_map_create failed with error %d\n", ret); + + dst->width = src->width; + dst->height = src->height; + av_frame_copy_props(dst, src); + + // The dst frame is no longer a hardware frame, from the perspective of any dst frame consumer. + av_buffer_unref(&dst->hw_frames_ctx); + + for (int plane = 0; plane < plane_count; ++plane) + { + dst->data[plane] = map[plane]; + dst->linesize[plane] = linesizes[plane]; + } + +fail: + if (map) + av_free(map); + + if (linesizes) + av_free(linesizes); + + if (ret < 0 && surface1 != NULL) + AMF_IFACE_CALL(surface1, Release); + + return ret; +} + const HWContextType ff_hwcontext_type_amf = { .type = AV_HWDEVICE_TYPE_AMF, .name = "AMF", @@ -836,6 +907,7 @@ const HWContextType ff_hwcontext_type_amf = { .transfer_get_formats = amf_transfer_get_formats, .transfer_data_to = amf_transfer_data_to, .transfer_data_from = amf_transfer_data_from, + .map_from = amf_map_frame, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_AMF_SURFACE, AV_PIX_FMT_NONE }, }; diff --git a/libavutil/version.h b/libavutil/version.h index 42f2d41052..429e65d77f 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -80,7 +80,7 @@ #define LIBAVUTIL_VERSION_MAJOR 60 #define LIBAVUTIL_VERSION_MINOR 33 -#define LIBAVUTIL_VERSION_MICRO 100 +#define LIBAVUTIL_VERSION_MICRO 101 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \