From 48b5fd5a3ba115b4bf9dc84c17d28d8febfd9e99 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:38:40 -0800 Subject: [PATCH 01/12] obs-ffmpeg: Update AMF SDK for AV1 support --- .../AMF/include/components/Component.h | 1 + .../AMF/include/components/CursorCapture.h | 1 + .../AMF/include/components/FFMPEGFileMuxer.h | 1 + .../AMF/include/components/HQScaler.h | 3 + .../AMF/include/components/PreAnalysis.h | 45 ++- .../AMF/include/components/VQEnhancer.h | 47 +++ .../AMF/include/components/VideoDecoderUVD.h | 3 +- .../AMF/include/components/VideoEncoderAV1.h | 292 ++++++++++++++++++ .../AMF/include/components/VideoEncoderHEVC.h | 15 +- .../AMF/include/components/VideoEncoderVCE.h | 5 +- 10 files changed, 397 insertions(+), 16 deletions(-) create mode 100644 plugins/obs-ffmpeg/external/AMF/include/components/VQEnhancer.h create mode 100644 plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderAV1.h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/Component.h b/plugins/obs-ffmpeg/external/AMF/include/components/Component.h index 2cd9fa5e4..5293b8f4e 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/Component.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/Component.h @@ -414,6 +414,7 @@ typedef enum AMF_STREAM_CODEC_ID_ENUM // matched codecs from VideoDecoxcderU AMF_STREAM_CODEC_ID_VP9 = 11, // AMFVideoDecoderHW_VP9 AMF_STREAM_CODEC_ID_VP9_10BIT = 12, // AMFVideoDecoderHW_VP9_10BIT AMF_STREAM_CODEC_ID_AV1 = 13, // AMFVideoDecoderHW_AV1 + AMF_STREAM_CODEC_ID_AV1_12BIT = 14, // AMFVideoDecoderHW_AV1_12BIT } AMF_STREAM_CODEC_ID_ENUM; // common stream properties diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h b/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h index 8b071c99a..e21c16909 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/CursorCapture.h @@ -43,6 +43,7 @@ namespace amf class AMFCursorCapture : public AMFInterface { public: + AMF_DECLARE_IID(0x166efa1a, 0x19b8, 0x42f2, 0x86, 0x0f, 0x56, 0x69, 0xca, 0x7a, 0x85, 0x4c) virtual AMF_RESULT AMF_STD_CALL AcquireCursor(amf::AMFSurface** pSurface) = 0; virtual AMF_RESULT AMF_STD_CALL Reset() = 0; }; diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h b/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h index e8adf2bbc..a44676095 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/FFMPEGFileMuxer.h @@ -49,5 +49,6 @@ #define FFMPEG_MUXER_ENABLE_AUDIO L"EnableAudio" // bool (default = false) #define FFMPEG_MUXER_CURRENT_TIME_INTERFACE L"CurrentTimeInterface" #define FFMPEG_MUXER_VIDEO_ROTATION L"VideoRotation" // amf_int64 (0, 90, 180, 270, default = 0) +#define FFMPEG_MUXER_USAGE_IS_TRIM L"UsageIsTrim" // bool (default = false) #endif //#ifndef AMF_FileMuxerFFMPEG_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h b/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h index 592dfb56a..207d87b49 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/HQScaler.h @@ -44,6 +44,8 @@ enum AMF_HQ_SCALER_ALGORITHM_ENUM AMF_HQ_SCALER_ALGORITHM_BILINEAR = 0, AMF_HQ_SCALER_ALGORITHM_BICUBIC = 1, AMF_HQ_SCALER_ALGORITHM_FSR = 2, + AMF_HQ_SCALER_ALGORITHM_POINT = 3, + AMF_HQ_SCALER_ALGORITHM_FSR1_1 = 4, }; @@ -60,5 +62,6 @@ enum AMF_HQ_SCALER_ALGORITHM_ENUM #define AMF_HQ_SCALER_FILL_COLOR L"FillColor" // AMFColor #define AMF_HQ_SCALER_FROM_SRGB L"FromSRGB" // bool (default=true) Convert to SRGB. +#define AMF_HQ_SCALER_SHARPNESS L"HQScalerSharpness" // Float in the range of [0.0, 2.0] #endif //#ifndef AMFHQScaler_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h b/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h index 2ab817f78..51e8da662 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/PreAnalysis.h @@ -1,4 +1,4 @@ -// +// // Notice Regarding Standards. AMD does not provide a license or sublicense to // any Intellectual Property Rights relating to any standards, including but not // limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4; @@ -6,9 +6,9 @@ // (collectively, the "Media Technologies"). For clarity, you will pay any // royalties due for such third party technologies, which may include the Media // Technologies that are owed as a result of AMD providing the Software to you. -// -// MIT license -// +// +// MIT license +// // Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -48,7 +48,7 @@ enum AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_ENUM enum AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_ENUM -{ +{ AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW = 0, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM = 1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH = 2 @@ -69,6 +69,26 @@ enum AMF_PA_CAQ_STRENGTH_ENUM AMF_PA_CAQ_STRENGTH_HIGH = 2 }; +// Perceptual adaptive quantization mode +enum AMF_PA_PAQ_MODE_ENUM +{ + AMF_PA_PAQ_MODE_NONE = 0, + AMF_PA_PAQ_MODE_CAQ = 1 +}; + +// Temporal adaptive quantization mode +enum AMF_PA_TAQ_MODE_ENUM +{ + AMF_PA_TAQ_MODE_NONE = 0, + AMF_PA_TAQ_MODE_1 = 1, + AMF_PA_TAQ_MODE_2 = 2 +}; + +enum AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_ENUM +{ + AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE = 0, //default + AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO = 1 +}; // PA object properties @@ -77,17 +97,19 @@ enum AMF_PA_CAQ_STRENGTH_ENUM #define AMF_PA_SCENE_CHANGE_DETECTION_ENABLE L"PASceneChangeDetectionEnable" // bool (default : True) - Enable Scene Change Detection GPU algorithm #define AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY L"PASceneChangeDetectionSensitivity" // AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_ENUM (default : Medium) - Scene Change Detection Sensitivity -#define AMF_PA_STATIC_SCENE_DETECTION_ENABLE L"PAStaticSceneDetectionEnable" // bool (default : True) - Enable Skip Detection GPU algorithm +#define AMF_PA_STATIC_SCENE_DETECTION_ENABLE L"PAStaticSceneDetectionEnable" // bool (default : False) - Enable Skip Detection GPU algorithm #define AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY L"PAStaticSceneDetectionSensitivity" // AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_ENUM (default : High) - Allowable absolute difference between pixels (sample counts) #define AMF_PA_FRAME_SAD_ENABLE L"PAFrameSadEnable" // bool (default : True) - Enable Frame SAD algorithm #define AMF_PA_ACTIVITY_TYPE L"PAActivityType" // AMF_PA_ACTIVITY_TYPE_ENUM (default : Calculate on Y) - Block activity calculation mode -#define AMF_PA_LTR_ENABLE L"PALongTermReferenceEnable" // bool (default : True) - Enable Automatic Long Term Reference frame management - - +#define AMF_PA_LTR_ENABLE L"PALongTermReferenceEnable" // bool (default : False) - Enable Automatic Long Term Reference frame management +#define AMF_PA_LOOKAHEAD_BUFFER_DEPTH L"PALookAheadBufferDepth" // amf_uint64 (default : 0) Values: [0, MAX_LOOKAHEAD_DEPTH] - PA lookahead buffer size +#define AMF_PA_PAQ_MODE L"PAPerceptualAQMode" // AMF_PA_PAQ_MODE_ENUM (default : AMF_PA_PAQ_MODE_NONE) - Perceptual AQ mode +#define AMF_PA_TAQ_MODE L"PATemporalAQMode" // AMF_PA_TAQ_MODE_ENUM (default: AMF_PA_TAQ_MODE_NONE) - Temporal AQ mode +#define AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE L"PAHighMotionQualityBoostMode" // AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_ENUM (default: None) - High motion quality boost mode /////////////////////////////////////////// -// the following properties are available -// only through the Encoder - trying to +// the following properties are available +// only through the Encoder - trying to // access/set them when PA is standalone // will fail @@ -107,4 +129,5 @@ enum AMF_PA_CAQ_STRENGTH_ENUM #define AMF_PA_SCENE_CHANGE_DETECT L"PASceneChangeDetect" // bool - True/False - available if AMF_PA_SCENE_CHANGE_DETECTION_ENABLE was set to True #define AMF_PA_STATIC_SCENE_DETECT L"PAStaticSceneDetect" // bool - True/False - available if AMF_PA_STATIC_SCENE_DETECTION_ENABLE was set to True + #endif //#ifndef AMFPreAnalysis_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/VQEnhancer.h b/plugins/obs-ffmpeg/external/AMF/include/components/VQEnhancer.h new file mode 100644 index 000000000..1ea7b2ec9 --- /dev/null +++ b/plugins/obs-ffmpeg/external/AMF/include/components/VQEnhancer.h @@ -0,0 +1,47 @@ +// +// Notice Regarding Standards. AMD does not provide a license or sublicense to +// any Intellectual Property Rights relating to any standards, including but not +// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4; +// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3 +// (collectively, the "Media Technologies"). For clarity, you will pay any +// royalties due for such third party technologies, which may include the Media +// Technologies that are owed as a result of AMD providing the Software to you. +// +// MIT license +// +// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#ifndef AMFVQEnhancer_h +#define AMFVQEnhancer_h + +#pragma once + +#define VE_FCR_DEFAULT_ATTENUATION 0.1 + +#define AMFVQEnhancer L"AMFVQEnhancer" + +#define AMF_VIDEO_ENHANCER_ENGINE_TYPE L"AMF_VIDEI_ENHANCER_ENGINE_TYPE" // AMF_MEMORY_TYPE (DX11, DX12, OPENCL, VULKAN default : DX11)" - determines how the object is initialized and what kernels to use +#define AMF_VIDEO_ENHANCER_OUTPUT_SIZE L"AMF_VIDEO_ENHANCER_OUTPUT_SIZE" // AMFSize +#define AMF_VE_FCR_ATTENUATION L"AMF_VE_FCR_ATTENUATION" // Float in the range of [0.02, 0.4], default : 0.1 +#define AMF_VE_FCR_RADIUS L"AMF_VE_FCR_RADIUS" // int in the range of [1, 4] + +#endif //#ifndef AMFVQEnhancer_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h b/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h index 14ca91db1..eb28c29eb 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/VideoDecoderUVD.h @@ -53,6 +53,7 @@ #define AMFVideoDecoderHW_VP9 L"AMFVideoDecoderHW_VP9" #define AMFVideoDecoderHW_VP9_10BIT L"AMFVideoDecoderHW_VP9_10BIT" #define AMFVideoDecoderHW_AV1 L"AMFVideoDecoderHW_AV1" +#define AMFVideoDecoderHW_AV1_12BIT L"AMFVideoDecoderHW_AV1_12BIT" enum AMF_VIDEO_DECODER_MODE_ENUM { @@ -108,6 +109,7 @@ enum AMF_TIMESTAMP_MODE_ENUM #define AMF_VIDEO_DECODER_OUTPUT_COLOR_PRIMARIES L"OutputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 7.1 See ColorSpace.h for enum #define AMF_VIDEO_DECODER_OUTPUT_HDR_METADATA L"OutHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL +#define AMF_VIDEO_DECODER_LOW_LATENCY L"LowLatencyDecode" // amf_bool; default = false; true = low latency decode, false = regular decode #if defined(__ANDROID__) #define AMF_VIDEO_DECODER_NATIVEWINDOW L"AndroidNativeWindow" // amf_int64; default = 0; pointer to native window @@ -118,5 +120,4 @@ enum AMF_TIMESTAMP_MODE_ENUM #define AMF_VIDEO_DECODER_NATIVEWINDOW L"AppleNativeWindow" // amf_int64; default = 0; pointer to native window #endif //__APPLE__ - #endif //#ifndef AMF_VideoDecoderUVD_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderAV1.h b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderAV1.h new file mode 100644 index 000000000..e02803bbd --- /dev/null +++ b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderAV1.h @@ -0,0 +1,292 @@ +// +// Copyright (c) 2021-2022 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +//------------------------------------------------------------------------------------------------- +// VideoEncoderHW_AV1 interface declaration +//------------------------------------------------------------------------------------------------- + +#ifndef AMF_VideoEncoderAV1_h +#define AMF_VideoEncoderAV1_h +#pragma once + +#include "Component.h" +#include "ColorSpace.h" +#include "PreAnalysis.h" + +#define AMFVideoEncoder_AV1 L"AMFVideoEncoderHW_AV1" + +enum AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_NONE = 0, // No encoding latency requirement. Encoder will balance encoding time and power consumption. + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_POWER_SAVING_REAL_TIME = 1, // Try the best to finish encoding a frame within 1/framerate sec. This mode may cause more power consumption + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_REAL_TIME = 2, // Try the best to finish encoding a frame within 1/(2 x framerate) sec. This mode will cause more power consumption than POWER_SAVING_REAL_TIME + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY = 3 // Encoding as fast as possible. This mode causes highest power consumption. +}; + +enum AMF_VIDEO_ENCODER_AV1_USAGE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING = 0, + AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM +{ + AMF_VIDEO_ENCODER_AV1_LEVEL_2_0 = 0, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_1 = 1, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_2 = 2, + AMF_VIDEO_ENCODER_AV1_LEVEL_2_3 = 3, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_0 = 4, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_1 = 5, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_2 = 6, + AMF_VIDEO_ENCODER_AV1_LEVEL_3_3 = 7, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_0 = 8, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_1 = 9, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_2 = 10, + AMF_VIDEO_ENCODER_AV1_LEVEL_4_3 = 11, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_0 = 12, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_1 = 13, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_2 = 14, + AMF_VIDEO_ENCODER_AV1_LEVEL_5_3 = 15, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_0 = 16, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_1 = 17, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_2 = 18, + AMF_VIDEO_ENCODER_AV1_LEVEL_6_3 = 19, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_0 = 20, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_1 = 21, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_2 = 22, + AMF_VIDEO_ENCODER_AV1_LEVEL_7_3 = 23 +}; + +enum AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM +{ + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN = -1, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP = 0, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR = 1, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR = 2, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR = 3, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR = 4, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR = 5, + AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR = 6 +}; + +enum AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY = 1, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_1080P_CODED_1082 = 2, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS = 3 +}; + +enum AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY = 1, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY = 2, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_SWITCH = 3, + AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_SHOW_EXISTING = 4 +}; + +enum AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY = 0, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTRA_ONLY = 1, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTER = 2, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SWITCH = 3, + AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SHOW_EXISTING = 4 +}; + +enum AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_ENUM +{ + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY = 0, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY = 30, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED = 70, + AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED = 100 +}; + +enum AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_GOP_ALIGNED = 1, + AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED = 2 +}; + +enum AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_FIXED_INTERVAL = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_CDEF_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_CDEF_DISABLE = 0, + AMF_VIDEO_ENCODER_AV1_CDEF_ENABLE_DEFAULT = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_DISABLE = 0, + AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENABLE_DEFAULT = 1 +}; + +enum AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE = 0, + AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ = 1 // Content adaptive quantization mode +}; + +enum AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE_ENUM +{ + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__DISABLED = 0, + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__GOP_ALIGNED = 1, + AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__CONTINUOUS = 2 +}; + + +// *** Static properties - can be set only before Init() *** + +// Encoder Engine Settings +#define AMF_VIDEO_ENCODER_AV1_ENCODER_INSTANCE_INDEX L"Av1EncoderInstanceIndex" // amf_int64; default = 0; selected HW instance idx. The number of instances is queried by using AMF_VIDEO_ENCODER_AV1_CAP_NUM_OF_HW_INSTANCES +#define AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE L"Av1EncodingLatencyMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_ENUM); default = depends on USAGE; The encoding latency mode. +#define AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT L"Av1QueryTimeout" // amf_int64; default = 0 (no wait); timeout for QueryOutput call in ms. + +// Usage Settings +#define AMF_VIDEO_ENCODER_AV1_USAGE L"Av1Usage" // amf_int64(AMF_VIDEO_ENCODER_AV1_USAGE_ENUM); default = N/A; Encoder usage. fully configures parameter set. + +// Session Configuration +#define AMF_VIDEO_ENCODER_AV1_FRAMESIZE L"Av1FrameSize" // AMFSize; default = 0,0; Frame size +#define AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH L"Av1ColorBitDepth" // amf_int64(AMF_COLOR_BIT_DEPTH_ENUM); default = AMF_COLOR_BIT_DEPTH_8 +#define AMF_VIDEO_ENCODER_AV1_PROFILE L"Av1Profile" // amf_int64(AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM) ; default = depends on USAGE; the codec profile of the coded bitstream +#define AMF_VIDEO_ENCODER_AV1_LEVEL L"Av1Level" // amf_int64 (AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM); default = depends on USAGE; the codec level of the coded bitstream +#define AMF_VIDEO_ENCODER_AV1_TILES_PER_FRAME L"Av1NumTilesPerFrame" // amf_int64; default = 1; Number of tiles Per Frame. This is treated as suggestion. The actual number of tiles might be different due to compliance or encoder limitation. +#define AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET L"Av1QualityPreset" // amf_int64(AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_ENUM); default = depends on USAGE; Quality Preset + +// Codec Configuration +#define AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS L"Av1ScreenContentTools" // bool; default = depends on USAGE; If true, allow enabling screen content tools by AMF_VIDEO_ENCODER_AV1_PALETTE_MODE_ENABLE and AMF_VIDEO_ENCODER_AV1_FORCE_INTEGER_MV; if false, all screen content tools are disabled. +#define AMF_VIDEO_ENCODER_AV1_ORDER_HINT L"Av1OrderHint" // bool; default = depends on USAGE; If true, code order hint; if false, don't code order hint +#define AMF_VIDEO_ENCODER_AV1_FRAME_ID L"Av1FrameId" // bool; default = depends on USAGE; If true, code frame id; if false, don't code frame id +#define AMF_VIDEO_ENCODER_AV1_TILE_GROUP_OBU L"Av1TileGroupObu" // bool; default = depends on USAGE; If true, code FrameHeaderObu + TileGroupObu and each TileGroupObu contains one tile; if false, code FrameObu. +#define AMF_VIDEO_ENCODER_AV1_CDEF_MODE L"Av1CdefMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_CDEF_MODE_ENUM); default = depends on USAGE; Cdef mode +#define AMF_VIDEO_ENCODER_AV1_ERROR_RESILIENT_MODE L"Av1ErrorResilientMode" // bool; default = depends on USAGE; If true, enable error resilient mode; if false, disable error resilient mode + +// Rate Control and Quality Enhancement +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD L"Av1RateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method +#define AMF_VIDEO_ENCODER_AV1_QVBR_QUALITY_LEVEL L"Av1QvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 +#define AMF_VIDEO_ENCODER_AV1_INITIAL_VBV_BUFFER_FULLNESS L"Av1InitialVBVBufferFullness" // amf_int64; default = depends on USAGE; Initial VBV Buffer Fullness 0=0% 64=100% + +// Alignment Mode Configuration +#define AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE L"Av1AlignmentMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM); default = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY; Alignment Mode. + +#define AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE L"Av1EnablePreAnalysis" // bool; default = depends on USAGE; If true, enables the pre-analysis module. Refer to AMF Video PreAnalysis API reference for more details. If false, disable the pre-analysis module. +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE L"Av1RateControlPreEncode" // bool; default = depends on USAGE; If true, enables pre-encode assist in rate control; if false, disables pre-encode assist in rate control. +#define AMF_VIDEO_ENCODER_AV1_HIGH_MOTION_QUALITY_BOOST L"Av1HighMotionQualityBoost" // bool; default = depends on USAGE; If true, enable high motion quality boost mode; if false, disable high motion quality boost mode. +#define AMF_VIDEO_ENCODER_AV1_AQ_MODE L"Av1AQMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM); default = depends on USAGE; AQ mode + +// Picture Management Configuration +#define AMF_VIDEO_ENCODER_AV1_MAX_NUM_TEMPORAL_LAYERS L"Av1MaxNumOfTemporalLayers" // amf_int64; default = depends on USAGE; Max number of temporal layers might be enabled. The maximum value can be queried from AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_TEMPORAL_LAYERS +#define AMF_VIDEO_ENCODER_AV1_MAX_LTR_FRAMES L"Av1MaxNumLTRFrames" // amf_int64; default = depends on USAGE; Max number of LTR frames. The maximum value can be queried from AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_LTR_FRAMES +#define AMF_VIDEO_ENCODER_AV1_MAX_NUM_REFRAMES L"Av1MaxNumRefFrames" // amf_int64; default = 1; Maximum number of reference frames + +// color conversion +#define AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA L"Av1InHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL + +// Miscellaneous +#define AMF_VIDEO_ENCODER_AV1_EXTRA_DATA L"Av1ExtraData" // AMFInterface* - > AMFBuffer*; buffer to retrieve coded sequence header + + +// *** Dynamic properties - can be set anytime *** + +// Codec Configuration +#define AMF_VIDEO_ENCODER_AV1_PALETTE_MODE L"Av1PaletteMode" // bool; default = depends on USAGE; If true, enable palette mode; if false, disable palette mode. Valid only when AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS is true. +#define AMF_VIDEO_ENCODER_AV1_FORCE_INTEGER_MV L"Av1ForceIntegerMv" // bool; default = depends on USAGE; If true, enable force integer MV; if false, disable force integer MV. Valid only when AMF_VIDEO_ENCODER_AV1_SCREEN_CONTENT_TOOLS is true. +#define AMF_VIDEO_ENCODER_AV1_CDF_UPDATE L"Av1CdfUpdate" // bool; default = depends on USAGE; If true, enable CDF update; if false, disable CDF update. +#define AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE L"Av1CdfFrameEndUpdateMode" // amd_int64(AMF_VIDEO_ENCODER_AV1_CDF_FRAME_END_UPDATE_MODE_ENUM); default = depends on USAGE; CDF frame end update mode + + +// Rate Control and Quality Enhancement +#define AMF_VIDEO_ENCODER_AV1_VBV_BUFFER_SIZE L"Av1VBVBufferSize" // amf_int64; default = depends on USAGE; VBV Buffer Size in bits +#define AMF_VIDEO_ENCODER_AV1_FRAMERATE L"Av1FrameRate" // AMFRate; default = depends on usage; Frame Rate +#define AMF_VIDEO_ENCODER_AV1_ENFORCE_HRD L"Av1EnforceHRD" // bool; default = depends on USAGE; If true, enforce HRD; if false, HRD is not enforced. +#define AMF_VIDEO_ENCODER_AV1_FILLER_DATA L"Av1FillerData" // bool; default = depends on USAGE; If true, code filler data when needed; if false, don't code filler data. +#define AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE L"Av1TargetBitrate" // amf_int64; default = depends on USAGE; Target bit rate in bits +#define AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE L"Av1PeakBitrate" // amf_int64; default = depends on USAGE; Peak bit rate in bits + +#define AMF_VIDEO_ENCODER_AV1_MAX_COMPRESSED_FRAME_SIZE L"Av1MaxCompressedFrameSize" // amf_int64; default = 0; Max compressed frame Size in bits. 0 - no limit +#define AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTRA L"Av1MinQIndex_Intra" // amf_int64; default = depends on USAGE; Min QIndex for intra frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTRA L"Av1MaxQIndex_Intra" // amf_int64; default = depends on USAGE; Max QIndex for intra frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER L"Av1MinQIndex_Inter" // amf_int64; default = depends on USAGE; Min QIndex for inter frames; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER L"Av1MaxQIndex_Inter" // amf_int64; default = depends on USAGE; Max QIndex for inter frames; range = 0-255 + +#define AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA L"Av1QIndex_Intra" // amf_int64; default = depends on USAGE; intra-frame QIndex; range = 0-255 +#define AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER L"Av1QIndex_Inter" // amf_int64; default = depends on USAGE; inter-frame QIndex; range = 0-255 + +#define AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME L"Av1RateControlSkipFrameEnable" // bool; default = depends on USAGE; If true, rate control may code skip frame when needed; if false, rate control will not code skip frame. + + +// Picture Management Configuration +#define AMF_VIDEO_ENCODER_AV1_GOP_SIZE L"Av1GOPSize" // amf_int64; default = depends on USAGE; GOP Size (distance between automatically inserted key frames). If 0, key frame will be inserted at first frame only. Note that GOP may be interrupted by AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE. +#define AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE L"Av1HeaderInsertionMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_ENUM); default = depends on USAGE; sequence header insertion mode +#define AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE L"Av1SwitchFrameInsertionMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_ENUM); default = depends on USAGE; switch frame insertin mode +#define AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INTERVAL L"Av1SwitchFrameInterval" // amf_int64; default = depends on USAGE; the interval between two inserted switch frames. Valid only when AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE is AMF_VIDEO_ENCODER_AV1_SWITCH_FRAME_INSERTION_MODE_FIXED_INTERVAL. +#define AMF_VIDEO_ENCODER_AV1_NUM_TEMPORAL_LAYERS L"Av1NumTemporalLayers" // amf_int64; default = depends on USAGE; Number of temporal layers. Can be changed at any time but the change is only applied when encoding next base layer frame. + +#define AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE L"Av1IntraRefreshMode" // amf_int64(AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE_ENUM); default AMF_VIDEO_ENCODER_AV1_INTRA_REFRESH_MODE__DISABLED +#define AMF_VIDEO_ENCODER_AV1_INTRAREFRESH_STRIPES L"Av1IntraRefreshNumOfStripes" // amf_int64; default = N/A; Valid only when intra refresh is enabled. + +// color conversion +#define AMF_VIDEO_ENCODER_AV1_INPUT_COLOR_PROFILE L"Av1InputColorProfile" // amf_int64(AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM); default = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN - mean AUTO by size +#define AMF_VIDEO_ENCODER_AV1_INPUT_TRANSFER_CHARACTERISTIC L"Av1InputColorTransferChar" // amf_int64(AMF_COLOR_TRANSFER_CHARACTERISTIC_ENUM); default = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, ISO/IEC 23001-8_2013 section 7.2 See VideoDecoderUVD.h for enum +#define AMF_VIDEO_ENCODER_AV1_INPUT_COLOR_PRIMARIES L"Av1InputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 section 7.1 See ColorSpace.h for enum + +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE L"Av1OutputColorProfile" // amf_int64(AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM); default = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN - mean AUTO by size +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC L"Av1OutputColorTransferChar" // amf_int64(AMF_COLOR_TRANSFER_CHARACTERISTIC_ENUM); default = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED, ISO/IEC 23001-8_2013 ?7.2 See VideoDecoderUVD.h for enum +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES L"Av1OutputColorPrimaries" // amf_int64(AMF_COLOR_PRIMARIES_ENUM); default = AMF_COLOR_PRIMARIES_UNDEFINED, ISO/IEC 23001-8_2013 section 7.1 See ColorSpace.h for enum + + +// Frame encode parameters +#define AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE L"Av1ForceFrameType" // amf_int64(AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_ENUM); default = AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_NONE; generate particular frame type +#define AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER L"Av1ForceInsertSequenceHeader" // bool; default = false; If true, force insert sequence header with current frame; +#define AMF_VIDEO_ENCODER_AV1_MARK_CURRENT_WITH_LTR_INDEX L"Av1MarkCurrentWithLTRIndex" // amf_int64; default = N/A; Mark current frame with LTR index +#define AMF_VIDEO_ENCODER_AV1_FORCE_LTR_REFERENCE_BITFIELD L"Av1ForceLTRReferenceBitfield" // amf_int64; default = 0; force LTR bit-field +#define AMF_VIDEO_ENCODER_AV1_ROI_DATA L"Av1ROIData" // 2D AMFSurface, surface format: AMF_SURFACE_GRAY32 + +// Encode output parameters +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE L"Av1OutputFrameType" // amf_int64(AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_ENUM); default = N/A +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_MARKED_LTR_INDEX L"Av1MarkedLTRIndex" // amf_int64; default = N/A; Marked LTR index +#define AMF_VIDEO_ENCODER_AV1_OUTPUT_REFERENCED_LTR_INDEX_BITFIELD L"Av1ReferencedLTRIndexBitfield" // amf_int64; default = N/A; referenced LTR bit-field + +// AV1 Encoder capabilities - exposed in AMFCaps interface +#define AMF_VIDEO_ENCODER_AV1_CAP_NUM_OF_HW_INSTANCES L"Av1CapNumOfHwInstances" // amf_int64; default = N/A; number of HW encoder instances +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT L"Av1CapMaxThroughput" // amf_int64; default = N/A; MAX throughput for AV1 encoder in MB (16 x 16 pixel) +#define AMF_VIDEO_ENCODER_AV1_CAP_REQUESTED_THROUGHPUT L"Av1CapRequestedThroughput" // amf_int64; default = N/A; Currently total requested throughput for AV1 encode in MB (16 x 16 pixel) +#define AMF_VIDEO_ENCODER_AV1_CAP_COLOR_CONVERSION L"Av1CapColorConversion" // amf_int64(AMF_ACCELERATION_TYPE); default = N/A; type of supported color conversion. default AMF_ACCEL_GPU +#define AMF_VIDEO_ENCODER_AV1_CAP_PRE_ANALYSIS L"Av1PreAnalysis" // amf_bool - pre analysis module is available for AV1 UVE encoder, n/a for the other encoders +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_BITRATE L"Av1MaxBitrate" // amf_int64; default = N/A; Maximum bit rate in bits +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_PROFILE L"Av1MaxProfile" // amf_int64(AMF_VIDEO_ENCODER_AV1_PROFILE_ENUM); default = N/A; max value of code profile +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_LEVEL L"Av1MaxLevel" // amf_int64(AMF_VIDEO_ENCODER_AV1_LEVEL_ENUM); default = N/A; max value of codec level +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_TEMPORAL_LAYERS L"Av1CapMaxNumTemporalLayers" // amf_int64; default = N/A; The cap of maximum number of temporal layers +#define AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_LTR_FRAMES L"Av1CapMaxNumLTRFrames" // amf_int64; default = N/A; The cap of maximum number of LTR frames. This value is calculated based on current value of AMF_VIDEO_ENCODER_AV1_MAX_NUM_TEMPORAL_LAYERS. + +#endif //#ifndef AMF_VideoEncoderAV1_h diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h index c1ead8985..19af408f4 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderHEVC.h @@ -80,7 +80,10 @@ enum AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_ENUM AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP = 0, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, - AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR, + AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }; enum AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_ENUM @@ -145,9 +148,10 @@ enum AMF_VIDEO_ENCODER_HEVC_LTR_MODE_ENUM #define AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET L"HevcQualityPreset" // amf_int64(AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_ENUM); default = depends on USAGE; Quality Preset #define AMF_VIDEO_ENCODER_HEVC_EXTRADATA L"HevcExtraData" // AMFInterface* - > AMFBuffer*; SPS/PPS buffer - read-only #define AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO L"HevcAspectRatio" // AMFRatio; default = 1, 1 -#define AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE L"LowLatencyInternal" // bool; default = false, enables low latency mode +#define AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE L"LowLatencyInternal" // bool; default = false, enables low latency mode #define AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE L"HevcEnablePreAnalysis" // bool; default = false; enables the pre-analysis module. Currently only works in AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR mode. Refer to AMF Video PreAnalysis API reference for more details. -#define AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE L"HevcNominalRange" // amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE); default = amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_STUDIO); property is bool but amf_int64 also works for backward compatibility. +#define AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE L"HevcNominalRange" // amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE); default = amf_int64(AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_STUDIO); property is bool but amf_int64 also works for backward compatibility. +#define AMF_VIDEO_ENCODER_HEVC_MAX_NUM_TEMPORAL_LAYERS L"HevcMaxNumOfTemporalLayers" // amf_int64; default = 1; Max number of temporal layers. // Picture control properties #define AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR L"HevcGOPSPerIDR" // amf_int64; default = 1; The frequency to insert IDR as start of a GOP. 0 means no IDR will be inserted. @@ -159,6 +163,7 @@ enum AMF_VIDEO_ENCODER_HEVC_LTR_MODE_ENUM // Rate control properties #define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD L"HevcRateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method +#define AMF_VIDEO_ENCODER_HEVC_QVBR_QUALITY_LEVEL L"HevcQvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 #define AMF_VIDEO_ENCODER_HEVC_VBV_BUFFER_SIZE L"HevcVBVBufferSize" // amf_int64; default = depends on USAGE; VBV Buffer Size in bits #define AMF_VIDEO_ENCODER_HEVC_INITIAL_VBV_BUFFER_FULLNESS L"HevcInitialVBVBufferFullness" // amf_int64; default = 64; Initial VBV Buffer Fullness 0=0% 64=100% #define AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ L"HevcEnableVBAQ" // // bool; default = depends on USAGE; Enable auto VBAQ @@ -213,6 +218,9 @@ enum AMF_VIDEO_ENCODER_HEVC_LTR_MODE_ENUM #define AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA L"HevcInHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL //#define AMF_VIDEO_ENCODER_HEVC_OUTPUT_HDR_METADATA L"HevcOutHDRMetadata" // AMFBuffer containing AMFHDRMetadata; default NULL +// SVC +#define AMF_VIDEO_ENCODER_HEVC_NUM_TEMPORAL_LAYERS L"HevcNumOfTemporalLayers" // amf_int64; default = 1; Number of temporal layers. Can be changed at any time but the change is only applied when encoding next base layer frame. + // DPB management #define AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE L"HevcPicTransferMode" // amf_int64(AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE_ENUM); default = AMF_VIDEO_ENCODER_HEVC_PICTURE_TRANSFER_MODE_OFF - whether to exchange reference/reconstructed pic between encoder and application @@ -282,6 +290,7 @@ enum AMF_VIDEO_ENCODER_HEVC_LTR_MODE_ENUM #define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_LEVEL L"HevcMaxLevel" // amf_int64 maximum profile level #define AMF_VIDEO_ENCODER_HEVC_CAP_MIN_REFERENCE_FRAMES L"HevcMinReferenceFrames" // amf_int64 minimum number of reference frames #define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_REFERENCE_FRAMES L"HevcMaxReferenceFrames" // amf_int64 maximum number of reference frames +#define AMF_VIDEO_ENCODER_HEVC_CAP_MAX_TEMPORAL_LAYERS L"HevcMaxTemporalLayers" // amf_int64 maximum number of temporal layers #define AMF_VIDEO_ENCODER_HEVC_CAP_NUM_OF_HW_INSTANCES L"HevcNumOfHwInstances" // amf_int64 number of HW encoder instances #define AMF_VIDEO_ENCODER_HEVC_CAP_COLOR_CONVERSION L"HevcColorConversion" // amf_int64(AMF_ACCELERATION_TYPE) - type of supported color conversion. default AMF_ACCEL_GPU #define AMF_VIDEO_ENCODER_HEVC_CAP_PRE_ANALYSIS L"HevcPreAnalysis" // amf_bool - pre analysis module is available for HEVC UVE encoder, n/a for the other encoders diff --git a/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h index 6a9a9cc9a..7cb839c09 100644 --- a/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h +++ b/plugins/obs-ffmpeg/external/AMF/include/components/VideoEncoderVCE.h @@ -79,7 +79,9 @@ enum AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_ENUM AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, - AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR, + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR, + AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }; enum AMF_VIDEO_ENCODER_QUALITY_PRESET_ENUM @@ -164,6 +166,7 @@ enum AMF_VIDEO_ENCODER_LTR_MODE_ENUM #define AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE L"RateControlPreanalysisEnable" // amf_int64(AMF_VIDEO_ENCODER_PREENCODE_MODE_ENUM); default = AMF_VIDEO_ENCODER_PREENCODE_DISABLED; enables pre-encode assisted rate control. Deprecated, please use AMF_VIDEO_ENCODER_PREENCODE_ENABLE instead. #define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD L"RateControlMethod" // amf_int64(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_ENUM); default = depends on USAGE; Rate Control Method #define AMF_VIDEO_ENCODER_QVBR_QUALITY_LEVEL L"QvbrQualityLevel" // amf_int64; default = 23; QVBR quality level; range = 1-51 +#define AMF_VIDEO_ENCODER_MAX_NUM_TEMPORAL_LAYERS L"MaxNumOfTemporalLayers" // amf_int64; default = 1; Max number of temporal layers. #if !defined(__GNUC__) && !defined(__clang__) #pragma deprecated("AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE") #endif From acfad45eadef15935f1fe3247b1d129c44c6d4ac Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:19:32 -0800 Subject: [PATCH 02/12] obs-ffmpeg: Fix transcoding API typo --- plugins/obs-ffmpeg/texture-amf-opts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-ffmpeg/texture-amf-opts.hpp b/plugins/obs-ffmpeg/texture-amf-opts.hpp index b82702909..a961a0531 100644 --- a/plugins/obs-ffmpeg/texture-amf-opts.hpp +++ b/plugins/obs-ffmpeg/texture-amf-opts.hpp @@ -29,7 +29,7 @@ static void amf_apply_opt(amf_base *enc, obs_option *opt) } else if (strcmp(opt->name, "usage") == 0) { if (strcmp(opt->value, "transcoding") == 0) { - set_enum_opt(USAGE, TRANSCONDING); + set_enum_opt(USAGE, TRANSCODING); } else if (strcmp(opt->value, "ultralowlatency") == 0) { set_enum_opt(USAGE, ULTRA_LOW_LATENCY); } else if (strcmp(opt->value, "lowlatency") == 0) { From 21d079fdcc7c2e7524e85c14484e85191dbde004 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:34:21 -0800 Subject: [PATCH 03/12] obs-ffmpeg: Use codec enum for amf_properties_internal --- plugins/obs-ffmpeg/texture-amf.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index f5487e5b1..2686d6ca0 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -948,7 +948,7 @@ static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, return true; } -static obs_properties_t *amf_properties_internal(bool hevc) +static obs_properties_t *amf_properties_internal(amf_codec_type codec) { obs_properties_t *props = obs_properties_create(); obs_property_t *p; @@ -986,7 +986,7 @@ static obs_properties_t *amf_properties_internal(bool hevc) add_preset("speed"); #undef add_preset - if (!hevc) { + if (amf_codec_type::AVC == codec) { p = obs_properties_add_list(props, "profile", obs_module_text("Profile"), OBS_COMBO_TYPE_LIST, @@ -1014,13 +1014,13 @@ static obs_properties_t *amf_properties_internal(bool hevc) static obs_properties_t *amf_avc_properties(void *unused) { UNUSED_PARAMETER(unused); - return amf_properties_internal(false); + return amf_properties_internal(amf_codec_type::AVC); } static obs_properties_t *amf_hevc_properties(void *unused) { UNUSED_PARAMETER(unused); - return amf_properties_internal(true); + return amf_properties_internal(amf_codec_type::HEVC); } /* ========================================================================= */ From 535ced04d58ff851bcb6fa564a94858c4d8a1213 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:35:48 -0800 Subject: [PATCH 04/12] obs-ffmpeg: Allow 0-51 for CQP property 0-51 makes it consistent with other encoder implementations (At least for AVC/HEVC) --- plugins/obs-ffmpeg/texture-amf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index 2686d6ca0..67a692ce2 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -968,7 +968,7 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) obs_property_int_set_suffix(p, " Kbps"); obs_properties_add_int(props, "cqp", obs_module_text("NVENC.CQLevel"), - 1, 30, 1); + 0, 51, 1); p = obs_properties_add_int(props, "keyint_sec", obs_module_text("KeyframeIntervalSec"), 0, From 1948ddf2faa9027da8523078ef12fee9ca25f17e Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:39:38 -0800 Subject: [PATCH 05/12] obs-ffmpeg: Only allow AMF high/baseline profiles for AVC --- plugins/obs-ffmpeg/texture-amf.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index 67a692ce2..3a4a42168 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -993,9 +993,11 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) OBS_COMBO_FORMAT_STRING); #define add_profile(val) obs_property_list_add_string(p, val, val) - add_profile("high"); + if (amf_codec_type::AVC == codec) + add_profile("high"); add_profile("main"); - add_profile("baseline"); + if (amf_codec_type::AVC == codec) + add_profile("baseline"); #undef add_profile obs_properties_add_int(props, "bf", obs_module_text("BFrames"), From ef1a9c46e342469708ae77d45bff8963cdbc30a5 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:41:24 -0800 Subject: [PATCH 06/12] obs-ffmpeg: Only show b-frames AMF property for AVC --- plugins/obs-ffmpeg/texture-amf.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index 3a4a42168..cfabf45ec 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -999,7 +999,9 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) if (amf_codec_type::AVC == codec) add_profile("baseline"); #undef add_profile + } + if (amf_codec_type::AVC == codec) { obs_properties_add_int(props, "bf", obs_module_text("BFrames"), 0, 5, 1); } From 8b386a64170b313061aa82ff1d7d387ea1d2bf8b Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:45:50 -0800 Subject: [PATCH 07/12] obs-ffmpeg: Make AMF AVC encoder name consistent w/ others --- plugins/obs-ffmpeg/texture-amf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index cfabf45ec..a4ced5b78 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -1032,7 +1032,7 @@ static obs_properties_t *amf_hevc_properties(void *unused) static const char *amf_avc_get_name(void *) { - return "AMD HW H.264"; + return "AMD HW H.264 (AVC)"; } static inline int get_avc_preset(amf_base *enc, obs_data_t *settings) From a8fc9226f8d76d2ee033e72a221deed5754014bf Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:48:50 -0800 Subject: [PATCH 08/12] obs-ffmpeg: Use codec enum for AMF texture encode check --- plugins/obs-ffmpeg/texture-amf.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index a4ced5b78..8f6ab4941 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -891,10 +891,13 @@ static void amf_destroy(void *data) delete enc; } -static void check_texture_encode_capability(obs_encoder_t *encoder, bool hevc) +static void check_texture_encode_capability(obs_encoder_t *encoder, + amf_codec_type codec) { obs_video_info ovi; obs_get_video_info(&ovi); + bool avc = amf_codec_type::AVC == codec; + bool hevc = amf_codec_type::HEVC == codec; if (obs_encoder_scaling_enabled(encoder)) throw "Encoder scaling is active"; @@ -919,8 +922,8 @@ static void check_texture_encode_capability(obs_encoder_t *encoder, bool hevc) } } - if ((hevc && !caps[ovi.adapter].supports_hevc) || - (!hevc && !caps[ovi.adapter].supports_avc)) + if ((avc && !caps[ovi.adapter].supports_avc) || + (hevc && !caps[ovi.adapter].supports_hevc)) throw "Wrong adapter"; } @@ -1257,7 +1260,7 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings) static void *amf_avc_create_texencode(obs_data_t *settings, obs_encoder_t *encoder) try { - check_texture_encode_capability(encoder, false); + check_texture_encode_capability(encoder, amf_codec_type::AVC); std::unique_ptr enc = std::make_unique(); enc->encoder = encoder; @@ -1589,7 +1592,7 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings) static void *amf_hevc_create_texencode(obs_data_t *settings, obs_encoder_t *encoder) try { - check_texture_encode_capability(encoder, true); + check_texture_encode_capability(encoder, amf_codec_type::HEVC); std::unique_ptr enc = std::make_unique(); enc->encoder = encoder; From 927733240ccb2cf3980491a59a4477e79f99cbfd Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:50:27 -0800 Subject: [PATCH 09/12] obs-ffmpeg: Add AMF AV1 encoder --- plugins/obs-ffmpeg/data/locale/en-US.ini | 1 + .../obs-ffmpeg/obs-amf-test/obs-amf-test.cpp | 5 + plugins/obs-ffmpeg/texture-amf-opts.hpp | 86 ++- plugins/obs-ffmpeg/texture-amf.cpp | 491 ++++++++++++++++-- 4 files changed, 537 insertions(+), 46 deletions(-) diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index 484f230fe..1e0c74340 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -48,6 +48,7 @@ NVENC.Multipass.fullres="Two Passes (Full Resolution)" AMF.Preset.speed="Speed" AMF.Preset.balanced="Balanced" AMF.Preset.quality="Quality" +AMF.Preset.highQuality="High Quality" FFmpegSource="Media Source" LocalFile="Local File" diff --git a/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp b/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp index 7701c3717..a78e01d49 100644 --- a/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp +++ b/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test.cpp @@ -2,6 +2,7 @@ #include "../external/AMF/include/core/Trace.h" #include "../external/AMF/include/components/VideoEncoderVCE.h" #include "../external/AMF/include/components/VideoEncoderHEVC.h" +#include "../external/AMF/include/components/VideoEncoderAV1.h" #include @@ -24,6 +25,7 @@ struct adapter_caps { bool is_amd = false; bool supports_avc = false; bool supports_hevc = false; + bool supports_av1 = false; }; static AMFFactory *amf_factory = nullptr; @@ -81,6 +83,7 @@ static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx) caps.supports_avc = has_encoder(amf_context, AMFVideoEncoderVCE_AVC); caps.supports_hevc = has_encoder(amf_context, AMFVideoEncoder_HEVC); + caps.supports_av1 = has_encoder(amf_context, AMFVideoEncoder_AV1); return true; } @@ -145,6 +148,8 @@ try { caps.supports_avc ? "true" : "false"); printf("supports_hevc=%s\n", caps.supports_hevc ? "true" : "false"); + printf("supports_av1=%s\n", + caps.supports_av1 ? "true" : "false"); } return 0; diff --git a/plugins/obs-ffmpeg/texture-amf-opts.hpp b/plugins/obs-ffmpeg/texture-amf-opts.hpp index a961a0531..b1c37d200 100644 --- a/plugins/obs-ffmpeg/texture-amf-opts.hpp +++ b/plugins/obs-ffmpeg/texture-amf-opts.hpp @@ -17,25 +17,40 @@ static void amf_apply_opt(amf_base *enc, obs_option *opt) { bool avc = enc->codec == amf_codec_type::AVC; bool hevc = enc->codec == amf_codec_type::HEVC; + bool av1 = enc->codec == amf_codec_type::AV1; if (strcmp(opt->name, "g") == 0 || strcmp(opt->name, "keyint") == 0) { int val = atoi(opt->value); - if (enc->codec == amf_codec_type::AVC) + if (avc) set_avc_opt(IDR_PERIOD, val); - else + else if (hevc) set_hevc_opt(NUM_GOPS_PER_IDR, val); + else if (av1) + set_av1_opt(GOP_SIZE, val); } else if (strcmp(opt->name, "usage") == 0) { if (strcmp(opt->value, "transcoding") == 0) { set_enum_opt(USAGE, TRANSCODING); } else if (strcmp(opt->value, "ultralowlatency") == 0) { - set_enum_opt(USAGE, ULTRA_LOW_LATENCY); + if (avc) + set_avc_enum(USAGE, ULTRA_LOW_LATENCY); + else if (hevc) + set_hevc_enum(USAGE, ULTRA_LOW_LATENCY); + else + warn("Invalid value for %s: %s", opt->name, + opt->value); } else if (strcmp(opt->value, "lowlatency") == 0) { set_enum_opt(USAGE, LOW_LATENCY); } else if (strcmp(opt->value, "webcam") == 0) { - set_enum_opt(USAGE, WEBCAM); + if (avc) + set_avc_enum(USAGE, WEBCAM); + else if (hevc) + set_hevc_enum(USAGE, WEBCAM); + else + warn("Invalid value for %s: %s", opt->name, + opt->value); } else { warn("Invalid value for %s: %s", opt->name, opt->value); } @@ -69,7 +84,12 @@ static void amf_apply_opt(amf_base *enc, obs_option *opt) val.erase(pos, 1); int level = std::stoi(val); - set_opt(PROFILE_LEVEL, level); + if (avc) + set_avc_opt(PROFILE_LEVEL, level); + else if (hevc) + set_hevc_opt(PROFILE_LEVEL, level); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "quality") == 0) { @@ -106,42 +126,82 @@ static void amf_apply_opt(amf_base *enc, obs_option *opt) } else if (strcmp(opt->name, "filler_data") == 0) { bool val = str_to_bool(opt->value); - set_opt(FILLER_DATA_ENABLE, val); + if (avc) + set_avc_opt(FILLER_DATA_ENABLE, val); + else if (hevc) + set_hevc_opt(FILLER_DATA_ENABLE, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "vbaq") == 0) { bool val = str_to_bool(opt->value); - set_opt(ENABLE_VBAQ, val); + if (avc) + set_avc_opt(ENABLE_VBAQ, val); + else if (hevc) + set_hevc_opt(ENABLE_VBAQ, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "qp_i") == 0) { int val = atoi(opt->value); - set_opt(QP_I, val); + if (avc) + set_avc_opt(QP_I, val); + else if (hevc) + set_hevc_opt(QP_I, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "qp_p") == 0) { int val = atoi(opt->value); - set_opt(QP_P, val); + if (avc) + set_avc_opt(QP_P, val); + else if (hevc) + set_hevc_opt(QP_P, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "me_half_pel") == 0) { bool val = str_to_bool(opt->value); - set_opt(MOTION_HALF_PIXEL, val); + if (avc) + set_avc_opt(MOTION_HALF_PIXEL, val); + else if (hevc) + set_hevc_opt(MOTION_HALF_PIXEL, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "me_quarter_pel") == 0) { bool val = str_to_bool(opt->value); - set_opt(MOTION_QUARTERPIXEL, val); + if (avc) + set_avc_opt(MOTION_QUARTERPIXEL, val); + else if (hevc) + set_hevc_opt(MOTION_QUARTERPIXEL, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "aud") == 0) { bool val = str_to_bool(opt->value); - set_opt(INSERT_AUD, val); + if (avc) + set_avc_opt(INSERT_AUD, val); + else if (hevc) + set_hevc_opt(INSERT_AUD, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (strcmp(opt->name, "max_au_size") == 0) { int val = atoi(opt->value); - set_opt(MAX_AU_SIZE, val); + if (avc) + set_avc_opt(MAX_AU_SIZE, val); + else if (hevc) + set_hevc_opt(MAX_AU_SIZE, val); + else + warn("Invalid value for %s: %s", opt->name, opt->value); } else if (avc && strcmp(opt->name, "preanalysis") == 0) { diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index 8f6ab4941..91bfc5f68 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -16,6 +16,7 @@ #include "external/AMF/include/components/VideoEncoderHEVC.h" #include "external/AMF/include/components/VideoEncoderVCE.h" +#include "external/AMF/include/components/VideoEncoderAV1.h" #include "external/AMF/include/core/Factory.h" #include "external/AMF/include/core/Trace.h" @@ -63,6 +64,7 @@ struct adapter_caps { bool is_amd = false; bool supports_avc = false; bool supports_hevc = false; + bool supports_av1 = false; }; /* ------------------------------------------------------------------------- */ @@ -80,6 +82,7 @@ static uint64_t amf_version = 0; enum class amf_codec_type { AVC, HEVC, + AV1, }; struct amf_base { @@ -213,25 +216,34 @@ static void set_amf_property(amf_base *enc, const wchar_t *name, const T &value) set_amf_property(enc, AMF_VIDEO_ENCODER_##name, value) #define set_hevc_property(enc, name, value) \ set_amf_property(enc, AMF_VIDEO_ENCODER_HEVC_##name, value) +#define set_av1_property(enc, name, value) \ + set_amf_property(enc, AMF_VIDEO_ENCODER_AV1_##name, value) #define get_avc_property(enc, name, value) \ get_amf_property(enc, AMF_VIDEO_ENCODER_##name, value) #define get_hevc_property(enc, name, value) \ get_amf_property(enc, AMF_VIDEO_ENCODER_HEVC_##name, value) +#define get_av1_property(enc, name, value) \ + get_amf_property(enc, AMF_VIDEO_ENCODER_AV1_##name, value) #define get_opt_name(name) \ ((enc->codec == amf_codec_type::AVC) ? AMF_VIDEO_ENCODER_##name \ - : AMF_VIDEO_ENCODER_HEVC_##name) + : (enc->codec == amf_codec_type::HEVC) \ + ? AMF_VIDEO_ENCODER_HEVC_##name \ + : AMF_VIDEO_ENCODER_AV1_##name) #define set_opt(name, value) set_amf_property(enc, get_opt_name(name), value) #define get_opt(name, value) get_amf_property(enc, get_opt_name(name), value) #define set_avc_opt(name, value) set_avc_property(enc, name, value) #define set_hevc_opt(name, value) set_hevc_property(enc, name, value) +#define set_av1_opt(name, value) set_av1_property(enc, name, value) #define set_enum_opt(name, value) \ set_amf_property(enc, get_opt_name(name), get_opt_name(name##_##value)) #define set_avc_enum(name, value) \ set_avc_property(enc, name, AMF_VIDEO_ENCODER_##name##_##value) #define set_hevc_enum(name, value) \ set_hevc_property(enc, name, AMF_VIDEO_ENCODER_HEVC_##name##_##value) +#define set_av1_enum(name, value) \ + set_av1_property(enc, name, AMF_VIDEO_ENCODER_AV1_##name##_##value) /* ------------------------------------------------------------------------- */ /* Implementation */ @@ -400,11 +412,27 @@ static inline void calc_throughput(amf_base *enc) static inline void check_preset_compatibility(amf_base *enc, const char *&preset) { - /* 1.8 * current base throughput == quality, + /* 1.9 * current base throughput == highQuality, + * 1.8 * current base throughput == quality, * 1.1 * current base throughput == balanced */ + static constexpr amf_int64 throughput_high_quality_mul = 19; static constexpr amf_int64 throughput_quality_mul = 18; static constexpr amf_int64 throughput_balanced_mul = 11; + /* if the throughput * 1.9 is lower than the max throughput, switch to + * a lower preset */ + if (astrcmpi(preset, "highQuality") == 0) { + if (!enc->max_throughput) { + preset = "balanced"; + } else { + amf_int64 req_throughput = enc->throughput * + throughput_high_quality_mul / + 10; + if (enc->max_throughput < req_throughput) + preset = "quality"; + } + } + /* if the throughput * 1.8 is lower than the max throughput, switch to * a lower preset */ if (astrcmpi(preset, "quality") == 0) { @@ -447,27 +475,60 @@ static void convert_to_encoder_packet(amf_base *enc, AMFDataPtr &data, enc->packet_data = AMFBufferPtr(data); data->GetProperty(L"PTS", &packet->pts); - bool hevc = enc->codec == amf_codec_type::HEVC; - const wchar_t *get_output_type = - hevc ? AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE - : AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE; + const wchar_t *get_output_type; + switch (enc->codec) { + case amf_codec_type::AVC: + get_output_type = AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE; + break; + case amf_codec_type::HEVC: + get_output_type = AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE; + break; + case amf_codec_type::AV1: + get_output_type = AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE; + break; + } - uint64_t type; - data->GetProperty(get_output_type, &type); + uint64_t type = 0; + AMF_RESULT res = data->GetProperty(get_output_type, &type); + if (res != AMF_OK) + throw amf_error("Failed to GetProperty(): encoder output " + "data type", + res); - switch (type) { - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR: - packet->priority = OBS_NAL_PRIORITY_HIGHEST; - break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: - packet->priority = OBS_NAL_PRIORITY_HIGH; - break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: - packet->priority = OBS_NAL_PRIORITY_LOW; - break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: - packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; - break; + if (enc->codec == amf_codec_type::AVC || + enc->codec == amf_codec_type::HEVC) { + switch (type) { + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR: + packet->priority = OBS_NAL_PRIORITY_HIGHEST; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: + packet->priority = OBS_NAL_PRIORITY_HIGH; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: + packet->priority = OBS_NAL_PRIORITY_LOW; + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + } + } else if (enc->codec == amf_codec_type::AV1) { + switch (type) { + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY: + packet->priority = OBS_NAL_PRIORITY_HIGHEST; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTRA_ONLY: + packet->priority = OBS_NAL_PRIORITY_HIGH; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_INTER: + packet->priority = OBS_NAL_PRIORITY_LOW; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SWITCH: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + case AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_SHOW_EXISTING: + packet->priority = OBS_NAL_PRIORITY_DISPOSABLE; + break; + } } packet->data = (uint8_t *)enc->packet_data->GetNative(); @@ -769,6 +830,23 @@ static void h265_video_info_fallback(void *, struct video_scale_info *info) } } +static void av1_video_info_fallback(void *, struct video_scale_info *info) +{ + switch (info->format) { + case VIDEO_FORMAT_RGBA: + case VIDEO_FORMAT_BGRA: + case VIDEO_FORMAT_BGRX: + info->format = VIDEO_FORMAT_RGBA; + break; + case VIDEO_FORMAT_I010: + case VIDEO_FORMAT_P010: + info->format = VIDEO_FORMAT_P010; + break; + default: + info->format = VIDEO_FORMAT_NV12; + } +} + static bool amf_create_encoder(amf_base *enc) try { AMF_RESULT res; @@ -787,8 +865,10 @@ try { if (enc->fallback) { if (enc->codec == amf_codec_type::AVC) h264_video_info_fallback(NULL, &info); - else + else if (enc->codec == amf_codec_type::HEVC) h265_video_info_fallback(NULL, &info); + else + av1_video_info_fallback(NULL, &info); } enc->cx = obs_encoder_get_width(enc->encoder); @@ -868,10 +948,21 @@ try { enc->init(); - res = amf_factory->CreateComponent(enc->amf_context, - enc->codec == amf_codec_type::HEVC - ? AMFVideoEncoder_HEVC - : AMFVideoEncoderVCE_AVC, + const wchar_t *codec = nullptr; + switch (enc->codec) { + case (amf_codec_type::AVC): + codec = AMFVideoEncoderVCE_AVC; + break; + case (amf_codec_type::HEVC): + codec = AMFVideoEncoder_HEVC; + break; + case (amf_codec_type::AV1): + codec = AMFVideoEncoder_AV1; + break; + default: + codec = AMFVideoEncoder_HEVC; + } + res = amf_factory->CreateComponent(enc->amf_context, codec, &enc->amf_encoder); if (res != AMF_OK) throw amf_error("CreateComponent failed", res); @@ -898,10 +989,12 @@ static void check_texture_encode_capability(obs_encoder_t *encoder, obs_get_video_info(&ovi); bool avc = amf_codec_type::AVC == codec; bool hevc = amf_codec_type::HEVC == codec; + bool av1 = amf_codec_type::AV1 == codec; if (obs_encoder_scaling_enabled(encoder)) throw "Encoder scaling is active"; - if (hevc) { + + if (hevc || av1) { if (!obs_nv12_tex_active() && !obs_p010_tex_active()) throw "NV12/P010 textures aren't active"; } else if (!obs_nv12_tex_active()) { @@ -923,7 +1016,8 @@ static void check_texture_encode_capability(obs_encoder_t *encoder, } if ((avc && !caps[ovi.adapter].supports_avc) || - (hevc && !caps[ovi.adapter].supports_hevc)) + (hevc && !caps[ovi.adapter].supports_hevc) || + (av1 && !caps[ovi.adapter].supports_av1)) throw "Wrong adapter"; } @@ -963,6 +1057,12 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) obs_property_list_add_string(p, "CBR", "CBR"); obs_property_list_add_string(p, "CQP", "CQP"); obs_property_list_add_string(p, "VBR", "VBR"); + if (amf_codec_type::AV1 == codec) { + obs_property_list_add_string(p, "VBR_LAT", "VBR_LAT"); + obs_property_list_add_string(p, "QVBR", "QVBR"); + obs_property_list_add_string(p, "HQVBR", "HQVBR"); + obs_property_list_add_string(p, "HQCBR", "HQCBR"); + } obs_property_set_modified_callback(p, rate_control_modified); @@ -971,7 +1071,7 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) obs_property_int_set_suffix(p, " Kbps"); obs_properties_add_int(props, "cqp", obs_module_text("NVENC.CQLevel"), - 0, 51, 1); + 0, codec == amf_codec_type::AV1 ? 63 : 51, 1); p = obs_properties_add_int(props, "keyint_sec", obs_module_text("KeyframeIntervalSec"), 0, @@ -984,12 +1084,15 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec) #define add_preset(val) \ obs_property_list_add_string(p, obs_module_text("AMF.Preset." val), val) + if (amf_codec_type::AV1 == codec) { + add_preset("highQuality"); + } add_preset("quality"); add_preset("balanced"); add_preset("speed"); #undef add_preset - if (amf_codec_type::AVC == codec) { + if (amf_codec_type::AVC == codec || amf_codec_type::AV1 == codec) { p = obs_properties_add_list(props, "profile", obs_module_text("Profile"), OBS_COMBO_TYPE_LIST, @@ -1030,6 +1133,12 @@ static obs_properties_t *amf_hevc_properties(void *unused) return amf_properties_internal(amf_codec_type::HEVC); } +static obs_properties_t *amf_av1_properties(void *unused) +{ + UNUSED_PARAMETER(unused); + return amf_properties_internal(amf_codec_type::AV1); +} + /* ========================================================================= */ /* AVC Implementation */ @@ -1684,6 +1793,316 @@ static void register_hevc() #endif //ENABLE_HEVC +/* ========================================================================= */ +/* AV1 Implementation */ + +static const char *amf_av1_get_name(void *) +{ + return "AMD HW AV1"; +} + +static inline int get_av1_preset(amf_base *enc, obs_data_t *settings) +{ + const char *preset = obs_data_get_string(settings, "preset"); + + check_preset_compatibility(enc, preset); + + if (astrcmpi(preset, "highquality") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY; + else if (astrcmpi(preset, "quality") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY; + else if (astrcmpi(preset, "balanced") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED; + else if (astrcmpi(preset, "speed") == 0) + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED; + + return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED; +} + +static inline int get_av1_rate_control(const char *rc_str) +{ + if (astrcmpi(rc_str, "cqp") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP; + else if (astrcmpi(rc_str, "vbr_lat") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "vbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + else if (astrcmpi(rc_str, "cbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; + else if (astrcmpi(rc_str, "qvbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqvbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR; + else if (astrcmpi(rc_str, "hqcbr") == 0) + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR; + + return AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; +} + +static inline int get_av1_profile(obs_data_t *settings) +{ + const char *profile = obs_data_get_string(settings, "profile"); + + if (astrcmpi(profile, "main") == 0) + return AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN; + + return AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN; +} + +static void amf_av1_update_data(amf_base *enc, int rc, int64_t bitrate, + int64_t cq_value) +{ + if (rc != AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP) { + set_av1_property(enc, TARGET_BITRATE, bitrate); + set_av1_property(enc, PEAK_BITRATE, bitrate); + set_av1_property(enc, VBV_BUFFER_SIZE, bitrate); + + if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { + set_av1_property(enc, FILLER_DATA, true); + } else if ( + rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR || + rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) { + set_av1_property(enc, PEAK_BITRATE, bitrate * 1.5); + } + } else { + int64_t qp = cq_value * 4; + set_av1_property(enc, Q_INDEX_INTRA, qp); + set_av1_property(enc, Q_INDEX_INTER, qp); + } +} + +static bool amf_av1_update(void *data, obs_data_t *settings) +try { + amf_base *enc = (amf_base *)data; + + if (enc->first_update) { + enc->first_update = false; + return true; + } + + int64_t bitrate = obs_data_get_int(settings, "bitrate"); + int64_t cq_level = obs_data_get_int(settings, "cqp"); + const char *rc_str = obs_data_get_string(settings, "rate_control"); + int rc = get_av1_rate_control(rc_str); + + amf_av1_update_data(enc, rc, bitrate * 1000, cq_level); + + AMF_RESULT res = enc->amf_encoder->ReInit(enc->cx, enc->cy); + if (res != AMF_OK) + throw amf_error("AMFComponent::Init failed", res); + + return true; + +} catch (const amf_error &err) { + amf_base *enc = (amf_base *)data; + error("%s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return false; +} + +static bool amf_av1_init(void *data, obs_data_t *settings) +{ + amf_base *enc = (amf_base *)data; + + int64_t bitrate = obs_data_get_int(settings, "bitrate"); + int64_t qp = obs_data_get_int(settings, "cqp"); + const char *preset = obs_data_get_string(settings, "preset"); + const char *profile = obs_data_get_string(settings, "profile"); + const char *rc_str = obs_data_get_string(settings, "rate_control"); + + check_preset_compatibility(enc, preset); + + int rc = get_av1_rate_control(rc_str); + set_av1_property(enc, RATE_CONTROL_METHOD, rc); + + amf_av1_update_data(enc, rc, bitrate * 1000, qp); + + set_av1_property(enc, ENFORCE_HRD, true); + + int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); + int gop_size = (keyint_sec) ? keyint_sec * enc->fps_num / enc->fps_den + : 250; + set_av1_property(enc, GOP_SIZE, gop_size); + + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); + if (ffmpeg_opts && *ffmpeg_opts) { + struct obs_options opts = obs_parse_options(ffmpeg_opts); + for (size_t i = 0; i < opts.count; i++) { + amf_apply_opt(enc, &opts.options[i]); + } + obs_free_options(opts); + } + + if (!ffmpeg_opts || !*ffmpeg_opts) + ffmpeg_opts = "(none)"; + + info("settings:\n" + "\trate_control: %s\n" + "\tbitrate: %d\n" + "\tcqp: %d\n" + "\tkeyint: %d\n" + "\tpreset: %s\n" + "\tprofile: %s\n" + "\twidth: %d\n" + "\theight: %d\n" + "\tparams: %s", + rc_str, bitrate, qp, gop_size, preset, profile, enc->cx, enc->cy, + ffmpeg_opts); + + return true; +} + +static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) +{ + enc->codec = amf_codec_type::AV1; + + if (!amf_create_encoder(enc)) + throw "Failed to create encoder"; + + AMFCapsPtr caps; + AMF_RESULT res = enc->amf_encoder->GetCaps(&caps); + if (res == AMF_OK) { + caps->GetProperty(AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT, + &enc->max_throughput); + } + + const bool is10bit = enc->amf_format == AMF_SURFACE_P010; + + set_av1_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); + set_av1_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); + set_av1_property(enc, ALIGNMENT_MODE, + AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS); + set_av1_property(enc, QUALITY_PRESET, get_av1_preset(enc, settings)); + set_av1_property(enc, COLOR_BIT_DEPTH, + is10bit ? AMF_COLOR_BIT_DEPTH_10 + : AMF_COLOR_BIT_DEPTH_8); + set_av1_property(enc, PROFILE, get_av1_profile(settings)); + set_av1_property(enc, ENCODING_LATENCY_MODE, + AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_NONE); + // set_av1_property(enc, RATE_CONTROL_PREENCODE, true); + set_av1_property(enc, OUTPUT_COLOR_PROFILE, enc->amf_color_profile); + set_av1_property(enc, OUTPUT_TRANSFER_CHARACTERISTIC, + enc->amf_characteristic); + set_av1_property(enc, OUTPUT_COLOR_PRIMARIES, enc->amf_primaries); + + amf_av1_init(enc, settings); + + res = enc->amf_encoder->Init(enc->amf_format, enc->cx, enc->cy); + if (res != AMF_OK) + throw amf_error("AMFComponent::Init failed", res); + + set_av1_property(enc, FRAMERATE, enc->amf_frame_rate); + + AMFVariant p; + res = enc->amf_encoder->GetProperty(AMF_VIDEO_ENCODER_AV1_EXTRA_DATA, + &p); + if (res == AMF_OK && p.type == AMF_VARIANT_INTERFACE) + enc->header = AMFBufferPtr(p.pInterface); +} + +static void *amf_av1_create_texencode(obs_data_t *settings, + obs_encoder_t *encoder) +try { + check_texture_encode_capability(encoder, amf_codec_type::AV1); + + std::unique_ptr enc = std::make_unique(); + enc->encoder = encoder; + enc->encoder_str = "texture-amf-av1"; + + if (!amf_init_d3d11(enc.get())) + throw "Failed to create D3D11"; + + amf_av1_create_internal(enc.get(), settings); + return enc.release(); + +} catch (const amf_error &err) { + blog(LOG_ERROR, "[texture-amf-av1] %s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); + +} catch (const char *err) { + blog(LOG_ERROR, "[texture-amf-av1] %s: %s", __FUNCTION__, err); + return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); +} + +static void *amf_av1_create_fallback(obs_data_t *settings, + obs_encoder_t *encoder) +try { + std::unique_ptr enc = std::make_unique(); + enc->encoder = encoder; + enc->encoder_str = "fallback-amf-av1"; + + video_t *video = obs_encoder_video(encoder); + const struct video_output_info *voi = video_output_get_info(video); + switch (voi->format) { + case VIDEO_FORMAT_I010: + case VIDEO_FORMAT_P010: { + break; + } + default: + switch (voi->colorspace) { + case VIDEO_CS_2100_PQ: + case VIDEO_CS_2100_HLG: { + const char *const text = + obs_module_text("AMF.8bitUnsupportedHdr"); + obs_encoder_set_last_error(encoder, text); + throw text; + } + } + } + + amf_av1_create_internal(enc.get(), settings); + return enc.release(); + +} catch (const amf_error &err) { + blog(LOG_ERROR, "[fallback-amf-av1] %s: %s: %ls", __FUNCTION__, err.str, + amf_trace->GetResultText(err.res)); + return nullptr; + +} catch (const char *err) { + blog(LOG_ERROR, "[fallback-amf-av1] %s: %s", __FUNCTION__, err); + return nullptr; +} + +static void amf_av1_defaults(obs_data_t *settings) +{ + obs_data_set_default_int(settings, "bitrate", 2500); + obs_data_set_default_int(settings, "cqp", 7); + obs_data_set_default_string(settings, "rate_control", "CBR"); + obs_data_set_default_string(settings, "preset", "quality"); + obs_data_set_default_string(settings, "profile", "high"); +} + +static void register_av1() +{ + struct obs_encoder_info amf_encoder_info = {}; + amf_encoder_info.id = "av1_texture_amf"; + amf_encoder_info.type = OBS_ENCODER_VIDEO; + amf_encoder_info.codec = "av1"; + amf_encoder_info.get_name = amf_av1_get_name; + amf_encoder_info.create = amf_av1_create_texencode; + amf_encoder_info.destroy = amf_destroy; + amf_encoder_info.update = amf_av1_update; + amf_encoder_info.encode_texture = amf_encode_tex; + amf_encoder_info.get_defaults = amf_av1_defaults; + amf_encoder_info.get_properties = amf_av1_properties; + amf_encoder_info.get_extra_data = amf_extra_data; + amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE | + OBS_ENCODER_CAP_DYN_BITRATE; + + obs_register_encoder(&amf_encoder_info); + + amf_encoder_info.id = "av1_fallback_amf"; + amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL | + OBS_ENCODER_CAP_DYN_BITRATE; + amf_encoder_info.encode_texture = nullptr; + amf_encoder_info.create = amf_av1_create_fallback; + amf_encoder_info.encode = amf_encode_fallback; + amf_encoder_info.get_video_info = av1_video_info_fallback; + + obs_register_encoder(&amf_encoder_info); +} + /* ========================================================================= */ /* Global Stuff */ @@ -1701,7 +2120,7 @@ try { FreeLibrary(amf_module_test); /* ----------------------------------- */ - /* Check for AVC/HEVC support */ + /* Check for supported codecs */ BPtr test_exe = os_get_executable_path_ptr("obs-amf-test.exe"); std::string caps_str; @@ -1738,6 +2157,7 @@ try { uint32_t adapter_count = (uint32_t)config_num_sections(config); bool avc_supported = false; bool hevc_supported = false; + bool av1_supported = false; for (uint32_t i = 0; i < adapter_count; i++) { std::string section = std::to_string(i); @@ -1749,13 +2169,16 @@ try { "supports_avc"); info.supports_hevc = config_get_bool(config, section.c_str(), "supports_hevc"); + info.supports_av1 = config_get_bool(config, section.c_str(), + "supports_av1"); avc_supported |= info.supports_avc; hevc_supported |= info.supports_hevc; + av1_supported |= info.supports_av1; } - if (!avc_supported && !hevc_supported) - throw "Neither AVC nor HEVC are supported by any devices"; + if (!avc_supported && !hevc_supported && !av1_supported) + throw "Neither AVC, HEVC, nor AV1 are supported by any devices"; /* ----------------------------------- */ /* Init AMF */ @@ -1800,6 +2223,8 @@ try { if (hevc_supported) register_hevc(); #endif + if (av1_supported) + register_av1(); } catch (const std::string &str) { /* doing debug here because string exceptions indicate the user is From 8a831e2da5fc646978cc77abceddc580fce83b67 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Tue, 8 Nov 2022 00:38:23 -0800 Subject: [PATCH 10/12] UI: Add AMD AV1 to simple output mode --- UI/data/locale/en-US.ini | 1 + UI/window-basic-main-outputs.cpp | 5 +++++ UI/window-basic-main-profiles.cpp | 9 +++++++++ UI/window-basic-main.hpp | 1 + UI/window-basic-settings.cpp | 18 ++++++++++++++++++ UI/window-basic-settings.hpp | 1 + 6 files changed, 35 insertions(+) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index a05a24314..31956c42c 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -950,6 +950,7 @@ Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.AMD.HEVC="Hardware (AMD, HEVC)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD.AV1="Hardware (AMD, AV1)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.H264="Hardware (NVENC, H.264)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.AV1="Hardware (NVENC, AV1)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.HEVC="Hardware (NVENC, HEVC)" diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp index 60a097f11..26c43dc01 100644 --- a/UI/window-basic-main-outputs.cpp +++ b/UI/window-basic-main-outputs.cpp @@ -377,6 +377,8 @@ const char *get_simple_output_encoder(const char *encoder) } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_HEVC) == 0) { return "h265_texture_amf"; #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_AV1) == 0) { + return "av1_texture_amf"; } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) { return EncoderAvailable("jim_nvenc") ? "jim_nvenc" : "ffmpeg_nvenc"; @@ -549,6 +551,9 @@ void SimpleOutput::Update() presetType = "NVENCPreset2"; #endif + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD_AV1) == 0) { + presetType = "AMDAV1Preset"; + } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC_AV1) == 0) { presetType = "NVENCPreset2"; diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp index f4dc8f44f..384369f38 100644 --- a/UI/window-basic-main-profiles.cpp +++ b/UI/window-basic-main-profiles.cpp @@ -829,6 +829,7 @@ void OBSBasic::CheckForSimpleModeX264Fallback() bool nve_hevc_supported = false; bool apple_hevc_supported = false; #endif + bool amd_av1_supported = false; bool apple_supported = false; bool changed = false; size_t idx = 0; @@ -847,6 +848,8 @@ void OBSBasic::CheckForSimpleModeX264Fallback() else if (strcmp(id, "ffmpeg_hevc_nvenc") == 0) nve_hevc_supported = true; #endif + else if (strcmp(id, "av1_texture_amf") == 0) + amd_av1_supported = true; else if (strcmp(id, "com.apple.videotoolbox.videoencoder.ave.avc") == 0) @@ -898,6 +901,12 @@ void OBSBasic::CheckForSimpleModeX264Fallback() name = SIMPLE_ENCODER_X264; return false; } + } else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) { + if (!amd_av1_supported) { + changed = true; + name = SIMPLE_ENCODER_X264; + return false; + } } else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) { if (!apple_supported) { changed = true; diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 54e4502f3..4def5ed32 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -70,6 +70,7 @@ class OBSBasicStats; #define SIMPLE_ENCODER_NVENC_HEVC "nvenc_hevc" #define SIMPLE_ENCODER_AMD "amd" #define SIMPLE_ENCODER_AMD_HEVC "amd_hevc" +#define SIMPLE_ENCODER_AMD_AV1 "amd_av1" #define SIMPLE_ENCODER_APPLE_H264 "apple_h264" #define SIMPLE_ENCODER_APPLE_HEVC "apple_hevc" diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 03a8ba6b4..c5cf82f91 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1729,6 +1729,8 @@ void OBSBasicSettings::LoadSimpleOutputSettings() "NVENCPreset2"); const char *amdPreset = config_get_string(main->Config(), "SimpleOutput", "AMDPreset"); + const char *amdAV1Preset = config_get_string( + main->Config(), "SimpleOutput", "AMDAV1Preset"); const char *custom = config_get_string(main->Config(), "SimpleOutput", "x264Settings"); const char *recQual = @@ -1748,6 +1750,7 @@ void OBSBasicSettings::LoadSimpleOutputSettings() curQSVPreset = qsvPreset; curNVENCPreset = nvPreset; curAMDPreset = amdPreset; + curAMDAV1Preset = amdAV1Preset; audioBitrate = FindClosestAvailableAACBitrate(audioBitrate); @@ -3491,6 +3494,8 @@ void OBSBasicSettings::SaveOutputSettings() #endif else if (encoder == SIMPLE_ENCODER_AMD) presetType = "AMDPreset"; + else if (encoder == SIMPLE_ENCODER_AMD_AV1) + presetType = "AMDAV1Preset"; else if (encoder == SIMPLE_ENCODER_APPLE_H264 #ifdef ENABLE_HEVC || encoder == SIMPLE_ENCODER_APPLE_HEVC @@ -4776,6 +4781,10 @@ void OBSBasicSettings::FillSimpleRecordingValues() ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD)); + if (EncoderAvailable("av1_texture_amf")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.AMD.AV1"), + QString(SIMPLE_ENCODER_AMD_AV1)); if (EncoderAvailable("com.apple.videotoolbox.videoencoder.ave.avc") #ifndef __aarch64__ && os_get_emulation_status() == true @@ -4892,6 +4901,15 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged() ui->simpleOutAdvanced->setVisible(false); ui->simpleOutPreset->setVisible(false); ui->simpleOutPresetLabel->setVisible(false); + + } else if (encoder == SIMPLE_ENCODER_AMD_AV1) { + ui->simpleOutPreset->addItem("Speed", "speed"); + ui->simpleOutPreset->addItem("Balanced", "balanced"); + ui->simpleOutPreset->addItem("Quality", "quality"); + ui->simpleOutPreset->addItem("High Quality", "highQuality"); + + defaultPreset = "balanced"; + preset = curAMDAV1Preset; } else { #define PRESET_STR(val) \ diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp index 6e79fe747..c312eec89 100644 --- a/UI/window-basic-settings.hpp +++ b/UI/window-basic-settings.hpp @@ -146,6 +146,7 @@ private: QString curQSVPreset; QString curNVENCPreset; QString curAMDPreset; + QString curAMDAV1Preset; QString curAdvStreamEncoder; QString curAdvRecordEncoder; From 49e5f7783f53e70f43382fe361f6ba75bdf8585c Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Wed, 9 Nov 2022 11:42:04 -0500 Subject: [PATCH 11/12] obs-ffmpeg: Suggest docs to reference for AMF/FFmpeg options --- plugins/obs-ffmpeg/data/locale/en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index 1e0c74340..2f43ed0b5 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -14,7 +14,7 @@ Lossless="Lossless" Level="Level" AMFOpts="AMF/FFmpeg Options" -AMFOpts.ToolTip="Use to specify custom AMF or FFmpeg options. For example, \"level=5.2 profile=main BPicturesPattern=3\"" +AMFOpts.ToolTip="Use to specify custom AMF or FFmpeg options. For example, \"level=5.2 profile=main\". Check the AMF encoder docs for more details." BFrames="Max B-frames" From 341f288b5753529ff0580369483328981da107f0 Mon Sep 17 00:00:00 2001 From: Roman Huts <71274498+rhutsAMD@users.noreply.github.com> Date: Wed, 9 Nov 2022 18:14:18 -0500 Subject: [PATCH 12/12] obs-ffmpeg: Fix encoder preset quality fallbacks for AVC/HEVC/AV1 (Jim note: The missing description of this commit is that basically, the CAP_MAX_THROUGHPUT value returns a different result based upon what the other settings are currently set to. It didn't operate the way it was originally programmed.) --- plugins/obs-ffmpeg/texture-amf.cpp | 106 +++++++++++++++++------------ 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp index 91bfc5f68..e0034c7dd 100644 --- a/plugins/obs-ffmpeg/texture-amf.cpp +++ b/plugins/obs-ffmpeg/texture-amf.cpp @@ -409,48 +409,74 @@ static inline void calc_throughput(amf_base *enc) mb_frame * (amf_int64)enc->fps_num / (amf_int64)enc->fps_den; } +static inline int get_avc_preset(amf_base *enc, const char *preset); +static inline int get_hevc_preset(amf_base *enc, const char *preset); +static inline int get_av1_preset(amf_base *enc, const char *preset); + +static inline int get_preset(amf_base *enc, const char *preset) +{ + if (enc->codec == amf_codec_type::AVC) + return get_avc_preset(enc, preset); + + else if (enc->codec == amf_codec_type::HEVC) + return get_hevc_preset(enc, preset); + + else if (enc->codec == amf_codec_type::AV1) + return get_av1_preset(enc, preset); + + return 0; +} + +static inline void refresh_throughput_caps(amf_base *enc, const char *&preset) +{ + AMF_RESULT res = AMF_OK; + AMFCapsPtr caps; + + set_opt(QUALITY_PRESET, get_preset(enc, preset)); + res = enc->amf_encoder->GetCaps(&caps); + if (res == AMF_OK) { + caps->GetProperty(get_opt_name(CAP_MAX_THROUGHPUT), + &enc->max_throughput); + } +} + static inline void check_preset_compatibility(amf_base *enc, const char *&preset) { - /* 1.9 * current base throughput == highQuality, - * 1.8 * current base throughput == quality, - * 1.1 * current base throughput == balanced */ - static constexpr amf_int64 throughput_high_quality_mul = 19; - static constexpr amf_int64 throughput_quality_mul = 18; - static constexpr amf_int64 throughput_balanced_mul = 11; + /* The throughput depends on the current preset and the other static + * encoder properties. If the throughput is lower than the max + * throughput, switch to a lower preset. */ - /* if the throughput * 1.9 is lower than the max throughput, switch to - * a lower preset */ if (astrcmpi(preset, "highQuality") == 0) { if (!enc->max_throughput) { - preset = "balanced"; + preset = "quality"; + set_opt(QUALITY_PRESET, get_preset(enc, preset)); } else { - amf_int64 req_throughput = enc->throughput * - throughput_high_quality_mul / - 10; - if (enc->max_throughput < req_throughput) + if (enc->max_throughput < enc->throughput) { preset = "quality"; + refresh_throughput_caps(enc, preset); + } } } - /* if the throughput * 1.8 is lower than the max throughput, switch to - * a lower preset */ if (astrcmpi(preset, "quality") == 0) { if (!enc->max_throughput) { preset = "balanced"; + set_opt(QUALITY_PRESET, get_preset(enc, preset)); } else { - amf_int64 req_throughput = - enc->throughput * throughput_quality_mul / 10; - if (enc->max_throughput < req_throughput) + if (enc->max_throughput < enc->throughput) { preset = "balanced"; + refresh_throughput_caps(enc, preset); + } } } if (astrcmpi(preset, "balanced") == 0) { - amf_int64 req_throughput = - enc->throughput * throughput_balanced_mul / 10; - if (enc->max_throughput && enc->max_throughput < req_throughput) + if (enc->max_throughput && + enc->max_throughput < enc->throughput) { preset = "speed"; + refresh_throughput_caps(enc, preset); + } } } @@ -1147,12 +1173,8 @@ static const char *amf_avc_get_name(void *) return "AMD HW H.264 (AVC)"; } -static inline int get_avc_preset(amf_base *enc, obs_data_t *settings) +static inline int get_avc_preset(amf_base *enc, const char *preset) { - const char *preset = obs_data_get_string(settings, "preset"); - - check_preset_compatibility(enc, preset); - if (astrcmpi(preset, "quality") == 0) return AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY; else if (astrcmpi(preset, "speed") == 0) @@ -1246,8 +1268,6 @@ static bool amf_avc_init(void *data, obs_data_t *settings) const char *rc_str = obs_data_get_string(settings, "rate_control"); int64_t bf = obs_data_get_int(settings, "bf"); - check_preset_compatibility(enc, preset); - if (enc->bframes_supported) { set_avc_property(enc, MAX_CONSECUTIVE_BPICTURES, 3); set_avc_property(enc, B_PIC_PATTERN, bf); @@ -1281,6 +1301,8 @@ static bool amf_avc_init(void *data, obs_data_t *settings) set_avc_property(enc, DE_BLOCKING_FILTER, true); + check_preset_compatibility(enc, preset); + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); if (ffmpeg_opts && *ffmpeg_opts) { struct obs_options opts = obs_parse_options(ffmpeg_opts); @@ -1329,9 +1351,11 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings) &enc->max_throughput); } + const char *preset = obs_data_get_string(settings, "preset"); + set_avc_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); set_avc_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); - set_avc_property(enc, QUALITY_PRESET, get_avc_preset(enc, settings)); + set_avc_property(enc, QUALITY_PRESET, get_avc_preset(enc, preset)); set_avc_property(enc, PROFILE, get_avc_profile(settings)); set_avc_property(enc, LOWLATENCY_MODE, false); set_avc_property(enc, CABAC_ENABLE, AMF_VIDEO_ENCODER_UNDEFINED); @@ -1473,12 +1497,8 @@ static const char *amf_hevc_get_name(void *) return "AMD HW H.265 (HEVC)"; } -static inline int get_hevc_preset(amf_base *enc, obs_data_t *settings) +static inline int get_hevc_preset(amf_base *enc, const char *preset) { - const char *preset = obs_data_get_string(settings, "preset"); - - check_preset_compatibility(enc, preset); - if (astrcmpi(preset, "balanced") == 0) return AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED; else if (astrcmpi(preset, "speed") == 0) @@ -1569,6 +1589,8 @@ static bool amf_hevc_init(void *data, obs_data_t *settings) set_hevc_property(enc, GOP_SIZE, gop_size); + check_preset_compatibility(enc, preset); + const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); if (ffmpeg_opts && *ffmpeg_opts) { struct obs_options opts = obs_parse_options(ffmpeg_opts); @@ -1642,10 +1664,11 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings) const bool pq = is_pq(enc); const bool hlg = is_hlg(enc); const bool is_hdr = pq || hlg; + const char *preset = obs_data_get_string(settings, "preset"); set_hevc_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); set_hevc_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); - set_hevc_property(enc, QUALITY_PRESET, get_hevc_preset(enc, settings)); + set_hevc_property(enc, QUALITY_PRESET, get_hevc_preset(enc, preset)); set_hevc_property(enc, COLOR_BIT_DEPTH, is10bit ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8); @@ -1801,12 +1824,8 @@ static const char *amf_av1_get_name(void *) return "AMD HW AV1"; } -static inline int get_av1_preset(amf_base *enc, obs_data_t *settings) +static inline int get_av1_preset(amf_base *enc, const char *preset) { - const char *preset = obs_data_get_string(settings, "preset"); - - check_preset_compatibility(enc, preset); - if (astrcmpi(preset, "highquality") == 0) return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY; else if (astrcmpi(preset, "quality") == 0) @@ -1910,8 +1929,6 @@ static bool amf_av1_init(void *data, obs_data_t *settings) const char *profile = obs_data_get_string(settings, "profile"); const char *rc_str = obs_data_get_string(settings, "rate_control"); - check_preset_compatibility(enc, preset); - int rc = get_av1_rate_control(rc_str); set_av1_property(enc, RATE_CONTROL_METHOD, rc); @@ -1933,6 +1950,8 @@ static bool amf_av1_init(void *data, obs_data_t *settings) obs_free_options(opts); } + check_preset_compatibility(enc, preset); + if (!ffmpeg_opts || !*ffmpeg_opts) ffmpeg_opts = "(none)"; @@ -1967,12 +1986,13 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) } const bool is10bit = enc->amf_format == AMF_SURFACE_P010; + const char *preset = obs_data_get_string(settings, "preset"); set_av1_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); set_av1_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); set_av1_property(enc, ALIGNMENT_MODE, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS); - set_av1_property(enc, QUALITY_PRESET, get_av1_preset(enc, settings)); + set_av1_property(enc, QUALITY_PRESET, get_av1_preset(enc, preset)); set_av1_property(enc, COLOR_BIT_DEPTH, is10bit ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8);