From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 85C214E396 for ; Fri, 20 Feb 2026 12:05:10 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'zk9GW0q6eg43R0HVwhvVl8izFjzmvcZ9ec+eE6tsJR0=', expected b'1qUfmYfg5am6+A2LRWmK3BpCpnAxzJ/k6heLp2Iv/eU=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1771589073; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=zk9GW0q6eg43R0HVwhvVl8izFjzmvcZ9ec+eE6tsJR0=; b=gKFQ5ZogPPfD1qLdT72AFyemMS2kNJQgBAlIst+hOODz9fAHHZU6tVcHm9bOZNwa7pcat Xp03uOWrTtnSWL+goCdCsQIjs5hc3DjZFg/tyow/5+t6WhrSfoMO0nAuKJueJ6TlezjzQw7 RGXAwk3mMgfGBKehcN5H8yZvYmCzzg/41Qv7LSJfbZAfGKu2dauXJTdaA/yzjE2TIRWoHa9 XxehTDdBUSj9yKe8SaGyLlf0MPnTpFJQC3jWAquSF9C7cOnQSCBG/dOqqJ3LdhMNz0kumf4 +M+1llf3l6yf7bTxPf4yPd8MaNdaLEP2WouYb46lkhdullp1BWVixQzH62+Q== Received: from [172.18.0.3] (unknown [172.18.0.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 14BE469126C; Fri, 20 Feb 2026 14:04:33 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1771589060; b=kAPGNsgE1B+iEg4fMM2Q2d7wJ78vr/jA3Ityio3OyqjtkCmrrBqger3TzPDt5BJk2E9K5 en/GvuzAwtUa7DHQfJfbw/wyoqCMHzThPMk9EMzrxIsvE/RzHBKJDDRX0oQ7nhwpYq/42f8 b7R0sW9JRrYBBLhuMWz7jYNMdICyqi4hX/7mi0Y4O5SVrpPDMC3tE8C7E56uLGELWrGZ8pz ySRA/RrLWFBGMgcyGosgyZo6nxNbJ9yXW5wLuLTKRahKNE8Sufg1Brqwv6weQmbv6tr0QXR ZSm/3phIgefUchwUk7u7WKGCSX4qkMPYaqf07ih27hWnRiwBvuHMGTTS/SkQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1771589060; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=goRLJY9pNyO7BpIeYWJbupnH9NSW9t88wQwNDnsZ5+Q=; b=FsIZFum3MkGY18HQKCmJegNSCmv5EHQj3SBSI/ZfmjzmjqfgXjwHDtnI3ExyEoUo9V+dS vY+qIQeVi7kM2AjULkoYW7myy7lVveajLffju5bTjSrhkRcA2Y9e8yYT8WzpK2C1FQveYoT YyEj6+rSeCd0e4ybx5B/S2a2CGjqCOgKV3aumvjJMkLqGz75fXdf/cDtxKFlD+cMqYUR55G G/chp0FUcIY5Gk4sRvUDFpBSn6WH7jVHUgbsiqxoGFS8fO8ov8BTXsFy/nEYihvNG6rGufE IxJfQnSfTwGdgFTRFKqyHnU9UQiN1HeO8xEVk0KPYkc3YPGc8AGCcEurmOng== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1771589051; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=1qUfmYfg5am6+A2LRWmK3BpCpnAxzJ/k6heLp2Iv/eU=; b=1SJcT3WgoWMsv+snqOP0bC3a3W6T+vkJOxRdWfgilB1x7Oy+uwoQ+xKYrb7pe16Pj6zIG dpI87+qofPRAYPpJ9w+3cxkaLSMAEaBtsMQey+mlERX5Le0+Mqqz7rQaOLJOHZhW4vIc243 tYYXrQtyhyf1U2v0Hn6qx+DghVwHuVxV9rzpenKpBTmyysaTsqmj7m0DKUbJzAvMZ/SjBKz yS2BOX8byJgQH0MAmcJTDRQFgOJbgix2/Nszdh2NemEkPc486oLNdU87Qnxd6766hQPSe/1 XihtTN+F7/fz800GTL7+pf4rs+44SrCwldb+tBx/HLIK2iHrhuSMtaWA/OVQ== MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Fri, 20 Feb 2026 12:04:11 -0000 Message-ID: <177158905182.25.7312536821130965598@29965ddac10e> Message-ID-Hash: NRARQ2P46UWUAWEVJFANADRLJBDQBWRD X-Message-ID-Hash: NRARQ2P46UWUAWEVJFANADRLJBDQBWRD X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PR] avfilter/vf_vpp_amf: Extend AMF Color Converter HDR capabilities (PR #21811) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: DmitriiGershenkop via ffmpeg-devel Cc: DmitriiGershenkop Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: 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 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 : - 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 #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 -#include - -#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 +#include + #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 -#include #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 #include #include +#include +#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