From 00988e70ac35d7cb8bc1ce9f46fb019b94f6a523 Mon Sep 17 00:00:00 2001 From: Evgeny Pavlov Date: Thu, 9 Feb 2023 11:16:19 +0100 Subject: [PATCH] amfcodec: Initial support of preanalysis and preencoding for AMF encoders Part-of: --- .../sys/amfcodec/gstamfav1enc.cpp | 312 ++++++++++- .../sys/amfcodec/gstamfencoder.cpp | 499 +++++++++++++++++- .../sys/amfcodec/gstamfencoder.h | 87 ++- .../sys/amfcodec/gstamfh264enc.cpp | 309 ++++++++++- .../sys/amfcodec/gstamfh265enc.cpp | 311 ++++++++++- 5 files changed, 1510 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfav1enc.cpp b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfav1enc.cpp index e3f27d6339..dc0b19ba6b 100644 --- a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfav1enc.cpp +++ b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfav1enc.cpp @@ -73,7 +73,9 @@ typedef struct amf_int64 max_gop_size; amf_int64 default_gop_size; guint valign; + gboolean pre_encode_supported; gboolean smart_access_supported; + GstAmfEncoderPASupportedOptions pa_supported; } GstAmfAv1EncDeviceCaps; /** @@ -265,7 +267,23 @@ enum PROP_QP_I, PROP_QP_P, PROP_REF_FRAMES, - PROP_SMART_ACCESS + PROP_SMART_ACCESS, + PROP_PRE_ENCODE, + PROP_PRE_ANALYSIS, + PROP_PA_ACTIVITY_TYPE, + PROP_PA_SCENE_CHANGE_DETECTION, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + PROP_PA_STATIC_SCENE_DETECTION, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + PROP_PA_INITIAL_QP, + PROP_PA_MAX_QP, + PROP_PA_CAQ_STRENGTH, + PROP_PA_FRAME_SAD, + PROP_PA_LTR, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + PROP_PA_PAQ_MODE, + PROP_PA_TAQ_MODE, + PROP_PA_HQMB_MODE, }; #define DEFAULT_USAGE AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING @@ -276,6 +294,7 @@ enum #define DEFAULT_MIN_MAX_QP -1 #define DEFAULT_REF_FRAMES 1 #define DEFAULT_SMART_ACCESS FALSE +#define DEFAULT_PRE_ENCODE FALSE #define DOC_SINK_CAPS_COMM \ "format = (string) {NV12, P010_10LE}, " \ @@ -309,6 +328,8 @@ typedef struct _GstAmfAv1Enc guint qp_p; guint ref_frames; gboolean smart_access; + gboolean pre_encode; + GstAmfEncoderPreAnalysis pa; } GstAmfAv1Enc; typedef struct _GstAmfAv1EncClass @@ -346,8 +367,11 @@ gst_amf_av1_enc_class_init (GstAmfAv1EncClass * klass, gpointer data) GstAmfEncoderClass *amf_class = GST_AMF_ENCODER_CLASS (klass); GstAmfAv1EncClassData *cdata = (GstAmfAv1EncClassData *) data; GstAmfAv1EncDeviceCaps *dev_caps = &cdata->dev_caps; + GstAmfEncoderPASupportedOptions *pa_supported = &dev_caps->pa_supported; GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS); + GParamFlags pa_param_flags = (GParamFlags) (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | GST_PARAM_CONDITIONALLY_AVAILABLE); GstPadTemplate *pad_templ; GstCaps *doc_caps; @@ -413,7 +437,12 @@ gst_amf_av1_enc_class_init (GstAmfAv1EncClass * klass, gpointer data) g_object_class_install_property (object_class, PROP_REF_FRAMES, g_param_spec_uint ("ref-frames", "Reference Frames", "Number of reference frames", 0, 8, DEFAULT_REF_FRAMES, param_flags)); - + if (cdata->dev_caps.pre_encode_supported) { + g_object_class_install_property (object_class, PROP_PRE_ENCODE, + g_param_spec_boolean ("pre-encode", "Pre-encode", + "Enable pre-encode", DEFAULT_PRE_ENCODE, + (GParamFlags) (param_flags | GST_PARAM_CONDITIONALLY_AVAILABLE))); + } if (cdata->dev_caps.smart_access_supported) { g_object_class_install_property (object_class, PROP_SMART_ACCESS, g_param_spec_boolean ("smart-access-video", "Smart Access Video", @@ -424,6 +453,113 @@ gst_amf_av1_enc_class_init (GstAmfAv1EncClass * klass, gpointer data) GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS))); } + if (dev_caps->pre_analysis) { + g_object_class_install_property (object_class, PROP_PRE_ANALYSIS, + g_param_spec_boolean ("pre-analysis", "Pre-analysis", + "Enable pre-analysis", DEFAULT_PRE_ANALYSIS, param_flags)); + if (pa_supported->activity_type) { + g_object_class_install_property (object_class, PROP_PA_ACTIVITY_TYPE, + g_param_spec_enum ("pa-activity-type", "Pre-analysis activity type", + "Set the type of activity analysis for pre-analysis", + GST_TYPE_AMF_ENC_PA_ACTIVITY_TYPE, DEFAULT_PA_ACTIVITY_TYPE, + pa_param_flags)); + } + if (pa_supported->scene_change_detection) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION, + g_param_spec_boolean ("pa-scene-change-detection", + "Pre-analysis scene change detection", + "Enable scene change detection for pre-analysis", + DEFAULT_PA_SCENE_CHANGE_DETECTION, pa_param_flags)); + } + if (pa_supported->scene_change_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-scene-change-detection-sensitivity", + "Pre-analysis scene change detection sensitivity", + "Set the sensitivity of scene change detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->static_scene_detection) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION, + g_param_spec_boolean ("pa-static-scene-detection", + "Pre-analysis static scene detection", + "Enable static scene detection for pre-analysis", + DEFAULT_PA_STATIC_SCENE_DETECTION, pa_param_flags)); + } + if (pa_supported->static_scene_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-static-scene-detection-sensitivity", + "Pre-analysis static scene detection sensitivity", + "Set the sensitivity of static scene detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->initial_qp) { + g_object_class_install_property (object_class, PROP_PA_INITIAL_QP, + g_param_spec_uint ("pa-initial-qp", "Pre-analysis initial QP", + "The QP value that is used immediately after a scene change", 0, + 51, DEFAULT_PA_INITIAL_QP, pa_param_flags)); + } + if (pa_supported->max_qp) { + g_object_class_install_property (object_class, PROP_PA_MAX_QP, + g_param_spec_uint ("pa-max-qp", "Pre-analysis max QP", + "The QP threshold to allow a skip frame", 0, 51, + DEFAULT_PA_MAX_QP, pa_param_flags)); + } + if (pa_supported->caq_strength) { + g_object_class_install_property (object_class, PROP_PA_CAQ_STRENGTH, + g_param_spec_enum ("pa-caq-strength", "Pre-analysis CAQ strength", + "Content Adaptive Quantization strength for pre-analysis", + GST_TYPE_AMF_ENC_PA_CAQ_STRENGTH, DEFAULT_PA_CAQ_STRENGTH, + pa_param_flags)); + } + if (pa_supported->frame_sad) { + g_object_class_install_property (object_class, PROP_PA_FRAME_SAD, + g_param_spec_boolean ("pa-frame-sad", "Pre-analysis SAD algorithm", + "Enable Frame SAD algorithm", DEFAULT_PA_FRAME_SAD, + pa_param_flags)); + } + if (pa_supported->ltr) { + g_object_class_install_property (object_class, PROP_PA_LTR, + g_param_spec_boolean ("pa-ltr", "Pre-analysis LTR", + "Enable long term reference frame management", DEFAULT_PA_LTR, + pa_param_flags)); + } + if (pa_supported->lookahead_buffer_depth) { + g_object_class_install_property (object_class, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + g_param_spec_uint ("pa-lookahead-buffer-depth", + "Pre-analysis lookahead buffer depth", + "Set the PA lookahead buffer size", 0, 41, + DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH, pa_param_flags)); + } + if (pa_supported->paq_mode) { + g_object_class_install_property (object_class, PROP_PA_PAQ_MODE, + g_param_spec_enum ("pa-paq-mode", "Pre-analysis PAQ mode", + "Set the perceptual adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_PAQ_MODE, DEFAULT_PA_PAQ_MODE, + pa_param_flags)); + } + if (pa_supported->taq_mode) { + g_object_class_install_property (object_class, PROP_PA_TAQ_MODE, + g_param_spec_enum ("pa-taq-mode", "Pre-analysis TAQ mode", + "Set the temporal adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_TAQ_MODE, DEFAULT_PA_TAQ_MODE, + pa_param_flags)); + } + if (pa_supported->hmqb_mode) { + g_object_class_install_property (object_class, PROP_PA_HQMB_MODE, + g_param_spec_enum ("pa-hqmb-mode", "Pre-analysis HQMB mode", + "Set the PA high motion quality boost mode", + GST_TYPE_AMF_ENC_PA_HQMB_MODE, DEFAULT_PA_HQMB_MODE, + pa_param_flags)); + } + } + gst_element_class_set_metadata (element_class, "AMD AMF AV1 Video Encoder", "Codec/Encoder/Video/Hardware", @@ -495,6 +631,25 @@ gst_amf_av1_enc_init (GstAmfAv1Enc * self) self->qp_p = (guint) dev_caps->default_qp_p; self->ref_frames = DEFAULT_REF_FRAMES; self->smart_access = DEFAULT_SMART_ACCESS; + self->pre_encode = DEFAULT_PRE_ENCODE; + // Init pre-analysis options + self->pa.pre_analysis = DEFAULT_PRE_ANALYSIS; + self->pa.activity_type = DEFAULT_PA_ACTIVITY_TYPE; + self->pa.scene_change_detection = DEFAULT_PA_SCENE_CHANGE_DETECTION; + self->pa.scene_change_detection_sensitivity = + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY; + self->pa.static_scene_detection = DEFAULT_PA_STATIC_SCENE_DETECTION; + self->pa.static_scene_detection_sensitivity = + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY; + self->pa.initial_qp = DEFAULT_PA_INITIAL_QP; + self->pa.max_qp = DEFAULT_PA_MAX_QP; + self->pa.caq_strength = DEFAULT_PA_CAQ_STRENGTH; + self->pa.frame_sad = DEFAULT_PA_FRAME_SAD; + self->pa.ltr = DEFAULT_PA_LTR; + self->pa.lookahead_buffer_depth = DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH; + self->pa.paq_mode = DEFAULT_PA_PAQ_MODE; + self->pa.taq_mode = DEFAULT_PA_TAQ_MODE; + self->pa.hmqb_mode = DEFAULT_PA_HQMB_MODE; } static void @@ -605,6 +760,53 @@ gst_amf_av1_enc_set_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: update_bool (self, &self->smart_access, value); break; + case PROP_PRE_ENCODE: + update_bool (self, &self->pre_encode, value); + break; + case PROP_PRE_ANALYSIS: + update_bool (self, &self->pa.pre_analysis, value); + break; + case PROP_PA_ACTIVITY_TYPE: + update_enum (self, &self->pa.activity_type, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + update_bool (self, &self->pa.scene_change_detection, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.scene_change_detection_sensitivity, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + update_bool (self, &self->pa.static_scene_detection, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.static_scene_detection_sensitivity, value); + break; + case PROP_PA_INITIAL_QP: + update_uint (self, &self->pa.initial_qp, value); + break; + case PROP_PA_MAX_QP: + update_uint (self, &self->pa.max_qp, value); + break; + case PROP_PA_CAQ_STRENGTH: + update_enum (self, &self->pa.caq_strength, value); + break; + case PROP_PA_FRAME_SAD: + update_bool (self, &self->pa.frame_sad, value); + case PROP_PA_LTR: + update_bool (self, &self->pa.ltr, value); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + update_uint (self, &self->pa.lookahead_buffer_depth, value); + break; + case PROP_PA_PAQ_MODE: + update_enum (self, &self->pa.paq_mode, value); + break; + case PROP_PA_TAQ_MODE: + update_enum (self, &self->pa.taq_mode, value); + break; + case PROP_PA_HQMB_MODE: + update_enum (self, &self->pa.hmqb_mode, value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -665,6 +867,54 @@ gst_amf_av1_enc_get_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: g_value_set_boolean (value, self->smart_access); break; + case PROP_PRE_ENCODE: + g_value_set_boolean (value, self->pre_encode); + break; + case PROP_PRE_ANALYSIS: + g_value_set_boolean (value, self->pa.pre_analysis); + break; + case PROP_PA_ACTIVITY_TYPE: + g_value_set_enum (value, self->pa.activity_type); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + g_value_set_boolean (value, self->pa.scene_change_detection); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.scene_change_detection_sensitivity); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + g_value_set_boolean (value, self->pa.static_scene_detection); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.static_scene_detection_sensitivity); + break; + case PROP_PA_INITIAL_QP: + g_value_set_uint (value, self->pa.initial_qp); + break; + case PROP_PA_MAX_QP: + g_value_set_uint (value, self->pa.max_qp); + break; + case PROP_PA_CAQ_STRENGTH: + g_value_set_enum (value, self->pa.caq_strength); + break; + case PROP_PA_FRAME_SAD: + g_value_set_boolean (value, self->pa.frame_sad); + break; + case PROP_PA_LTR: + g_value_set_boolean (value, self->pa.ltr); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + g_value_set_uint (value, self->pa.lookahead_buffer_depth); + break; + case PROP_PA_PAQ_MODE: + g_value_set_enum (value, self->pa.paq_mode); + break; + case PROP_PA_TAQ_MODE: + g_value_set_enum (value, self->pa.taq_mode); + break; + case PROP_PA_HQMB_MODE: + g_value_set_enum (value, self->pa.hmqb_mode); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -871,6 +1121,33 @@ gst_amf_av1_enc_set_format (GstAmfEncoder * encoder, } } + if (dev_caps->pre_encode_supported) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE, + (amf_bool) self->pre_encode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-encode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + } + + if (dev_caps->pre_analysis) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, + (amf_bool) self->pa.pre_analysis); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + if (self->pa.pre_analysis) { + result = + gst_amf_encoder_set_pre_analysis_options (encoder, comp, &self->pa, + &dev_caps->pa_supported); + if (result != AMF_OK) + goto error; + } + } + result = comp->Init (surface_format, info->width, info->height); if (result != AMF_OK) { GST_ERROR_OBJECT (self, "Failed to init component, result %" @@ -1093,6 +1370,7 @@ gst_amf_av1_enc_create_class_data (GstD3D11Device * device, AMFComponent * comp) amf_int32 in_min_height = 0, in_max_height = 0; amf_int32 out_min_width = 0, out_max_width = 0; amf_int32 out_min_height = 0, out_max_height = 0; + amf_bool pre_encode_supported; amf_bool smart_access_supported; amf_int32 num_val; std::set < std::string > formats; @@ -1247,11 +1525,41 @@ gst_amf_av1_enc_create_class_data (GstD3D11Device * device, AMFComponent * comp) QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER, default_qp_p, 26); #undef QUERY_DEFAULT_PROP + result = comp->GetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE, + &pre_encode_supported); + if (result == AMF_OK) + dev_caps.pre_encode_supported = TRUE; + result = comp->GetProperty (AMF_VIDEO_ENCODER_AV1_ENABLE_SMART_ACCESS_VIDEO, &smart_access_supported); if (result == AMF_OK) dev_caps.smart_access_supported = TRUE; + if (dev_caps.pre_analysis) { + amf_bool pre_analysis = FALSE; + // Store initial pre-analysis value + result = + comp->GetProperty (AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, + &pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to get pre-analysis option"); + } + // We need to enable pre-analysis for checking options availability + result = + comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, + (amf_bool) TRUE); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis option"); + } + gst_amf_encoder_check_pa_supported_options (&dev_caps.pa_supported, comp); + result = + comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, + pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis option"); + } + } + { const AMFPropertyInfo *pinfo = nullptr; result = comp->GetPropertyInfo (AMF_VIDEO_ENCODER_AV1_GOP_SIZE, &pinfo); diff --git a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.cpp b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.cpp index a0e3d9eee3..ece85adcf9 100644 --- a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.cpp +++ b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.cpp @@ -35,6 +35,300 @@ using namespace Microsoft::WRL; using namespace amf; /* *INDENT-ON* */ +/** + * GstAmfEncPAActivityType: + * + * Determines whether activity analysis is performed on the Luma component + * only (Y) or on both Luma and Chroma (YUV). + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_activity_get_type (void) +{ + static GType pa_activity_type = 0; + static const GEnumValue activity_types[] = { + /** + * GstAmfEncPAActivityType::y: + * + * Activity analysis is performed on the Luma component only (Y) + */ + {AMF_PA_ACTIVITY_Y, "Luma (Y) component only", + "y"}, + + /** + * GstAmfEncPAActivityType::yuv: + * + * Activity analysis is performed on both Luma and Chroma components (YUV) + */ + {AMF_PA_ACTIVITY_YUV, "Luma and Chroma components (YUV)", "yuv"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_activity_type)) { + GType type = + g_enum_register_static ("GstAmfEncPAActivityType", activity_types); + g_once_init_leave (&pa_activity_type, type); + } + + return pa_activity_type; +} + +/** + * GstAmfEncPASceneChangeDetectionSensitivity: + * + * Sensitivity of scene change detection. The higher the sensitivity, the more + * restrictive it is to detect a scene change. This parameter takes effect + * only when AMF_PA_LOOKAHEAH_BUFFER_DEPTH is set to 0. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_scene_change_detection_sensitivity_get_type (void) +{ + static GType pa_scene_change_detection_sensitivity = 0; + static const GEnumValue sensitivity_types[] = { + /** + * GstAmfEncPASceneChangeDetectionSensitivity::low: + * + * Low sensitivity + */ + {AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW, "Low", "low"}, + + /** + * GstAmfEncPASceneChangeDetectionSensitivity::medium: + * + * Medium sensitivity + */ + {AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM, "Medium", "medium"}, + + /** + * GstAmfEncPASceneChangeDetectionSensitivity::high: + * + * High sensitivity + */ + {AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, "High", "high"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_scene_change_detection_sensitivity)) { + GType type = + g_enum_register_static + ("GstAmfEncPASceneChangeDetectionSensitivity", sensitivity_types); + g_once_init_leave (&pa_scene_change_detection_sensitivity, type); + } + + return pa_scene_change_detection_sensitivity; +} + +/** + * GstAmfEncPAStaticSceneDetectionSensitivity: + * + * Sensitivity of static scene detection. The higher the sensitivity, the more + * restrictive it is to detect a static scene. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_static_scene_detection_sensitivity_get_type (void) +{ + static GType pa_static_scene_detection_sensitivity = 0; + static const GEnumValue sensitivity_types[] = { + /** + * GstAmfEncPAStaticSceneDetectionSensitivity::low: + * + * Low sensitivity + */ + {AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW, "Low", "low"}, + + /** + * GstAmfEncPAStaticSceneDetectionSensitivity::medium: + * + * Medium sensitivity + */ + {AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM, "Medium", "medium"}, + + /** + * GstAmfEncPAStaticSceneDetectionSensitivity::high: + * + * High sensitivity + */ + {AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, "High", "high"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_static_scene_detection_sensitivity)) { + GType type = + g_enum_register_static + ("GstAmfEncPAStaticSceneDetectionSensitivity", sensitivity_types); + g_once_init_leave (&pa_static_scene_detection_sensitivity, type); + } + + return pa_static_scene_detection_sensitivity; +} + +/** + * GstAmfEncPACAQStrength: + * + * Content Adaptive Quantization strength. Stronger CAQ strength means larger + * variation in block level QP assignment. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_caq_strength_get_type (void) +{ + static GType pa_caq_strength = 0; + static const GEnumValue strength_types[] = { + /** + * GstAmfEncPACAQStrength::low: + * + * Low strength + */ + {AMF_PA_CAQ_STRENGTH_LOW, "Low", "low"}, + + /** + * GstAmfEncPACAQStrength::medium: + * + * Medium strength + */ + {AMF_PA_CAQ_STRENGTH_MEDIUM, "Medium", "medium"}, + + /** + * GstAmfEncPACAQStrength::high: + * + * High strength + */ + {AMF_PA_CAQ_STRENGTH_HIGH, "High", "high"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_caq_strength)) { + GType type = + g_enum_register_static ("GstAmfEncPACAQStrength", strength_types); + g_once_init_leave (&pa_caq_strength, type); + } + + return pa_caq_strength; +} + +/** + * GstAmfEncPAPAQMode: + * + * Sets the perceptual adaptive quantization mode. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_paq_mode_get_type (void) +{ + static GType pa_paq_mode = 0; + static const GEnumValue paq_modes[] = { + /** + * GstAmfEncPAPAQMode::none: + * + * No perceptual adaptive quantization + */ + {AMF_PA_PAQ_MODE_NONE, "None", "none"}, + + /** + * GstAmfEncPAPAQMode::caq: + * + * Content Adaptive Quantization (CAQ) mode + */ + {AMF_PA_PAQ_MODE_CAQ, "Content Adaptive Quantization (CAQ) mode", "caq"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_paq_mode)) { + GType type = g_enum_register_static ("GstAmfEncPAPAQMode", paq_modes); + g_once_init_leave (&pa_paq_mode, type); + } + + return pa_paq_mode; +} + +/** + * GstAmfEncPATAQMode: + * + * Sets the temporal adaptive quantization mode. MODE_1 is suitable for non-gaming + * applications whereas MODE_2 is suitable for gaming applications. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_taq_mode_get_type (void) +{ + static GType pa_taq_mode = 0; + static const GEnumValue taq_modes[] = { + /** + * GstAmfEncPATAQMode::none: + * + * No temporal adaptive quantization + */ + {AMF_PA_TAQ_MODE_NONE, "None", "none"}, + + /** + * GstAmfEncPATAQMode::mode1: + * + * MODE_1 is suitable for non-gaming applications + */ + {AMF_PA_TAQ_MODE_1, "Mode_1 is suitable for non-gaming applications", + "mode1"}, + + /** + * GstAmfEncPATAQMode::mode2: + * + * MODE_2 is suitable for for gaming applications + */ + {AMF_PA_TAQ_MODE_2, "Mode_2 is suitable for gaming applications", "mode2"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_taq_mode)) { + GType type = g_enum_register_static ("GstAmfEncPATAQMode", taq_modes); + g_once_init_leave (&pa_taq_mode, type); + } + + return pa_taq_mode; +} + +/** + * GstAmfEncPAHQMBMode: + * + * Sets the PA high motion quality boost (HQMB) mode to help the encoder in motion search. + * + * Since: 1.24 + */ +GType +gst_amf_enc_pa_hmbq_mode_get_type (void) +{ + static GType pa_hmbq_mode = 0; + static const GEnumValue hmbq_modes[] = { + /** + * GstAmfEncPAHQMBMode::none: + * + * No high motion quality boost + */ + {AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE, "None", "none"}, + + /** + * GstAmfEncPAHQMBMode::auto: + * + * Automatic mode + */ + {AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO, "Auto", "auto"}, + {0, nullptr, nullptr} + }; + + if (g_once_init_enter (&pa_hmbq_mode)) { + GType type = g_enum_register_static ("GstAmfEncPAHQMBMode", hmbq_modes); + g_once_init_leave (&pa_hmbq_mode, type); + } + + return pa_hmbq_mode; +} + GST_DEBUG_CATEGORY_STATIC (gst_amf_encoder_debug); #define GST_CAT_DEFAULT gst_amf_encoder_debug @@ -122,6 +416,22 @@ gst_amf_encoder_class_init (GstAmfEncoderClass * klass) "amfencoder", 0, "amfencoder"); gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENCODER, (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENC_PA_ACTIVITY_TYPE, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api + (GST_TYPE_AMF_ENC_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api + (GST_TYPE_AMF_ENC_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENC_PA_CAQ_STRENGTH, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENC_PA_PAQ_MODE, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENC_PA_TAQ_MODE, + (GstPluginAPIFlags) 0); + gst_type_mark_as_plugin_api (GST_TYPE_AMF_ENC_PA_HQMB_MODE, + (GstPluginAPIFlags) 0); } static void @@ -466,7 +776,7 @@ gst_amf_encoder_prepare_internal_pool (GstAmfEncoder * self) GST_VIDEO_INFO_SIZE (info), 0, 0); params = gst_d3d11_allocation_params_new (priv->device, info, - GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, 0); + GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0); params->desc[0].MiscFlags = D3D11_RESOURCE_MISC_SHARED; gst_buffer_pool_config_set_d3d11_allocation_params (config, params); @@ -775,7 +1085,8 @@ gst_amf_encoder_upload_buffer (GstAmfEncoder * self, GstBuffer * buffer) } gst_d3d11_memory_get_texture_desc (dmem, &desc); - if (desc.Usage != D3D11_USAGE_DEFAULT) { + if (desc.Usage != D3D11_USAGE_DEFAULT + || (desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) == 0) { GST_TRACE_OBJECT (self, "Not a default usage texture, d3d11 copy"); gst_d3d11_device_lock (priv->device); ret = gst_amf_encoder_copy_d3d11 (self, buffer, FALSE); @@ -1012,6 +1323,7 @@ gst_amf_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) GstCapsFeatures *features; gboolean is_d3d11 = FALSE; guint min_buffers = 0; + GstD3D11AllocationParams *params; gst_query_parse_allocation (query, &caps, nullptr); if (!caps) { @@ -1048,6 +1360,11 @@ gst_amf_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) size = GST_VIDEO_INFO_SIZE (&info); gst_buffer_pool_config_set_params (config, caps, size, min_buffers, 0); + params = gst_d3d11_allocation_params_new (device, &info, + GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0); + gst_buffer_pool_config_set_d3d11_allocation_params (config, params); + gst_d3d11_allocation_params_free (params); + if (!gst_buffer_pool_set_config (pool, config)) { GST_WARNING_OBJECT (self, "Failed to set pool config"); gst_object_unref (pool); @@ -1082,3 +1399,181 @@ gst_amf_encoder_set_subclass_data (GstAmfEncoder * encoder, gint64 adapter_luid, priv->codec_id = codec_id; } /* *INDENT-ON* */ + +AMF_RESULT +gst_amf_encoder_set_pre_analysis_options (GstAmfEncoder * self, + AMFComponent * comp, const GstAmfEncoderPreAnalysis * pa, + GstAmfEncoderPASupportedOptions * pa_supported) +{ + AMF_RESULT result; + if (pa_supported->activity_type) { + result = comp->SetProperty (AMF_PA_ACTIVITY_TYPE, + (AMF_PA_ACTIVITY_TYPE_ENUM) pa->activity_type); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis activity type, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->scene_change_detection) { + result = comp->SetProperty (AMF_PA_SCENE_CHANGE_DETECTION_ENABLE, + (amf_bool) pa->scene_change_detection); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis scene change detection, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->scene_change_detection_sensitivity) { + result = comp->SetProperty (AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + (AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_ENUM) + pa->scene_change_detection_sensitivity); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis scene change detection sensitivity, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->static_scene_detection) { + result = comp->SetProperty (AMF_PA_STATIC_SCENE_DETECTION_ENABLE, + (amf_bool) pa->static_scene_detection); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis static scene detection, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->static_scene_detection_sensitivity) { + result = comp->SetProperty (AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + (AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_ENUM) + pa->static_scene_detection_sensitivity); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis static scene detection sensitivity, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->initial_qp) { + result = comp->SetProperty (AMF_PA_INITIAL_QP_AFTER_SCENE_CHANGE, + (amf_int64) pa->initial_qp); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis initial QP, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->max_qp) { + result = comp->SetProperty (AMF_PA_MAX_QP_BEFORE_FORCE_SKIP, + (amf_int64) pa->max_qp); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis max QP, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->caq_strength) { + result = comp->SetProperty (AMF_PA_CAQ_STRENGTH, + (amf_int64) pa->caq_strength); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis CAQ strength, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->frame_sad) { + result = comp->SetProperty (AMF_PA_FRAME_SAD_ENABLE, + (amf_bool) pa->frame_sad); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis frame SAD algorithm, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->ltr) { + result = comp->SetProperty (AMF_PA_LTR_ENABLE, (amf_bool) pa->ltr); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis automatic Long Term Reference frame management, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->lookahead_buffer_depth) { + result = comp->SetProperty (AMF_PA_LOOKAHEAD_BUFFER_DEPTH, + (amf_int64) pa->lookahead_buffer_depth); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis lookahead buffer depth, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->paq_mode) { + result = comp->SetProperty (AMF_PA_PAQ_MODE, (amf_int64) pa->paq_mode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis PAQ mode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->taq_mode) { + result = comp->SetProperty (AMF_PA_TAQ_MODE, (amf_int64) pa->taq_mode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis TAQ mode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + if (pa_supported->hmqb_mode) { + result = comp->SetProperty (AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE, + (amf_int64) pa->hmqb_mode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, + "Failed to set pre-analysis high motion quality boost mode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + return result; + } + } + return AMF_OK; +} + +void +gst_amf_encoder_check_pa_supported_options (GstAmfEncoderPASupportedOptions * + pa_supported, AMFComponent * comp) +{ + if (comp->HasProperty (AMF_PA_ACTIVITY_TYPE)) + pa_supported->activity_type = TRUE; + if (comp->HasProperty (AMF_PA_SCENE_CHANGE_DETECTION_ENABLE)) + pa_supported->scene_change_detection = TRUE; + if (comp->HasProperty (AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY)) + pa_supported->scene_change_detection_sensitivity = TRUE; + if (comp->HasProperty (AMF_PA_STATIC_SCENE_DETECTION_ENABLE)) + pa_supported->static_scene_detection = TRUE; + if (comp->HasProperty (AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY)) + pa_supported->static_scene_detection_sensitivity = TRUE; + if (comp->HasProperty (AMF_PA_INITIAL_QP_AFTER_SCENE_CHANGE)) + pa_supported->initial_qp = TRUE; + if (comp->HasProperty (AMF_PA_MAX_QP_BEFORE_FORCE_SKIP)) + pa_supported->max_qp = TRUE; + if (comp->HasProperty (AMF_PA_CAQ_STRENGTH)) + pa_supported->caq_strength = TRUE; + if (comp->HasProperty (AMF_PA_FRAME_SAD_ENABLE)) + pa_supported->frame_sad = TRUE; + if (comp->HasProperty (AMF_PA_LTR_ENABLE)) + pa_supported->ltr = TRUE; + if (comp->HasProperty (AMF_PA_LOOKAHEAD_BUFFER_DEPTH)) + pa_supported->lookahead_buffer_depth = TRUE; + if (comp->HasProperty (AMF_PA_PAQ_MODE)) + pa_supported->paq_mode = TRUE; + if (comp->HasProperty (AMF_PA_TAQ_MODE)) + pa_supported->taq_mode = TRUE; + if (comp->HasProperty (AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE)) + pa_supported->hmqb_mode = TRUE; +} diff --git a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.h b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.h index fe2c0e92de..3e72fc0d37 100644 --- a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.h +++ b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfencoder.h @@ -19,6 +19,8 @@ #pragma once +#include +#include #include #include #include "gstamfutils.h" @@ -37,6 +39,42 @@ typedef struct _GstAmfEncoder GstAmfEncoder; typedef struct _GstAmfEncoderClass GstAmfEncoderClass; typedef struct _GstAmfEncoderPrivate GstAmfEncoderPrivate; +typedef struct _GstAmfEncoderPASupportedOptions { + gboolean activity_type; + gboolean scene_change_detection; + gboolean scene_change_detection_sensitivity; + gboolean static_scene_detection; + gboolean static_scene_detection_sensitivity; + gboolean initial_qp; + gboolean max_qp; + gboolean caq_strength; + gboolean frame_sad; + gboolean ltr; + gboolean lookahead_buffer_depth; + gboolean paq_mode; + gboolean taq_mode; + gboolean hmqb_mode; +} GstAmfEncoderPASupportedOptions; + +typedef struct _GstAmfEncoderPreAnalysis +{ + gboolean pre_analysis; + gint activity_type; + gboolean scene_change_detection; + gint scene_change_detection_sensitivity; + gboolean static_scene_detection; + gint static_scene_detection_sensitivity; + guint initial_qp; + guint max_qp; + gint caq_strength; + gboolean frame_sad; + gboolean ltr; + guint lookahead_buffer_depth; + gint paq_mode; + gint taq_mode; + gint hmqb_mode; +} GstAmfEncoderPreAnalysis; + struct _GstAmfEncoder { GstVideoEncoder parent; @@ -47,7 +85,7 @@ struct _GstAmfEncoder struct _GstAmfEncoderClass { GstVideoEncoderClass parent_class; - + GstAmfEncoderPASupportedOptions pa_supported; gboolean (*set_format) (GstAmfEncoder * encoder, GstVideoCodecState * state, gpointer component); @@ -73,6 +111,53 @@ void gst_amf_encoder_set_subclass_data (GstAmfEncoder * encoder, gint64 adapter_luid, const wchar_t * codec_id); +AMF_RESULT gst_amf_encoder_set_pre_analysis_options (GstAmfEncoder * self, + amf::AMFComponent * comp, + const GstAmfEncoderPreAnalysis * pa, + GstAmfEncoderPASupportedOptions * pa_supported); + +void gst_amf_encoder_check_pa_supported_options (GstAmfEncoderPASupportedOptions * pa_supported, + amf::AMFComponent * comp); + +// Pre-analysis settings +#define DEFAULT_PRE_ANALYSIS FALSE +#define DEFAULT_PA_ACTIVITY_TYPE AMF_PA_ACTIVITY_Y +#define DEFAULT_PA_SCENE_CHANGE_DETECTION TRUE +#define DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM +#define DEFAULT_PA_STATIC_SCENE_DETECTION FALSE +#define DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH + +#define DEFAULT_PA_INITIAL_QP 0 +#define DEFAULT_PA_MAX_QP 35 +#define DEFAULT_PA_CAQ_STRENGTH AMF_PA_CAQ_STRENGTH_MEDIUM +#define DEFAULT_PA_FRAME_SAD TRUE +#define DEFAULT_PA_LTR FALSE +#define DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH 0 +#define DEFAULT_PA_PAQ_MODE AMF_PA_PAQ_MODE_NONE +#define DEFAULT_PA_TAQ_MODE AMF_PA_TAQ_MODE_NONE +#define DEFAULT_PA_HQMB_MODE AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE + +#define GST_TYPE_AMF_ENC_PA_ACTIVITY_TYPE (gst_amf_enc_pa_activity_get_type ()) +GType gst_amf_enc_pa_activity_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_SCENE_CHANGE_DETECTION_SENSITIVITY (gst_amf_enc_pa_scene_change_detection_sensitivity_get_type ()) +GType gst_amf_enc_pa_scene_change_detection_sensitivity_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_STATIC_SCENE_DETECTION_SENSITIVITY (gst_amf_enc_pa_static_scene_detection_sensitivity_get_type ()) +GType gst_amf_enc_pa_static_scene_detection_sensitivity_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_CAQ_STRENGTH (gst_amf_enc_pa_caq_strength_get_type ()) +GType gst_amf_enc_pa_caq_strength_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_PAQ_MODE (gst_amf_enc_pa_paq_mode_get_type ()) +GType gst_amf_enc_pa_paq_mode_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_TAQ_MODE (gst_amf_enc_pa_taq_mode_get_type ()) +GType gst_amf_enc_pa_taq_mode_get_type (void); + +#define GST_TYPE_AMF_ENC_PA_HQMB_MODE (gst_amf_enc_pa_hmbq_mode_get_type ()) +GType gst_amf_enc_pa_hmbq_mode_get_type (void); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstAmfEncoder, gst_object_unref) G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh264enc.cpp b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh264enc.cpp index 76b67e192b..45a65a80b9 100644 --- a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh264enc.cpp +++ b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh264enc.cpp @@ -77,7 +77,9 @@ typedef struct amf_int64 default_qp_b; gboolean interlace_supported; guint valign; + gboolean pre_encode_supported; gboolean smart_access_supported; + GstAmfEncoderPASupportedOptions pa_supported; } GstAmfH264EncDeviceCaps; /** @@ -274,7 +276,23 @@ enum PROP_REF_FRAMES, PROP_AUD, PROP_CABAC, - PROP_SMART_ACCESS + PROP_SMART_ACCESS, + PROP_PRE_ENCODE, + PROP_PRE_ANALYSIS, + PROP_PA_ACTIVITY_TYPE, + PROP_PA_SCENE_CHANGE_DETECTION, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + PROP_PA_STATIC_SCENE_DETECTION, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + PROP_PA_INITIAL_QP, + PROP_PA_MAX_QP, + PROP_PA_CAQ_STRENGTH, + PROP_PA_FRAME_SAD, + PROP_PA_LTR, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + PROP_PA_PAQ_MODE, + PROP_PA_TAQ_MODE, + PROP_PA_HQMB_MODE, }; #define DEFAULT_USAGE AMF_VIDEO_ENCODER_USAGE_TRANSCODING @@ -287,6 +305,7 @@ enum #define DEFAULT_AUD TRUE #define DEFAULT_CABAC TRUE #define DEFAULT_SMART_ACCESS FALSE +#define DEFAULT_PRE_ENCODE FALSE #define DOC_SINK_CAPS_COMM \ "format = (string) NV12, " \ @@ -301,6 +320,7 @@ enum "profile = (string) { main, high, constrained-baseline, baseline }, " \ "stream-format = (string) { avc, byte-stream }, alignment = (string) au" + typedef struct _GstAmfH264Enc { GstAmfEncoder parent; @@ -326,6 +346,8 @@ typedef struct _GstAmfH264Enc gboolean aud; gboolean cabac; gboolean smart_access; + gboolean pre_encode; + GstAmfEncoderPreAnalysis pa; } GstAmfH264Enc; typedef struct _GstAmfH264EncClass @@ -366,8 +388,11 @@ gst_amf_h264_enc_class_init (GstAmfH264EncClass * klass, gpointer data) GstAmfEncoderClass *amf_class = GST_AMF_ENCODER_CLASS (klass); GstAmfH264EncClassData *cdata = (GstAmfH264EncClassData *) data; GstAmfH264EncDeviceCaps *dev_caps = &cdata->dev_caps; + GstAmfEncoderPASupportedOptions *pa_supported = &dev_caps->pa_supported; GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS); + GParamFlags pa_param_flags = (GParamFlags) (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | GST_PARAM_CONDITIONALLY_AVAILABLE); GstPadTemplate *pad_templ; GstCaps *doc_caps; @@ -432,7 +457,12 @@ gst_amf_h264_enc_class_init (GstAmfH264EncClass * klass, gpointer data) g_object_class_install_property (object_class, PROP_CABAC, g_param_spec_boolean ("cabac", "CABAC", "Enable CABAC entropy coding", TRUE, param_flags)); - + if (cdata->dev_caps.pre_encode_supported) { + g_object_class_install_property (object_class, PROP_PRE_ENCODE, + g_param_spec_boolean ("pre-encode", "Pre-encode", + "Enable pre-encode", DEFAULT_PRE_ENCODE, + (GParamFlags) (param_flags | GST_PARAM_CONDITIONALLY_AVAILABLE))); + } if (cdata->dev_caps.smart_access_supported) { g_object_class_install_property (object_class, PROP_SMART_ACCESS, g_param_spec_boolean ("smart-access-video", "Smart Access Video", @@ -443,6 +473,112 @@ gst_amf_h264_enc_class_init (GstAmfH264EncClass * klass, gpointer data) GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS))); } + if (dev_caps->pre_analysis) { + g_object_class_install_property (object_class, PROP_PRE_ANALYSIS, + g_param_spec_boolean ("pre-analysis", "Pre Analysis", + "Enable pre-analysis", DEFAULT_PRE_ANALYSIS, param_flags)); + if (pa_supported->activity_type) { + g_object_class_install_property (object_class, PROP_PA_ACTIVITY_TYPE, + g_param_spec_enum ("pa-activity-type", "Pre-analysis activity type", + "Set the type of activity analysis for pre-analysis", + GST_TYPE_AMF_ENC_PA_ACTIVITY_TYPE, DEFAULT_PA_ACTIVITY_TYPE, + pa_param_flags)); + } + if (pa_supported->scene_change_detection) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION, + g_param_spec_boolean ("pa-scene-change-detection", + "Pre-analysis scene change detection", + "Enable scene change detection for pre-analysis", + DEFAULT_PA_SCENE_CHANGE_DETECTION, pa_param_flags)); + } + if (pa_supported->scene_change_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-scene-change-detection-sensitivity", + "Pre-analysis scene change detection sensitivity", + "Set the sensitivity of scene change detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->static_scene_detection) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION, + g_param_spec_boolean ("pa-static-scene-detection", + "Pre-analysis static scene detection", + "Enable static scene detection for pre-analysis", + DEFAULT_PA_STATIC_SCENE_DETECTION, pa_param_flags)); + } + if (pa_supported->static_scene_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-static-scene-detection-sensitivity", + "Pre-analysis static scene detection sensitivity", + "Set the sensitivity of static scene detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->initial_qp) { + g_object_class_install_property (object_class, PROP_PA_INITIAL_QP, + g_param_spec_uint ("pa-initial-qp", "Pre-analysis initial QP", + "The QP value that is used immediately after a scene change", 0, + 51, DEFAULT_PA_INITIAL_QP, pa_param_flags)); + } + if (pa_supported->max_qp) { + g_object_class_install_property (object_class, PROP_PA_MAX_QP, + g_param_spec_uint ("pa-max-qp", "Pre-analysis max QP", + "The QP threshold to allow a skip frame", 0, 51, + DEFAULT_PA_MAX_QP, pa_param_flags)); + } + if (pa_supported->caq_strength) { + g_object_class_install_property (object_class, PROP_PA_CAQ_STRENGTH, + g_param_spec_enum ("pa-caq-strength", "Pre-analysis CAQ strength", + "Content Adaptive Quantization strength for pre-analysis", + GST_TYPE_AMF_ENC_PA_CAQ_STRENGTH, DEFAULT_PA_CAQ_STRENGTH, + pa_param_flags)); + } + if (pa_supported->frame_sad) { + g_object_class_install_property (object_class, PROP_PA_FRAME_SAD, + g_param_spec_boolean ("pa-frame-sad", "Pre-analysis SAD algorithm", + "Enable Frame SAD algorithm", DEFAULT_PA_FRAME_SAD, + pa_param_flags)); + } + if (pa_supported->ltr) { + g_object_class_install_property (object_class, PROP_PA_LTR, + g_param_spec_boolean ("pa-ltr", "Pre-analysis LTR", + "Enable long term reference frame management", DEFAULT_PA_LTR, + pa_param_flags)); + } + if (pa_supported->lookahead_buffer_depth) { + g_object_class_install_property (object_class, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + g_param_spec_uint ("pa-lookahead-buffer-depth", + "Pre-analysis lookahead buffer depth", + "Set the PA lookahead buffer size", 0, 41, + DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH, pa_param_flags)); + } + if (pa_supported->paq_mode) { + g_object_class_install_property (object_class, PROP_PA_PAQ_MODE, + g_param_spec_enum ("pa-paq-mode", "Pre-analysis PAQ mode", + "Set the perceptual adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_PAQ_MODE, DEFAULT_PA_PAQ_MODE, + pa_param_flags)); + } + if (pa_supported->taq_mode) { + g_object_class_install_property (object_class, PROP_PA_TAQ_MODE, + g_param_spec_enum ("pa-taq-mode", "Pre-analysis TAQ mode", + "Set the temporal adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_TAQ_MODE, DEFAULT_PA_TAQ_MODE, + pa_param_flags)); + } + if (pa_supported->hmqb_mode) { + g_object_class_install_property (object_class, PROP_PA_HQMB_MODE, + g_param_spec_enum ("pa-hqmb-mode", "Pre-analysis HQMB mode", + "Set the PA high motion quality boost mode", + GST_TYPE_AMF_ENC_PA_HQMB_MODE, DEFAULT_PA_HQMB_MODE, + pa_param_flags)); + } + } gst_element_class_set_metadata (element_class, "AMD AMF H.264 Video Encoder", "Codec/Encoder/Video/Hardware", @@ -517,6 +653,25 @@ gst_amf_h264_enc_init (GstAmfH264Enc * self) self->aud = DEFAULT_AUD; self->cabac = DEFAULT_CABAC; self->smart_access = DEFAULT_SMART_ACCESS; + self->pre_encode = DEFAULT_PRE_ENCODE; + // Init pre-analysis options + self->pa.pre_analysis = DEFAULT_PRE_ANALYSIS; + self->pa.activity_type = DEFAULT_PA_ACTIVITY_TYPE; + self->pa.scene_change_detection = DEFAULT_PA_SCENE_CHANGE_DETECTION; + self->pa.scene_change_detection_sensitivity = + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY; + self->pa.static_scene_detection = DEFAULT_PA_STATIC_SCENE_DETECTION; + self->pa.static_scene_detection_sensitivity = + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY; + self->pa.initial_qp = DEFAULT_PA_INITIAL_QP; + self->pa.max_qp = DEFAULT_PA_MAX_QP; + self->pa.caq_strength = DEFAULT_PA_CAQ_STRENGTH; + self->pa.frame_sad = DEFAULT_PA_FRAME_SAD; + self->pa.ltr = DEFAULT_PA_LTR; + self->pa.lookahead_buffer_depth = DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH; + self->pa.paq_mode = DEFAULT_PA_PAQ_MODE; + self->pa.taq_mode = DEFAULT_PA_TAQ_MODE; + self->pa.hmqb_mode = DEFAULT_PA_HQMB_MODE; } static void @@ -629,6 +784,53 @@ gst_amf_h264_enc_set_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: update_bool (self, &self->smart_access, value); break; + case PROP_PRE_ENCODE: + update_bool (self, &self->pre_encode, value); + break; + case PROP_PRE_ANALYSIS: + update_bool (self, &self->pa.pre_analysis, value); + break; + case PROP_PA_ACTIVITY_TYPE: + update_enum (self, &self->pa.activity_type, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + update_bool (self, &self->pa.scene_change_detection, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.scene_change_detection_sensitivity, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + update_bool (self, &self->pa.static_scene_detection, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.static_scene_detection_sensitivity, value); + break; + case PROP_PA_INITIAL_QP: + update_uint (self, &self->pa.initial_qp, value); + break; + case PROP_PA_MAX_QP: + update_uint (self, &self->pa.max_qp, value); + break; + case PROP_PA_CAQ_STRENGTH: + update_enum (self, &self->pa.caq_strength, value); + break; + case PROP_PA_FRAME_SAD: + update_bool (self, &self->pa.frame_sad, value); + case PROP_PA_LTR: + update_bool (self, &self->pa.ltr, value); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + update_uint (self, &self->pa.lookahead_buffer_depth, value); + break; + case PROP_PA_PAQ_MODE: + update_enum (self, &self->pa.paq_mode, value); + break; + case PROP_PA_TAQ_MODE: + update_enum (self, &self->pa.taq_mode, value); + break; + case PROP_PA_HQMB_MODE: + update_enum (self, &self->pa.hmqb_mode, value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -689,6 +891,54 @@ gst_amf_h264_enc_get_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: g_value_set_boolean (value, self->smart_access); break; + case PROP_PRE_ENCODE: + g_value_set_boolean (value, self->pre_encode); + break; + case PROP_PRE_ANALYSIS: + g_value_set_boolean (value, self->pa.pre_analysis); + break; + case PROP_PA_ACTIVITY_TYPE: + g_value_set_enum (value, self->pa.activity_type); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + g_value_set_boolean (value, self->pa.scene_change_detection); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.scene_change_detection_sensitivity); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + g_value_set_boolean (value, self->pa.static_scene_detection); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.static_scene_detection_sensitivity); + break; + case PROP_PA_INITIAL_QP: + g_value_set_uint (value, self->pa.initial_qp); + break; + case PROP_PA_MAX_QP: + g_value_set_uint (value, self->pa.max_qp); + break; + case PROP_PA_CAQ_STRENGTH: + g_value_set_enum (value, self->pa.caq_strength); + break; + case PROP_PA_FRAME_SAD: + g_value_set_boolean (value, self->pa.frame_sad); + break; + case PROP_PA_LTR: + g_value_set_boolean (value, self->pa.ltr); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + g_value_set_uint (value, self->pa.lookahead_buffer_depth); + break; + case PROP_PA_PAQ_MODE: + g_value_set_enum (value, self->pa.paq_mode); + break; + case PROP_PA_TAQ_MODE: + g_value_set_enum (value, self->pa.taq_mode); + break; + case PROP_PA_HQMB_MODE: + g_value_set_enum (value, self->pa.hmqb_mode); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -956,7 +1206,32 @@ gst_amf_h264_enc_set_format (GstAmfEncoder * encoder, GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); } } + if (dev_caps->pre_encode_supported) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_PREENCODE_ENABLE, + (amf_bool) self->pre_encode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-encode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + } + if (dev_caps->pre_analysis) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, + (amf_bool) self->pa.pre_analysis); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + if (self->pa.pre_analysis) { + result = + gst_amf_encoder_set_pre_analysis_options (encoder, comp, &self->pa, + &dev_caps->pa_supported); + if (result != AMF_OK) + goto error; + } + } result = comp->Init (AMF_SURFACE_NV12, info->width, info->height); if (result != AMF_OK) { GST_ERROR_OBJECT (self, "Failed to init component, result %" @@ -1360,6 +1635,7 @@ gst_amf_h264_enc_create_class_data (GstD3D11Device * device, amf_int32 out_min_width = 0, out_max_width = 0; amf_int32 out_min_height = 0, out_max_height = 0; amf_bool interlace_supported; + amf_bool pre_encode_supported; amf_bool smart_access_supported; amf_int32 num_val; gboolean have_nv12 = FALSE; @@ -1492,11 +1768,40 @@ gst_amf_h264_enc_create_class_data (GstD3D11Device * device, QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_QP_I, default_qp_b, 22); #undef QUERY_DEFAULT_PROP + result = comp->GetProperty (AMF_VIDEO_ENCODER_PREENCODE_ENABLE, + &pre_encode_supported); + if (result == AMF_OK) + dev_caps.pre_encode_supported = TRUE; + result = comp->GetProperty (AMF_VIDEO_ENCODER_ENABLE_SMART_ACCESS_VIDEO, &smart_access_supported); if (result == AMF_OK) dev_caps.smart_access_supported = TRUE; + if (dev_caps.pre_analysis) { + amf_bool pre_analysis = FALSE; + // Store initial pre-analysis value + result = + comp->GetProperty (AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, + &pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to get pre-analysis option"); + } + // We need to enable pre-analysis for checking options availability + result = + comp->SetProperty (AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, + (amf_bool) TRUE); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis option"); + } + gst_amf_encoder_check_pa_supported_options (&dev_caps.pa_supported, comp); + result = + comp->SetProperty (AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis options"); + } + } + min_width = MAX (in_min_width, 1); max_width = in_max_width; if (max_width == 0) { diff --git a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh265enc.cpp b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh265enc.cpp index 57359c6c0a..35839ee665 100644 --- a/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh265enc.cpp +++ b/subprojects/gst-plugins-bad/sys/amfcodec/gstamfh265enc.cpp @@ -75,7 +75,9 @@ typedef struct amf_int64 max_gop_size; amf_int64 default_gop_size; guint valign; + gboolean pre_encode_supported; gboolean smart_access_supported; + GstAmfEncoderPASupportedOptions pa_supported; } GstAmfH265EncDeviceCaps; /** @@ -274,7 +276,23 @@ enum PROP_QP_P, PROP_REF_FRAMES, PROP_AUD, - PROP_SMART_ACCESS + PROP_SMART_ACCESS, + PROP_PRE_ENCODE, + PROP_PRE_ANALYSIS, + PROP_PA_ACTIVITY_TYPE, + PROP_PA_SCENE_CHANGE_DETECTION, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + PROP_PA_STATIC_SCENE_DETECTION, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + PROP_PA_INITIAL_QP, + PROP_PA_MAX_QP, + PROP_PA_CAQ_STRENGTH, + PROP_PA_FRAME_SAD, + PROP_PA_LTR, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + PROP_PA_PAQ_MODE, + PROP_PA_TAQ_MODE, + PROP_PA_HQMB_MODE, }; #define DEFAULT_USAGE AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING @@ -285,6 +303,7 @@ enum #define DEFAULT_MIN_MAX_QP -1 #define DEFAULT_AUD TRUE #define DEFAULT_SMART_ACCESS FALSE +#define DEFAULT_PRE_ENCODE FALSE #define DOC_SINK_CAPS_COMM \ "format = (string) {NV12, P010_10LE}, " \ @@ -322,6 +341,8 @@ typedef struct _GstAmfH265Enc gboolean aud; gboolean smart_access; + gboolean pre_encode; + GstAmfEncoderPreAnalysis pa; } GstAmfH265Enc; typedef struct _GstAmfH265EncClass @@ -362,8 +383,11 @@ gst_amf_h265_enc_class_init (GstAmfH265EncClass * klass, gpointer data) GstAmfEncoderClass *amf_class = GST_AMF_ENCODER_CLASS (klass); GstAmfH265EncClassData *cdata = (GstAmfH265EncClassData *) data; GstAmfH265EncDeviceCaps *dev_caps = &cdata->dev_caps; + GstAmfEncoderPASupportedOptions *pa_supported = &dev_caps->pa_supported; GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS); + GParamFlags pa_param_flags = (GParamFlags) (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | GST_PARAM_CONDITIONALLY_AVAILABLE); GstPadTemplate *pad_templ; GstCaps *doc_caps; @@ -434,6 +458,12 @@ gst_amf_h265_enc_class_init (GstAmfH265EncClass * klass, gpointer data) g_object_class_install_property (object_class, PROP_AUD, g_param_spec_boolean ("aud", "AUD", "Use AU (Access Unit) delimiter", DEFAULT_AUD, param_flags)); + if (cdata->dev_caps.pre_encode_supported) { + g_object_class_install_property (object_class, PROP_PRE_ENCODE, + g_param_spec_boolean ("pre-encode", "Pre-encode", + "Enable pre-encode", DEFAULT_PRE_ENCODE, + (GParamFlags) (param_flags | GST_PARAM_CONDITIONALLY_AVAILABLE))); + } if (cdata->dev_caps.smart_access_supported) { g_object_class_install_property (object_class, PROP_SMART_ACCESS, @@ -445,6 +475,113 @@ gst_amf_h265_enc_class_init (GstAmfH265EncClass * klass, gpointer data) GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS))); } + if (dev_caps->pre_analysis) { + g_object_class_install_property (object_class, PROP_PRE_ANALYSIS, + g_param_spec_boolean ("pre-analysis", "Pre-analysis", + "Enable pre-analysis", DEFAULT_PRE_ANALYSIS, param_flags)); + if (pa_supported->activity_type) { + g_object_class_install_property (object_class, PROP_PA_ACTIVITY_TYPE, + g_param_spec_enum ("pa-activity-type", "Pre-analysis activity type", + "Set the type of activity analysis for pre-analysis", + GST_TYPE_AMF_ENC_PA_ACTIVITY_TYPE, DEFAULT_PA_ACTIVITY_TYPE, + pa_param_flags)); + } + if (pa_supported->scene_change_detection) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION, + g_param_spec_boolean ("pa-scene-change-detection", + "Pre-analysis scene change detection", + "Enable scene change detection for pre-analysis", + DEFAULT_PA_SCENE_CHANGE_DETECTION, pa_param_flags)); + } + if (pa_supported->scene_change_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-scene-change-detection-sensitivity", + "Pre-analysis scene change detection sensitivity", + "Set the sensitivity of scene change detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->static_scene_detection) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION, + g_param_spec_boolean ("pa-static-scene-detection", + "Pre-analysis static scene detection", + "Enable static scene detection for pre-analysis", + DEFAULT_PA_STATIC_SCENE_DETECTION, pa_param_flags)); + } + if (pa_supported->static_scene_detection_sensitivity) { + g_object_class_install_property (object_class, + PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + g_param_spec_enum ("pa-static-scene-detection-sensitivity", + "Pre-analysis static scene detection sensitivity", + "Set the sensitivity of static scene detection for pre-analysis", + GST_TYPE_AMF_ENC_PA_STATIC_SCENE_DETECTION_SENSITIVITY, + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY, pa_param_flags)); + } + if (pa_supported->initial_qp) { + g_object_class_install_property (object_class, PROP_PA_INITIAL_QP, + g_param_spec_uint ("pa-initial-qp", "Pre-analysis initial QP", + "The QP value that is used immediately after a scene change", 0, + 51, DEFAULT_PA_INITIAL_QP, pa_param_flags)); + } + if (pa_supported->max_qp) { + g_object_class_install_property (object_class, PROP_PA_MAX_QP, + g_param_spec_uint ("pa-max-qp", "Pre-analysis max QP", + "The QP threshold to allow a skip frame", 0, 51, + DEFAULT_PA_MAX_QP, pa_param_flags)); + } + if (pa_supported->caq_strength) { + g_object_class_install_property (object_class, PROP_PA_CAQ_STRENGTH, + g_param_spec_enum ("pa-caq-strength", "Pre-analysis CAQ strength", + "Content Adaptive Quantization strength for pre-analysis", + GST_TYPE_AMF_ENC_PA_CAQ_STRENGTH, DEFAULT_PA_CAQ_STRENGTH, + pa_param_flags)); + } + if (pa_supported->frame_sad) { + g_object_class_install_property (object_class, PROP_PA_FRAME_SAD, + g_param_spec_boolean ("pa-frame-sad", "Pre-analysis SAD algorithm", + "Enable Frame SAD algorithm", DEFAULT_PA_FRAME_SAD, + pa_param_flags)); + } + if (pa_supported->ltr) { + g_object_class_install_property (object_class, PROP_PA_LTR, + g_param_spec_boolean ("pa-ltr", "Pre-analysis LTR", + "Enable long term reference frame management", DEFAULT_PA_LTR, + pa_param_flags)); + } + if (pa_supported->lookahead_buffer_depth) { + g_object_class_install_property (object_class, + PROP_PA_LOOKAHEAD_BUFFER_DEPTH, + g_param_spec_uint ("pa-lookahead-buffer-depth", + "Pre-analysis lookahead buffer depth", + "Set the PA lookahead buffer size", 0, 41, + DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH, pa_param_flags)); + } + if (pa_supported->paq_mode) { + g_object_class_install_property (object_class, PROP_PA_PAQ_MODE, + g_param_spec_enum ("pa-paq-mode", "Pre-analysis PAQ mode", + "Set the perceptual adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_PAQ_MODE, DEFAULT_PA_PAQ_MODE, + pa_param_flags)); + } + if (pa_supported->taq_mode) { + g_object_class_install_property (object_class, PROP_PA_TAQ_MODE, + g_param_spec_enum ("pa-taq-mode", "Pre-analysis TAQ mode", + "Set the temporal adaptive quantization mode", + GST_TYPE_AMF_ENC_PA_TAQ_MODE, DEFAULT_PA_TAQ_MODE, + pa_param_flags)); + } + if (pa_supported->hmqb_mode) { + g_object_class_install_property (object_class, PROP_PA_HQMB_MODE, + g_param_spec_enum ("pa-hqmb-mode", "Pre-analysis HQMB mode", + "Set the PA high motion quality boost mode", + GST_TYPE_AMF_ENC_PA_HQMB_MODE, DEFAULT_PA_HQMB_MODE, + pa_param_flags)); + } + } + gst_element_class_set_metadata (element_class, "AMD AMF H.265 Video Encoder", "Codec/Encoder/Video/Hardware", @@ -518,6 +655,25 @@ gst_amf_h265_enc_init (GstAmfH265Enc * self) self->ref_frames = (guint) dev_caps->min_ref_frames; self->aud = DEFAULT_AUD; self->smart_access = DEFAULT_SMART_ACCESS; + self->pre_encode = DEFAULT_PRE_ENCODE; + // Init pre-analysis options + self->pa.pre_analysis = DEFAULT_PRE_ANALYSIS; + self->pa.activity_type = DEFAULT_PA_ACTIVITY_TYPE; + self->pa.scene_change_detection = DEFAULT_PA_SCENE_CHANGE_DETECTION; + self->pa.scene_change_detection_sensitivity = + DEFAULT_PA_SCENE_CHANGE_DETECTION_SENSITIVITY; + self->pa.static_scene_detection = DEFAULT_PA_STATIC_SCENE_DETECTION; + self->pa.static_scene_detection_sensitivity = + DEFAULT_PA_STATIC_SCENE_DETECTION_SENSITIVITY; + self->pa.initial_qp = DEFAULT_PA_INITIAL_QP; + self->pa.max_qp = DEFAULT_PA_MAX_QP; + self->pa.caq_strength = DEFAULT_PA_CAQ_STRENGTH; + self->pa.frame_sad = DEFAULT_PA_FRAME_SAD; + self->pa.ltr = DEFAULT_PA_LTR; + self->pa.lookahead_buffer_depth = DEFAULT_PA_LOOKAHEAD_BUFFER_DEPTH; + self->pa.paq_mode = DEFAULT_PA_PAQ_MODE; + self->pa.taq_mode = DEFAULT_PA_TAQ_MODE; + self->pa.hmqb_mode = DEFAULT_PA_HQMB_MODE; } static void @@ -632,6 +788,53 @@ gst_amf_h265_enc_set_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: update_bool (self, &self->smart_access, value); break; + case PROP_PRE_ENCODE: + update_bool (self, &self->pre_encode, value); + break; + case PROP_PRE_ANALYSIS: + update_bool (self, &self->pa.pre_analysis, value); + break; + case PROP_PA_ACTIVITY_TYPE: + update_enum (self, &self->pa.activity_type, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + update_bool (self, &self->pa.scene_change_detection, value); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.scene_change_detection_sensitivity, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + update_bool (self, &self->pa.static_scene_detection, value); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + update_enum (self, &self->pa.static_scene_detection_sensitivity, value); + break; + case PROP_PA_INITIAL_QP: + update_uint (self, &self->pa.initial_qp, value); + break; + case PROP_PA_MAX_QP: + update_uint (self, &self->pa.max_qp, value); + break; + case PROP_PA_CAQ_STRENGTH: + update_enum (self, &self->pa.caq_strength, value); + break; + case PROP_PA_FRAME_SAD: + update_bool (self, &self->pa.frame_sad, value); + case PROP_PA_LTR: + update_bool (self, &self->pa.ltr, value); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + update_uint (self, &self->pa.lookahead_buffer_depth, value); + break; + case PROP_PA_PAQ_MODE: + update_enum (self, &self->pa.paq_mode, value); + break; + case PROP_PA_TAQ_MODE: + update_enum (self, &self->pa.taq_mode, value); + break; + case PROP_PA_HQMB_MODE: + update_enum (self, &self->pa.hmqb_mode, value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -695,6 +898,54 @@ gst_amf_h265_enc_get_property (GObject * object, guint prop_id, case PROP_SMART_ACCESS: g_value_set_boolean (value, self->smart_access); break; + case PROP_PRE_ENCODE: + g_value_set_boolean (value, self->pre_encode); + break; + case PROP_PRE_ANALYSIS: + g_value_set_boolean (value, self->pa.pre_analysis); + break; + case PROP_PA_ACTIVITY_TYPE: + g_value_set_enum (value, self->pa.activity_type); + break; + case PROP_PA_SCENE_CHANGE_DETECTION: + g_value_set_boolean (value, self->pa.scene_change_detection); + break; + case PROP_PA_SCENE_CHANGE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.scene_change_detection_sensitivity); + break; + case PROP_PA_STATIC_SCENE_DETECTION: + g_value_set_boolean (value, self->pa.static_scene_detection); + break; + case PROP_PA_STATIC_SCENE_DETECTION_SENSITIVITY: + g_value_set_enum (value, self->pa.static_scene_detection_sensitivity); + break; + case PROP_PA_INITIAL_QP: + g_value_set_uint (value, self->pa.initial_qp); + break; + case PROP_PA_MAX_QP: + g_value_set_uint (value, self->pa.max_qp); + break; + case PROP_PA_CAQ_STRENGTH: + g_value_set_enum (value, self->pa.caq_strength); + break; + case PROP_PA_FRAME_SAD: + g_value_set_boolean (value, self->pa.frame_sad); + break; + case PROP_PA_LTR: + g_value_set_boolean (value, self->pa.ltr); + break; + case PROP_PA_LOOKAHEAD_BUFFER_DEPTH: + g_value_set_uint (value, self->pa.lookahead_buffer_depth); + break; + case PROP_PA_PAQ_MODE: + g_value_set_enum (value, self->pa.paq_mode); + break; + case PROP_PA_TAQ_MODE: + g_value_set_enum (value, self->pa.taq_mode); + break; + case PROP_PA_HQMB_MODE: + g_value_set_enum (value, self->pa.hmqb_mode); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1038,6 +1289,33 @@ gst_amf_h265_enc_set_format (GstAmfEncoder * encoder, } } + if (dev_caps->pre_encode_supported) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, + (amf_bool) self->pre_encode); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-encode, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + } + + if (dev_caps->pre_analysis) { + result = comp->SetProperty (AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, + (amf_bool) self->pa.pre_analysis); + if (result != AMF_OK) { + GST_ERROR_OBJECT (self, "Failed to set pre-analysis, result %" + GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result)); + goto error; + } + if (self->pa.pre_analysis) { + result = + gst_amf_encoder_set_pre_analysis_options (encoder, comp, &self->pa, + &dev_caps->pa_supported); + if (result != AMF_OK) + goto error; + } + } + result = comp->Init (surface_format, info->width, info->height); if (result != AMF_OK) { GST_ERROR_OBJECT (self, "Failed to init component, result %" @@ -1277,6 +1555,7 @@ gst_amf_h265_enc_create_class_data (GstD3D11Device * device, amf_int32 in_min_height = 0, in_max_height = 0; amf_int32 out_min_width = 0, out_max_width = 0; amf_int32 out_min_height = 0, out_max_height = 0; + amf_bool pre_encode_supported; amf_bool smart_access_supported; amf_int32 num_val; std::set < std::string > formats; @@ -1415,11 +1694,41 @@ gst_amf_h265_enc_create_class_data (GstD3D11Device * device, QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_HEVC_QP_P, default_qp_p, 26); #undef QUERY_DEFAULT_PROP + result = comp->GetProperty (AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, + &pre_encode_supported); + if (result == AMF_OK) + dev_caps.pre_encode_supported = TRUE; + result = comp->GetProperty (AMF_VIDEO_ENCODER_HEVC_ENABLE_SMART_ACCESS_VIDEO, &smart_access_supported); if (result == AMF_OK) dev_caps.smart_access_supported = TRUE; + if (dev_caps.pre_analysis) { + amf_bool pre_analysis = FALSE; + // Store initial pre-analysis value + result = + comp->GetProperty (AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, + &pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to get pre-analysis option"); + } + // We need to enable pre-analysis for checking options availability + result = + comp->SetProperty (AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, + (amf_bool) TRUE); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis option"); + } + gst_amf_encoder_check_pa_supported_options (&dev_caps.pa_supported, comp); + result = + comp->SetProperty (AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, + pre_analysis); + if (result != AMF_OK) { + GST_WARNING_OBJECT (device, "Failed to set pre-analysis option"); + } + } + { const AMFPropertyInfo *pinfo = nullptr; result = comp->GetPropertyInfo (AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, &pinfo);