From: DmitriiGershenkop via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: DmitriiGershenkop <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] avfilter/vf_vpp_amf: Extend AMF Color Converter HDR capabilities (PR #21811)
Date: Fri, 20 Feb 2026 12:04:11 -0000
Message-ID: <177158905182.25.7312536821130965598@29965ddac10e> (raw)
PR #21811 opened by DmitriiGershenkop
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21811
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21811.patch
>From c6f64052a7768bfd1007c33723f0b4cdd061beea Mon Sep 17 00:00:00 2001
From: Dmitrii Gershenkop <bortengineer@protonmail.com>
Date: Thu, 19 Feb 2026 14:29:45 +0100
Subject: [PATCH] avfilter/vf_vpp_amf: Extend AMF Color Converter HDR
capabilities
---
Changelog | 1 +
libavcodec/amfdec.c | 65 +-------------
libavcodec/amfenc.c | 91 +------------------
libavcodec/amfenc.h | 2 -
libavcodec/amfenc_av1.c | 4 +-
libavcodec/amfenc_h264.c | 3 +-
libavcodec/amfenc_hevc.c | 3 +-
libavfilter/version.h | 2 +-
libavfilter/vf_amf_common.c | 89 ++++++++++++++++--
libavfilter/vf_amf_common.h | 15 +++-
libavfilter/vf_sr_amf.c | 9 +-
libavfilter/vf_vpp_amf.c | 160 ++++++++++++++++++++++++++-------
libavutil/hwcontext_amf.c | 175 +++++++++++++++++++++++++++++++++---
libavutil/hwcontext_amf.h | 8 ++
14 files changed, 413 insertions(+), 214 deletions(-)
diff --git a/Changelog b/Changelog
index a9d68b369e..966ddf5f65 100644
--- a/Changelog
+++ b/Changelog
@@ -20,6 +20,7 @@ version <next>:
- JPEG-XS raw bitstream muxer and demuxer
- IAMF Projection mode Ambisonic Audio Elements muxing and demuxing
- Add vf_mestimate_d3d12 filter
+- Extend AMF Color Converter (vf_vpp_amf) HDR capabilities
version 8.0:
diff --git a/libavcodec/amfdec.c b/libavcodec/amfdec.c
index c178d5d912..7c58a96bb0 100644
--- a/libavcodec/amfdec.c
+++ b/libavcodec/amfdec.c
@@ -21,8 +21,6 @@
#include "amfdec.h"
#include "codec_internal.h"
#include "hwconfig.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/mem.h"
#include "libavutil/time.h"
#include "decode.h"
#include "decode_bsf.h"
@@ -125,31 +123,7 @@ static int amf_init_decoder(AVCodecContext *avctx)
} else if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) {
AMF_ASSIGN_PROPERTY_BOOL(res, ctx->decoder, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 0);
}
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
- switch (avctx->colorspace) {
- case AVCOL_SPC_SMPTE170M:
- if (avctx->color_range == AVCOL_RANGE_JPEG) {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
- } else {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
- }
- break;
- case AVCOL_SPC_BT709:
- if (avctx->color_range == AVCOL_RANGE_JPEG) {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
- } else {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
- }
- break;
- case AVCOL_SPC_BT2020_NCL:
- case AVCOL_SPC_BT2020_CL:
- if (avctx->color_range == AVCOL_RANGE_JPEG) {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
- } else {
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
- }
- break;
- }
+ color_profile = av_amf_get_color_profile(avctx->color_range, avctx->colorspace);
if (color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN)
AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_PROFILE, color_profile);
if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED)
@@ -435,41 +409,10 @@ static int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface* surface,
AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
if (ret != AMF_OK)
return ret;
- if (hdrmeta != NULL) {
- AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
- const int chroma_den = 50000;
- const int luma_den = 10000;
- if (!mastering)
- return AVERROR(ENOMEM);
-
- mastering->display_primaries[0][0] = av_make_q(hdrmeta->redPrimary[0], chroma_den);
- mastering->display_primaries[0][1] = av_make_q(hdrmeta->redPrimary[1], chroma_den);
-
- mastering->display_primaries[1][0] = av_make_q(hdrmeta->greenPrimary[0], chroma_den);
- mastering->display_primaries[1][1] = av_make_q(hdrmeta->greenPrimary[1], chroma_den);
-
- mastering->display_primaries[2][0] = av_make_q(hdrmeta->bluePrimary[0], chroma_den);
- mastering->display_primaries[2][1] = av_make_q(hdrmeta->bluePrimary[1], chroma_den);
-
- mastering->white_point[0] = av_make_q(hdrmeta->whitePoint[0], chroma_den);
- mastering->white_point[1] = av_make_q(hdrmeta->whitePoint[1], chroma_den);
-
- mastering->max_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den);
- mastering->min_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den);
-
- mastering->has_luminance = 1;
- mastering->has_primaries = 1;
- if (hdrmeta->maxContentLightLevel) {
- AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
-
- if (!light)
- return AVERROR(ENOMEM);
-
- light->MaxCLL = hdrmeta->maxContentLightLevel;
- light->MaxFALL = hdrmeta->maxFrameAverageLightLevel;
- }
- }
+ ret = av_amf_attach_hdr_metadata(frame, hdrmeta);
+ if (ret < 0)
+ return ret;
}
}
return 0;
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 329ce29005..50045b3ca3 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -17,13 +17,11 @@
*/
#include "config.h"
-#include "config_components.h"
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_amf.h"
-#include "libavutil/hwcontext_amf_internal.h"
#if CONFIG_D3D11VA
#include "libavutil/hwcontext_d3d11va.h"
#endif
@@ -37,62 +35,10 @@
#include "amfenc.h"
#include "encode.h"
-#include "internal.h"
-#include "libavutil/mastering_display_metadata.h"
#define AMF_AV_FRAME_REF L"av_frame_ref"
#define PTS_PROP L"PtsProp"
-static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta)
-{
- AVFrameSideData *sd_display;
- AVFrameSideData *sd_light;
- AVMasteringDisplayMetadata *display_meta;
- AVContentLightMetadata *light_meta;
-
- sd_display = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
- if (sd_display) {
- display_meta = (AVMasteringDisplayMetadata *)sd_display->data;
- if (display_meta->has_luminance) {
- const unsigned int luma_den = 10000;
- hdrmeta->maxMasteringLuminance =
- (amf_uint32)(luma_den * av_q2d(display_meta->max_luminance));
- hdrmeta->minMasteringLuminance =
- FFMIN((amf_uint32)(luma_den * av_q2d(display_meta->min_luminance)), hdrmeta->maxMasteringLuminance);
- }
- if (display_meta->has_primaries) {
- const unsigned int chroma_den = 50000;
- hdrmeta->redPrimary[0] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][0])), chroma_den);
- hdrmeta->redPrimary[1] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][1])), chroma_den);
- hdrmeta->greenPrimary[0] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][0])), chroma_den);
- hdrmeta->greenPrimary[1] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][1])), chroma_den);
- hdrmeta->bluePrimary[0] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][0])), chroma_den);
- hdrmeta->bluePrimary[1] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][1])), chroma_den);
- hdrmeta->whitePoint[0] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[0])), chroma_den);
- hdrmeta->whitePoint[1] =
- FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[1])), chroma_den);
- }
-
- sd_light = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
- if (sd_light) {
- light_meta = (AVContentLightMetadata *)sd_light->data;
- if (light_meta) {
- hdrmeta->maxContentLightLevel = (amf_uint16)light_meta->MaxCLL;
- hdrmeta->maxFrameAverageLightLevel = (amf_uint16)light_meta->MaxFALL;
- }
- }
- return 0;
- }
- return 1;
-}
-
#if CONFIG_D3D11VA
#include <d3d11.h>
#endif
@@ -479,7 +425,7 @@ static int amf_submit_frame(AVCodecContext *avctx, AVFrame *frame, AMFSurface
res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
if (res == AMF_OK) {
AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
- if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) {
+ if (av_amf_extract_hdr_metadata(frame, hdrmeta) == 0) {
switch (avctx->codec->id) {
case AV_CODEC_ID_H264:
AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break;
@@ -733,41 +679,6 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
return ret;
}
-int ff_amf_get_color_profile(AVCodecContext *avctx)
-{
- amf_int64 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
- if (avctx->color_range == AVCOL_RANGE_JPEG) {
- /// Color Space for Full (JPEG) Range
- switch (avctx->colorspace) {
- case AVCOL_SPC_SMPTE170M:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
- break;
- case AVCOL_SPC_BT709:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
- break;
- case AVCOL_SPC_BT2020_NCL:
- case AVCOL_SPC_BT2020_CL:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
- break;
- }
- } else {
- /// Color Space for Limited (MPEG) range
- switch (avctx->colorspace) {
- case AVCOL_SPC_SMPTE170M:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
- break;
- case AVCOL_SPC_BT709:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
- break;
- case AVCOL_SPC_BT2020_NCL:
- case AVCOL_SPC_BT2020_CL:
- color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
- break;
- }
- }
- return color_profile;
-}
-
const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = {
#if CONFIG_D3D11VA
HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA),
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index 8f5eb5a9ef..52a78b206a 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -161,8 +161,6 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
*/
extern const enum AVPixelFormat ff_amf_pix_fmts[];
-int ff_amf_get_color_profile(AVCodecContext *avctx);
-
/**
* Error handling helper
*/
diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c
index 70642a6b54..b57c76de27 100644
--- a/libavcodec/amfenc_av1.c
+++ b/libavcodec/amfenc_av1.c
@@ -15,7 +15,7 @@
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-
+#include "libavutil/hwcontext_amf.h"
#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
@@ -258,7 +258,7 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx)
AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, bit_depth);
// Color profile
- color_profile = ff_amf_get_color_profile(avctx);
+ color_profile = av_amf_get_color_profile(avctx->color_range, avctx->colorspace);
AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile);
// Color Range
diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c
index c39a65aead..b92b9af875 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -17,6 +17,7 @@
*/
+#include "libavutil/hwcontext_amf.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
@@ -270,7 +271,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx)
AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio);
}
- color_profile = ff_amf_get_color_profile(avctx);
+ color_profile = av_amf_get_color_profile(avctx->color_range, avctx->colorspace);
AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PROFILE, color_profile);
/// Color Range (Support for older Drivers)
diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c
index fe1d948c92..01d6ea9b3d 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/hwcontext_amf.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
@@ -252,7 +253,7 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx)
AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, bit_depth);
// Color profile
- color_profile = ff_amf_get_color_profile(avctx);
+ color_profile = av_amf_get_color_profile(avctx->color_range, avctx->colorspace);
AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile);
// Color Range (Support for older Drivers)
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 64cd692ab6..4239736a2d 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -32,7 +32,7 @@
#include "version_major.h"
#define LIBAVFILTER_VERSION_MINOR 12
-#define LIBAVFILTER_VERSION_MICRO 100
+#define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
diff --git a/libavfilter/vf_amf_common.c b/libavfilter/vf_amf_common.c
index b458de5e5c..a3f43ff0df 100644
--- a/libavfilter/vf_amf_common.c
+++ b/libavfilter/vf_amf_common.c
@@ -22,12 +22,11 @@
#include "avfilter.h"
#include "avfilter_internal.h"
#include "formats.h"
-#include "libavutil/mem.h"
#include "libavutil/imgutils.h"
+#include "AMF/components/VideoDecoderUVD.h"
#include "libavutil/hwcontext_amf.h"
#include "libavutil/hwcontext_amf_internal.h"
-#include "AMF/components/ColorSpace.h"
#include "scale_eval.h"
#if CONFIG_DXVA2
@@ -65,6 +64,12 @@ void amf_filter_uninit(AVFilterContext *avctx)
ctx->component = NULL;
}
+ if (ctx->master_display)
+ av_freep(&ctx->master_display);
+
+ if (ctx->light_meta)
+ av_freep(&ctx->light_meta);
+
av_buffer_unref(&ctx->amf_device_ref);
av_buffer_unref(&ctx->hwdevice_ref);
av_buffer_unref(&ctx->hwframes_in_ref);
@@ -137,19 +142,19 @@ int amf_filter_filter_frame(AVFilterLink *inlink, AVFrame *in)
}
out_color_range = AVCOL_RANGE_UNSPECIFIED;
- if (ctx->color_range == AMF_COLOR_RANGE_FULL)
+ if (ctx->out_color_range == AMF_COLOR_RANGE_FULL)
out_color_range = AVCOL_RANGE_JPEG;
- else if (ctx->color_range == AMF_COLOR_RANGE_STUDIO)
+ else if (ctx->out_color_range == AMF_COLOR_RANGE_STUDIO)
out_color_range = AVCOL_RANGE_MPEG;
- if (ctx->color_range != AMF_COLOR_RANGE_UNDEFINED)
+ if (ctx->out_color_range != AMF_COLOR_RANGE_UNDEFINED)
out->color_range = out_color_range;
- if (ctx->primaries != AMF_COLOR_PRIMARIES_UNDEFINED)
- out->color_primaries = ctx->primaries;
+ if (ctx->out_primaries != AMF_COLOR_PRIMARIES_UNDEFINED)
+ out->color_primaries = ctx->out_primaries;
- if (ctx->trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED)
- out->color_trc = ctx->trc;
+ if (ctx->out_trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED)
+ out->color_trc = ctx->out_trc;
if (ret < 0)
@@ -444,6 +449,7 @@ AVFrame *amf_amfsurface_to_avframe(AVFilterContext *avctx, AMFSurface* pSurface)
int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFSurface** ppSurface)
{
+ AMFVariantStruct var = { 0 };
AMFFilterContext *ctx = avctx->priv;
AMFSurface *surface;
AMF_RESULT res;
@@ -493,6 +499,71 @@ int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFS
break;
}
+ // If AMFSurface comes from other AMF components, it may have various
+ // properties already set. These properties can be used by other AMF
+ // components to perform their tasks. In the context of the AMF video
+ // filter, that other component could be an AMFVideoConverter. By default,
+ // AMFVideoConverter will use HDR related properties assigned to a surface
+ // by an AMFDecoder. If frames (surfaces) originated from any other source,
+ // i.e. from hevcdec, assign those properties from avframe; do not
+ // overwrite these properties if they already have a value.
+ res = surface->pVtbl->GetProperty(surface, AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC, &var);
+
+ if (res == AMF_NOT_FOUND && frame->color_trc != AVCOL_TRC_UNSPECIFIED)
+ // Note: as of now(Feb 2026), most AV and AMF enums are interchangeable.
+ // TBD: can enums change their values in the future?
+ // For better future-proofing it's better to have dedicated
+ // enum mapping functions.
+ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC, frame->color_trc);
+
+ res = surface->pVtbl->GetProperty(surface, AMF_VIDEO_DECODER_COLOR_PRIMARIES, &var);
+ if (res == AMF_NOT_FOUND && frame->color_primaries != AVCOL_PRI_UNSPECIFIED)
+ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_DECODER_COLOR_PRIMARIES, frame->color_primaries);
+
+ res = surface->pVtbl->GetProperty(surface, AMF_VIDEO_DECODER_COLOR_RANGE, &var);
+ if (res == AMF_NOT_FOUND && frame->color_range != AVCOL_RANGE_UNSPECIFIED)
+ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_DECODER_COLOR_RANGE, frame->color_range);
+
+ // Color range for older drivers
+ if (frame->color_range == AVCOL_RANGE_JPEG) {
+ AMF_ASSIGN_PROPERTY_BOOL(res, surface, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 1);
+ } else if (frame->color_range != AVCOL_RANGE_UNSPECIFIED)
+ AMF_ASSIGN_PROPERTY_BOOL(res, surface, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 0);
+
+ // Color profile for newer drivers
+ res = surface->pVtbl->GetProperty(surface, AMF_VIDEO_DECODER_COLOR_PROFILE, &var);
+ if (res == AMF_NOT_FOUND && frame->color_range != AVCOL_RANGE_UNSPECIFIED && frame->colorspace != AVCOL_SPC_UNSPECIFIED) {
+ amf_int64 color_profile = color_profile = av_amf_get_color_profile(frame->color_range, frame->colorspace);
+
+ if (color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN)
+ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_DECODER_COLOR_PROFILE, color_profile);
+ }
+
+ if (ctx->in_trc == AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084 && (ctx->master_display || ctx->light_meta)) {
+ AMFBuffer *hdrmeta_buffer = NULL;
+ res = ctx->amf_device_ctx->context->pVtbl->AllocBuffer(ctx->amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
+ if (res == AMF_OK) {
+ AMFHDRMetadata *hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
+
+ av_amf_display_mastering_meta_to_hdrmeta(ctx->master_display, hdrmeta);
+ av_amf_light_metadata_to_hdrmeta(ctx->light_meta, hdrmeta);
+ AMF_ASSIGN_PROPERTY_INTERFACE(res, surface, AMF_VIDEO_DECODER_HDR_METADATA, hdrmeta_buffer);
+ }
+ } else if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
+ res = surface->pVtbl->GetProperty(surface, AMF_VIDEO_DECODER_HDR_METADATA, &var);
+ if (res == AMF_NOT_FOUND) {
+ AMFBuffer *hdrmeta_buffer = NULL;
+ res = ctx->amf_device_ctx->context->pVtbl->AllocBuffer(ctx->amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
+ if (res == AMF_OK) {
+ AMFHDRMetadata *hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
+
+ if (av_amf_extract_hdr_metadata(frame, hdrmeta) == 0)
+ AMF_ASSIGN_PROPERTY_INTERFACE(res, surface, AMF_VIDEO_DECODER_HDR_METADATA, hdrmeta_buffer);
+ hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer);
+ }
+ }
+ }
+
if (frame->crop_left || frame->crop_right || frame->crop_top || frame->crop_bottom) {
size_t crop_x = frame->crop_left;
size_t crop_y = frame->crop_top;
diff --git a/libavfilter/vf_amf_common.h b/libavfilter/vf_amf_common.h
index d0a0214978..209ee966d8 100644
--- a/libavfilter/vf_amf_common.h
+++ b/libavfilter/vf_amf_common.h
@@ -24,6 +24,7 @@
#include "AMF/core/Surface.h"
#include "AMF/components/Component.h"
#include "libavutil/hwcontext_amf.h"
+#include "libavutil/mastering_display_metadata.h"
typedef struct AMFFilterContext {
const AVClass *class;
@@ -31,14 +32,22 @@ typedef struct AMFFilterContext {
int width, height;
enum AVPixelFormat format;
int scale_type;
+ int in_color_range;
+ int in_primaries;
+ int in_trc;
int color_profile;
- int color_range;
- int primaries;
- int trc;
+ int out_color_range;
+ int out_primaries;
+ int out_trc;
int fill;
int fill_color;
int keep_ratio;
+ char *disp_master;
+ char *max_cll;
+ AVMasteringDisplayMetadata *master_display;
+ AVContentLightMetadata *light_meta;
+
// HQScaler properties
int algorithm;
float sharpness;
diff --git a/libavfilter/vf_sr_amf.c b/libavfilter/vf_sr_amf.c
index 2179e81d2c..8f3ae7ed80 100644
--- a/libavfilter/vf_sr_amf.c
+++ b/libavfilter/vf_sr_amf.c
@@ -117,10 +117,13 @@ static int amf_filter_config_output(AVFilterLink *outlink)
AMF_ASSIGN_PROPERTY_BOOL(res, ctx->component, AMF_HQ_SCALER_FILL, ctx->fill);
AMF_ASSIGN_PROPERTY_BOOL(res, ctx->component, AMF_HQ_SCALER_KEEP_ASPECT_RATIO, ctx->keep_ratio);
// Setup default options to skip color conversion
+ ctx->in_color_range = AMF_COLOR_RANGE_UNDEFINED;
+ ctx->in_primaries = AMF_COLOR_PRIMARIES_UNDEFINED;
+ ctx->in_trc = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED;
ctx->color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
- ctx->color_range = AMF_COLOR_RANGE_UNDEFINED;
- ctx->primaries = AMF_COLOR_PRIMARIES_UNDEFINED;
- ctx->trc = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED;
+ ctx->out_color_range = AMF_COLOR_RANGE_UNDEFINED;
+ ctx->out_primaries = AMF_COLOR_PRIMARIES_UNDEFINED;
+ ctx->out_trc = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED;
res = ctx->component->pVtbl->Init(ctx->component, av_av_to_amf_format(in_format), inlink->w, inlink->h);
AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFHQScaler-Init() failed with error %d\n", res);
diff --git a/libavfilter/vf_vpp_amf.c b/libavfilter/vf_vpp_amf.c
index 78815551be..5baaa503c4 100644
--- a/libavfilter/vf_vpp_amf.c
+++ b/libavfilter/vf_vpp_amf.c
@@ -21,14 +21,9 @@
* VPP video filter with AMF hardware acceleration
*/
-#include <stdio.h>
-#include <string.h>
-
-#include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
+#include "libavutil/mem.h"
#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/time.h"
+#include "libavutil/internal.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_amf.h"
@@ -38,8 +33,6 @@
#include "vf_amf_common.h"
#include "avfilter.h"
-#include "formats.h"
-#include "video.h"
#include "scale_eval.h"
#include "avfilter_internal.h"
@@ -85,19 +78,26 @@ static int amf_filter_query_formats(AVFilterContext *avctx)
static int amf_filter_config_output(AVFilterLink *outlink)
{
- AVFilterContext *avctx = outlink->src;
- AVFilterLink *inlink = avctx->inputs[0];
- AMFFilterContext *ctx = avctx->priv;
+ AVFilterContext *avctx = outlink->src;
+ AVFilterLink *inlink = avctx->inputs[0];
AVHWFramesContext *hwframes_out = NULL;
+ AMFFilterContext *ctx = avctx->priv;
+ AMFBuffer *hdrmeta_buffer = NULL;
+ AMFHDRMetadata *hdrmeta = NULL;
AMFSize out_size;
- int err;
+ size_t size = 0;
+ int ret;
AMF_RESULT res;
enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM amf_color_profile;
enum AVPixelFormat in_format;
+ const int chroma_den = 50000;
+ const int luma_den = 10000;
+ const int total_max_cll_args = 2;
+ const int total_disp_meta_args = 10;
- err = amf_init_filter_config(outlink, &in_format);
- if (err < 0)
- return err;
+ ret = amf_init_filter_config(outlink, &in_format);
+ if (ret < 0)
+ return ret;
// FIXME: add checks whether we have HW context
hwframes_out = (AVHWFramesContext*)ctx->hwframes_out_ref->data;
res = ctx->amf_device_ctx->factory->pVtbl->CreateComponent(ctx->amf_device_ctx->factory, ctx->amf_device_ctx->context, AMFVideoConverter, &ctx->component);
@@ -118,21 +118,21 @@ static int amf_filter_config_output(AVFilterLink *outlink)
switch(ctx->color_profile) {
case AMF_VIDEO_CONVERTER_COLOR_PROFILE_601:
- if (ctx->color_range == AMF_COLOR_RANGE_FULL) {
+ if (ctx->out_color_range == AMF_COLOR_RANGE_FULL) {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
} else {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
}
break;
case AMF_VIDEO_CONVERTER_COLOR_PROFILE_709:
- if (ctx->color_range == AMF_COLOR_RANGE_FULL) {
+ if (ctx->out_color_range == AMF_COLOR_RANGE_FULL) {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
} else {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
}
break;
case AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020:
- if (ctx->color_range == AMF_COLOR_RANGE_FULL) {
+ if (ctx->out_color_range == AMF_COLOR_RANGE_FULL) {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
} else {
amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
@@ -143,20 +143,110 @@ static int amf_filter_config_output(AVFilterLink *outlink)
break;
}
+ if (ctx->in_color_range != AMF_COLOR_RANGE_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_INPUT_COLOR_RANGE, ctx->in_color_range);
+ }
+
+ if (ctx->in_primaries != AMF_COLOR_PRIMARIES_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_INPUT_COLOR_PRIMARIES, ctx->in_primaries);
+ }
+
+ if (ctx->in_trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_INPUT_TRANSFER_CHARACTERISTIC, ctx->in_trc);
+ }
+
+ if (ctx->disp_master) {
+ ctx->master_display = av_mastering_display_metadata_alloc();
+ if (!ctx->master_display)
+ return AVERROR(ENOMEM);
+
+ ret = sscanf_s(ctx->disp_master,
+ "G(%hu,%hu)B(%hu,%hu)R(%hu,%hu)WP(%hu,%hu)L(%u,%u)",
+ (uint16_t*)&ctx->master_display->display_primaries[1][0].num,
+ (uint16_t*)&ctx->master_display->display_primaries[1][1].num,
+ (uint16_t*)&ctx->master_display->display_primaries[2][0].num,
+ (uint16_t*)&ctx->master_display->display_primaries[2][1].num,
+ (uint16_t*)&ctx->master_display->display_primaries[0][0].num,
+ (uint16_t*)&ctx->master_display->display_primaries[0][1].num,
+ (uint16_t*)&ctx->master_display->white_point[0].num,
+ (uint16_t*)&ctx->master_display->white_point[1].num,
+ (unsigned*)&ctx->master_display->max_luminance.num,
+ (unsigned*)&ctx->master_display->min_luminance.num
+ );
+
+ if (ret != total_disp_meta_args) {
+ av_freep(&ctx->master_display);
+ av_log(avctx, AV_LOG_ERROR, "failed to parse mastering_display option\n");
+ return AVERROR(EINVAL);
+ }
+
+ ctx->master_display->display_primaries[1][0].den = chroma_den;
+ ctx->master_display->display_primaries[1][1].den = chroma_den;
+ ctx->master_display->display_primaries[2][0].den = chroma_den;
+ ctx->master_display->display_primaries[2][1].den = chroma_den;
+ ctx->master_display->display_primaries[0][0].den = chroma_den;
+ ctx->master_display->display_primaries[0][1].den = chroma_den;
+ ctx->master_display->white_point[0].den = chroma_den;
+ ctx->master_display->white_point[1].den = chroma_den;
+ ctx->master_display->max_luminance.den = luma_den;
+ ctx->master_display->min_luminance.den = luma_den;
+
+ ctx->master_display->has_primaries = 1;
+ ctx->master_display->has_luminance = 1;
+ }
+
+
+ if (ctx->max_cll) {
+ ctx->light_meta = av_content_light_metadata_alloc(&size);
+ if (!ctx->light_meta)
+ return AVERROR(ENOMEM);
+
+ ret = sscanf_s(ctx->max_cll,
+ "%hu,%hu",
+ (uint16_t*)&ctx->light_meta->MaxCLL,
+ (uint16_t*)&ctx->light_meta->MaxFALL
+ );
+
+ if (ret != total_max_cll_args) {
+ av_freep(ctx->light_meta);
+ ctx->light_meta = NULL;
+ av_log(avctx, AV_LOG_ERROR, "failed to parse max_cll option\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (ctx->light_meta || ctx->master_display) {
+ if (ctx->in_trc == AVCOL_TRC_SMPTEST2084) {
+ res = ctx->amf_device_ctx->context->pVtbl->AllocBuffer(ctx->amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
+ if (res == AMF_OK) {
+ hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
+
+ av_amf_display_mastering_meta_to_hdrmeta(ctx->master_display, hdrmeta);
+ av_amf_light_metadata_to_hdrmeta(ctx->light_meta, hdrmeta);
+
+ AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->component, AMF_VIDEO_CONVERTER_INPUT_HDR_METADATA, hdrmeta_buffer);
+
+ hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer);
+ }
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "master_display/max_cll options are applicable only if in_trc is set to SMPTE2084\n");
+ }
+ }
+
if (amf_color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN) {
AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_COLOR_PROFILE, amf_color_profile);
}
- if (ctx->color_range != AMF_COLOR_RANGE_UNDEFINED) {
- AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_COLOR_RANGE, ctx->color_range);
+ if (ctx->out_color_range != AMF_COLOR_RANGE_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_COLOR_RANGE, ctx->out_color_range);
}
- if (ctx->primaries != AMF_COLOR_PRIMARIES_UNDEFINED) {
- AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_COLOR_PRIMARIES, ctx->primaries);
+ if (ctx->out_primaries != AMF_COLOR_PRIMARIES_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_COLOR_PRIMARIES, ctx->out_primaries);
}
- if (ctx->trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED) {
- AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_TRANSFER_CHARACTERISTIC, ctx->trc);
+ if (ctx->out_trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED) {
+ AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_OUTPUT_TRANSFER_CHARACTERISTIC, ctx->out_trc);
}
res = ctx->component->pVtbl->Init(ctx->component, av_av_to_amf_format(in_format), inlink->w, inlink->h);
@@ -181,11 +271,13 @@ static const AVOption vpp_amf_options[] = {
{ "bt709", "BT.709", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709 }, 0, 0, FLAGS, "color_profile" },
{ "bt2020", "BT.2020", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020 }, 0, 0, FLAGS, "color_profile" },
- { "color_range", "Color range", OFFSET(color_range), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_RANGE_UNDEFINED }, AMF_COLOR_RANGE_UNDEFINED, AMF_COLOR_RANGE_FULL, FLAGS, "color_range" },
- { "studio", "Studio", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_RANGE_STUDIO }, 0, 0, FLAGS, "color_range" },
- { "full", "Full", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_RANGE_FULL }, 0, 0, FLAGS, "color_range" },
+ { "in_color_range", "Input color range", OFFSET(in_color_range), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_RANGE_UNDEFINED }, AMF_COLOR_RANGE_UNDEFINED, AMF_COLOR_RANGE_FULL, FLAGS, "color_range" },
+ { "out_color_range", "Output color range", OFFSET(out_color_range), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_RANGE_UNDEFINED }, AMF_COLOR_RANGE_UNDEFINED, AMF_COLOR_RANGE_FULL, FLAGS, "color_range" },
+ { "studio", "Studio", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_RANGE_STUDIO }, 0, 0, FLAGS, "color_range" },
+ { "full", "Full", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_RANGE_FULL }, 0, 0, FLAGS, "color_range" },
- { "primaries", "Output color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_PRIMARIES_UNDEFINED }, AMF_COLOR_PRIMARIES_UNDEFINED, AMF_COLOR_PRIMARIES_JEDEC_P22, FLAGS, "primaries" },
+ { "in_primaries", "Input color primaries", OFFSET(in_primaries), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_PRIMARIES_UNDEFINED }, AMF_COLOR_PRIMARIES_UNDEFINED, AMF_COLOR_PRIMARIES_JEDEC_P22, FLAGS, "primaries" },
+ { "out_primaries", "Output color primaries", OFFSET(out_primaries), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_PRIMARIES_UNDEFINED }, AMF_COLOR_PRIMARIES_UNDEFINED, AMF_COLOR_PRIMARIES_JEDEC_P22, FLAGS, "primaries" },
{ "bt709", "BT.709", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_PRIMARIES_BT709 }, 0, 0, FLAGS, "primaries" },
{ "bt470m", "BT.470M", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_PRIMARIES_BT470M }, 0, 0, FLAGS, "primaries" },
{ "bt470bg", "BT.470BG", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_PRIMARIES_BT470BG }, 0, 0, FLAGS, "primaries" },
@@ -198,7 +290,8 @@ static const AVOption vpp_amf_options[] = {
{ "smpte432", "SMPTE432", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_PRIMARIES_SMPTE432 }, 0, 0, FLAGS, "primaries" },
{ "jedec-p22", "JEDEC_P22", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_PRIMARIES_JEDEC_P22 }, 0, 0, FLAGS, "primaries" },
- { "trc", "Output transfer characteristics", OFFSET(trc), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED }, AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, AMF_COLOR_TRANSFER_CHARACTERISTIC_ARIB_STD_B67, FLAGS, "trc" },
+ { "in_trc", "Input transfer characteristics", OFFSET(in_trc), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED }, AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, AMF_COLOR_TRANSFER_CHARACTERISTIC_ARIB_STD_B67, FLAGS, "trc" },
+ { "out_trc", "Output transfer characteristics", OFFSET(out_trc), AV_OPT_TYPE_INT, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED }, AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, AMF_COLOR_TRANSFER_CHARACTERISTIC_ARIB_STD_B67, FLAGS, "trc" },
{ "bt709", "BT.709", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709 }, 0, 0, FLAGS, "trc" },
{ "gamma22", "GAMMA22", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_GAMMA22 }, 0, 0, FLAGS, "trc" },
{ "gamma28", "GAMMA28", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_GAMMA28 }, 0, 0, FLAGS, "trc" },
@@ -223,6 +316,13 @@ static const AVOption vpp_amf_options[] = {
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
+ { "master_display",
+ "set SMPTE2084 mastering display color volume info using libx265-style parameter string (G(%hu,%hu)B(%hu,%hu)R(%hu,%hu)WP(%hu,%hu)L(%u,%u)).",
+ OFFSET(disp_master), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS
+ },
+
+ { "max_cll", "set SMPTE2084 Max CLL and Max FALL values using libx265-style parameter string (%hu,%hu)", OFFSET(max_cll), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
+
{ NULL },
};
diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c
index 57bf08bc65..480fdb6391 100644
--- a/libavutil/hwcontext_amf.c
+++ b/libavutil/hwcontext_amf.c
@@ -16,12 +16,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "mem.h"
#include "buffer.h"
-#include "common.h"
+#include "pixfmt.h"
+#include "pixdesc.h"
+#include "imgutils.h"
#include "hwcontext.h"
#include "hwcontext_amf.h"
#include "hwcontext_internal.h"
#include "hwcontext_amf_internal.h"
+
+#include "libavutil/thread.h"
+#include "libavutil/avassert.h"
+
+#include <AMF/core/Surface.h>
+#include <AMF/core/Trace.h>
+
#if CONFIG_VULKAN
#include "hwcontext_vulkan.h"
#endif
@@ -35,14 +45,6 @@
#define COBJMACROS
#include "libavutil/hwcontext_dxva2.h"
#endif
-#include "mem.h"
-#include "pixdesc.h"
-#include "pixfmt.h"
-#include "imgutils.h"
-#include "thread.h"
-#include "libavutil/avassert.h"
-#include <AMF/core/Surface.h>
-#include <AMF/core/Trace.h>
#ifdef _WIN32
#include "compat/w32dlfcn.h"
#else
@@ -150,6 +152,157 @@ enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt)
return AV_PIX_FMT_NONE;
}
+enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM av_amf_get_color_profile(enum AVColorRange color_range, enum AVColorSpace color_space)
+{
+ switch (color_space) {
+ case AVCOL_SPC_SMPTE170M:
+ if (color_range == AVCOL_RANGE_JPEG) {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
+ } else {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
+ }
+ break;
+ case AVCOL_SPC_BT709:
+ if (color_range == AVCOL_RANGE_JPEG) {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
+ } else {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
+ }
+ break;
+ case AVCOL_SPC_BT2020_NCL:
+ case AVCOL_SPC_BT2020_CL:
+ if (color_range == AVCOL_RANGE_JPEG) {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
+ } else {
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
+ }
+ break;
+
+ default:
+ return AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
+ }
+}
+
+int av_amf_display_mastering_meta_to_hdrmeta(const AVMasteringDisplayMetadata *display_meta, AMFHDRMetadata *hdrmeta)
+{
+ if (!display_meta || !hdrmeta)
+ return AVERROR(EINVAL);
+
+ if (display_meta->has_luminance) {
+ const unsigned int luma_den = 10000;
+ hdrmeta->maxMasteringLuminance =
+ (amf_uint32)(luma_den * av_q2d(display_meta->max_luminance));
+ hdrmeta->minMasteringLuminance =
+ FFMIN((amf_uint32)(luma_den * av_q2d(display_meta->min_luminance)), hdrmeta->maxMasteringLuminance);
+ }
+
+ if (display_meta->has_primaries) {
+ const unsigned int chroma_den = 50000;
+ hdrmeta->redPrimary[0] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][0])), chroma_den);
+ hdrmeta->redPrimary[1] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][1])), chroma_den);
+ hdrmeta->greenPrimary[0] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][0])), chroma_den);
+ hdrmeta->greenPrimary[1] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][1])), chroma_den);
+ hdrmeta->bluePrimary[0] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][0])), chroma_den);
+ hdrmeta->bluePrimary[1] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][1])), chroma_den);
+ hdrmeta->whitePoint[0] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[0])), chroma_den);
+ hdrmeta->whitePoint[1] =
+ FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[1])), chroma_den);
+ }
+
+ return 0;
+}
+
+int av_amf_light_metadata_to_hdrmeta(const AVContentLightMetadata *light_meta, AMFHDRMetadata *hdrmeta)
+{
+ if (!light_meta || !hdrmeta)
+ return AVERROR(EINVAL);
+
+ hdrmeta->maxContentLightLevel = (amf_uint16)light_meta->MaxCLL;
+ hdrmeta->maxFrameAverageLightLevel = (amf_uint16)light_meta->MaxFALL;
+
+ return 0;
+}
+
+int av_amf_extract_hdr_metadata(const AVFrame *frame, AMFHDRMetadata *hdrmeta)
+{
+ AVFrameSideData *sidedata;
+
+ if (!frame || !hdrmeta)
+ return AVERROR(EINVAL);
+
+ sidedata = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
+ if (!sidedata)
+ return AVERROR(ENODATA);
+
+ if (av_amf_display_mastering_meta_to_hdrmeta((AVMasteringDisplayMetadata *)sidedata->data, hdrmeta) != 0)
+ return AVERROR(ENODATA);
+
+ sidedata = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
+ if (sidedata)
+ av_amf_light_metadata_to_hdrmeta((AVContentLightMetadata *)sidedata->data, hdrmeta);
+
+ return 0;
+
+}
+
+int av_amf_attach_hdr_metadata(AVFrame *frame, const AMFHDRMetadata *hdrmeta) {
+ if (!hdrmeta || !frame)
+ return AVERROR(EINVAL);
+
+ AVMasteringDisplayMetadata *mastering =
+ av_mastering_display_metadata_create_side_data(frame);
+ const int chroma_den = 50000;
+ const int luma_den = 10000;
+
+ if (!mastering)
+ return AVERROR(ENOMEM);
+
+ mastering->display_primaries[0][0] =
+ av_make_q(hdrmeta->redPrimary[0], chroma_den);
+ mastering->display_primaries[0][1] =
+ av_make_q(hdrmeta->redPrimary[1], chroma_den);
+
+ mastering->display_primaries[1][0] =
+ av_make_q(hdrmeta->greenPrimary[0], chroma_den);
+ mastering->display_primaries[1][1] =
+ av_make_q(hdrmeta->greenPrimary[1], chroma_den);
+
+ mastering->display_primaries[2][0] =
+ av_make_q(hdrmeta->bluePrimary[0], chroma_den);
+ mastering->display_primaries[2][1] =
+ av_make_q(hdrmeta->bluePrimary[1], chroma_den);
+
+ mastering->white_point[0] = av_make_q(hdrmeta->whitePoint[0], chroma_den);
+ mastering->white_point[1] = av_make_q(hdrmeta->whitePoint[1], chroma_den);
+
+ mastering->max_luminance =
+ av_make_q(hdrmeta->maxMasteringLuminance, luma_den);
+ mastering->min_luminance =
+ av_make_q(hdrmeta->maxMasteringLuminance, luma_den);
+
+ mastering->has_luminance = 1;
+ mastering->has_primaries = 1;
+ if (hdrmeta->maxContentLightLevel) {
+ AVContentLightMetadata *light =
+ av_content_light_metadata_create_side_data(frame);
+
+ if (!light)
+ return AVERROR(ENOMEM);
+
+ light->MaxCLL = hdrmeta->maxContentLightLevel;
+ light->MaxFALL = hdrmeta->maxFrameAverageLightLevel;
+ }
+
+ return 0;
+}
+
static const enum AVPixelFormat supported_formats[] = {
AV_PIX_FMT_NV12,
AV_PIX_FMT_YUV420P,
@@ -433,7 +586,7 @@ static int amf_device_init(AVHWDeviceContext *ctx)
if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
if (res == AMF_NOT_SUPPORTED)
av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
- else
+ else
av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
return AVERROR(ENOSYS);
}
@@ -462,7 +615,7 @@ static int amf_load_library(AVAMFDeviceContext* amf_ctx, void* avcl)
version_fun = (AMFQueryVersion_Fn)dlsym(amf_ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
AMF_RETURN_IF_FALSE(avcl, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
- res = version_fun(&amf_ctx->version);
+ res = version_fun((unsigned long long*)&amf_ctx->version);
AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
res = init_fun(AMF_FULL_VERSION, &amf_ctx->factory);
AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
diff --git a/libavutil/hwcontext_amf.h b/libavutil/hwcontext_amf.h
index 6f2cabc878..918eec97b8 100644
--- a/libavutil/hwcontext_amf.h
+++ b/libavutil/hwcontext_amf.h
@@ -26,6 +26,8 @@
#include <AMF/core/Context.h>
#include <AMF/core/Trace.h>
#include <AMF/core/Debug.h>
+#include <AMF/components/ColorSpace.h>
+#include "libavutil/mastering_display_metadata.h"
/**
* This struct is allocated as AVHWDeviceContext.hwctx
@@ -47,4 +49,10 @@ typedef struct AVAMFDeviceContext {
enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt);
enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt);
+enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM av_amf_get_color_profile(enum AVColorRange color_range, enum AVColorSpace color_space);
+int av_amf_display_mastering_meta_to_hdrmeta(const AVMasteringDisplayMetadata *display_meta, AMFHDRMetadata *hdrmeta);
+int av_amf_light_metadata_to_hdrmeta(const AVContentLightMetadata *light_meta, AMFHDRMetadata *hdrmeta);
+int av_amf_extract_hdr_metadata(const AVFrame *frame, AMFHDRMetadata *hdrmeta);
+int av_amf_attach_hdr_metadata(AVFrame *frame, const AMFHDRMetadata *hdrmeta);
+
#endif /* AVUTIL_HWCONTEXT_AMF_H */
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
reply other threads:[~2026-02-20 12:05 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=177158905182.25.7312536821130965598@29965ddac10e \
--to=ffmpeg-devel@ffmpeg.org \
--cc=code@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git