diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.c b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.c index dad951feef..544e73f203 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.c @@ -50,6 +50,8 @@ struct _GstVulkanEncoderPrivate GstVulkanEncoderPicture *slots[32]; + guint32 quality; + gboolean started; gboolean session_reset; @@ -222,6 +224,7 @@ gst_vulkan_encoder_new_video_session_parameters (GstVulkanEncoder * self, { GstVulkanEncoderPrivate *priv; VkVideoSessionParametersCreateInfoKHR session_params_info; + VkVideoEncodeQualityLevelInfoKHR quality_info; VkResult res; VkVideoSessionParametersKHR session_params; @@ -234,9 +237,14 @@ gst_vulkan_encoder_new_video_session_parameters (GstVulkanEncoder * self, return NULL; /* *INDENT-OFF* */ + quality_info = (VkVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pNext = params, + .qualityLevel = priv->quality, + }; session_params_info = (VkVideoSessionParametersCreateInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR, - .pNext = params, + .pNext = &quality_info, .videoSession = priv->session.session->handle, }; /* *INDENT-ON* */ @@ -406,6 +414,30 @@ gst_vulkan_encoder_profile_caps (GstVulkanEncoder * self) return gst_caps_ref (priv->profile_caps); } +/** + * gst_vulkan_encoder_quality_level: + * @self: a #GstVulkanEncoder + * + * Get the current encoding quality level. + * + * Returns: whether the encoder has started, it will return the quality level; + * otherwise it will return -1 + */ +gint32 +gst_vulkan_encoder_quality_level (GstVulkanEncoder * self) +{ + GstVulkanEncoderPrivate *priv; + + g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), -1); + + priv = gst_vulkan_encoder_get_instance_private (self); + + if (!priv->started) + return -1; + + return priv->quality; +} + /** * gst_vulkan_encoder_stop: * @self: a #GstVulkanEncoder @@ -448,6 +480,7 @@ gst_vulkan_encoder_stop (GstVulkanEncoder * self) * gst_vulkan_encoder_start: * @self: a #GstVulkanEncoder * @profile: a #GstVulkanVideoProfile + * @codec_quality_props: codec specific quality structure to fetch * @error: (out) : an error result in case of failure or %NULL * * Start the encoding session according to a valid Vulkan profile @@ -457,7 +490,8 @@ gst_vulkan_encoder_stop (GstVulkanEncoder * self) */ gboolean gst_vulkan_encoder_start (GstVulkanEncoder * self, - GstVulkanVideoProfile * profile, GError ** error) + GstVulkanVideoProfile * profile, + GstVulkanEncoderQualityProperties * codec_quality_props, GError ** error) { GstVulkanEncoderPrivate *priv; VkResult res; @@ -467,10 +501,13 @@ gst_vulkan_encoder_start (GstVulkanEncoder * self, int codec_idx; GstVulkanCommandPool *cmd_pool; VkQueryPoolVideoEncodeFeedbackCreateInfoKHR query_create; + VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR quality_info; + VkVideoEncodeQualityLevelPropertiesKHR quality_props; GError *query_err = NULL; g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE); g_return_val_if_fail (profile != NULL, FALSE); + g_return_val_if_fail (codec_quality_props != NULL, FALSE); priv = gst_vulkan_encoder_get_instance_private (self); @@ -652,6 +689,31 @@ gst_vulkan_encoder_start (GstVulkanEncoder * self, !(priv->caps. caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); + if (codec_quality_props->quality_level >= 0) { + priv->quality = MIN (codec_quality_props->quality_level, + priv->caps.encoder.caps.maxQualityLevels - 1); + } else { + priv->quality = priv->caps.encoder.caps.maxQualityLevels / 2; + } + + /* *INDENT-OFF* */ + quality_info = (VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pVideoProfile = &profile->profile, + .qualityLevel = priv->quality, + }; + quality_props = (VkVideoEncodeQualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_PROPERTIES_KHR, + .pNext = &codec_quality_props->codec, + }; + /* *INDENT-ON* */ + + res = priv->vk.GetPhysicalDeviceVideoEncodeQualityLevelProperties (gpu, + &quality_info, &quality_props); + if (gst_vulkan_error_to_g_error (res, error, + "vketPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR") + != VK_SUCCESS) + goto failed; /* *INDENT-OFF* */ session_create = (VkVideoSessionCreateInfoKHR) { @@ -943,6 +1005,7 @@ gst_vulkan_encoder_encode (GstVulkanEncoder * self, GstVideoInfo * info, VkVideoReferenceSlotInfoKHR ref_slots[37]; GstVulkanCommandBuffer *cmd_buf; GArray *barriers; + VkVideoEncodeQualityLevelInfoKHR quality_info; g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE); g_return_val_if_fail (info != NULL && pic != NULL, FALSE); @@ -954,9 +1017,16 @@ gst_vulkan_encoder_encode (GstVulkanEncoder * self, GstVideoInfo * info, goto bail; /* *INDENT-OFF* */ + quality_info = (VkVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pNext = NULL, + .qualityLevel = priv->quality, + }; coding_ctrl = (VkVideoCodingControlInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, - .flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR, + .pNext = &quality_info, + .flags = VK_VIDEO_CODING_CONTROL_ENCODE_QUALITY_LEVEL_BIT_KHR + | VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR, }; /* *INDENT-ON* */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.h b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.h index 5f768d63cb..7fee56283f 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.h @@ -33,6 +33,7 @@ GType gst_vulkan_encoder_get_type (void); typedef struct _GstVulkanEncoder GstVulkanEncoder; typedef struct _GstVulkanEncoderClass GstVulkanEncoderClass; +typedef struct _GstVulkanEncoderQualityPoperties GstVulkanEncoderQualityProperties; typedef union _GstVulkanEncoderParameters GstVulkanEncoderParameters; typedef union _GstVulkanEncoderParametersOverrides GstVulkanEncoderParametersOverrides; typedef union _GstVulkanEncoderParametersFeedback GstVulkanEncoderParametersFeedback; @@ -121,6 +122,16 @@ union _GstVulkanEncoderParametersFeedback VkVideoEncodeH265SessionParametersFeedbackInfoKHR h265; }; +struct _GstVulkanEncoderQualityPoperties +{ + gint32 quality_level; + union + { + VkVideoEncodeH264QualityLevelPropertiesKHR h264; + VkVideoEncodeH265QualityLevelPropertiesKHR h265; + } codec; +}; + G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVulkanEncoder, gst_object_unref) GST_VULKAN_API @@ -130,6 +141,7 @@ GstVulkanEncoder * gst_vulkan_encoder_create_from_queue (GstVulkanQueue GST_VULKAN_API gboolean gst_vulkan_encoder_start (GstVulkanEncoder * self, GstVulkanVideoProfile * profile, + GstVulkanEncoderQualityProperties * codec_quality_props, GError ** error); GST_VULKAN_API gboolean gst_vulkan_encoder_stop (GstVulkanEncoder * self); @@ -160,6 +172,9 @@ gboolean gst_vulkan_encoder_caps (GstVulkanEncode GstVulkanVideoCapabilities * caps); GST_VULKAN_API GstCaps * gst_vulkan_encoder_profile_caps (GstVulkanEncoder * self); +GST_VULKAN_API +gint32 gst_vulkan_encoder_quality_level (GstVulkanEncoder * self); + GST_VULKAN_API gboolean gst_vulkan_encoder_picture_init (GstVulkanEncoderPicture * pic, GstVulkanEncoder * self, diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkvideo-private.h b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkvideo-private.h index 2c27ecaad3..3ae6a2f600 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkvideo-private.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkvideo-private.h @@ -63,7 +63,8 @@ typedef enum { V(CmdEndVideoCoding) \ V(CmdDecodeVideo) \ V(CmdEncodeVideo) \ - V(GetEncodedVideoSessionParameters) + V(GetEncodedVideoSessionParameters) \ + V(GetPhysicalDeviceVideoEncodeQualityLevelProperties) struct _GstVulkanVideoFunctions { diff --git a/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh264.c b/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh264.c index 23a8d7c9b9..808728a093 100644 --- a/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh264.c +++ b/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh264.c @@ -595,9 +595,10 @@ setup_h264_encoder (guint32 width, gint32 height, gint sps_id, gint pps_id) StdVideoH264ProfileIdc profile_idc = STD_VIDEO_H264_PROFILE_IDC_HIGH; GstVulkanEncoderParameters enc_params; VkVideoEncodeH264SessionParametersAddInfoKHR params_add; + GstVulkanEncoderQualityProperties quality_props; + /* *INDENT-OFF* */ profile = (GstVulkanVideoProfile) { - /* *INDENT-OFF* */ .profile = { .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .pNext = &profile.usage.encode, @@ -617,8 +618,14 @@ setup_h264_encoder (guint32 width, gint32 height, gint sps_id, gint pps_id) .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR, .stdProfileIdc = profile_idc, } - /* *INDENT-ON* */ }; + quality_props = (GstVulkanEncoderQualityProperties) { + .quality_level = -1, + .codec.h264 = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_KHR, + }, + }; + /* *INDENT-ON* */ for (i = 0; i < instance->n_physical_devices; i++) { GstVulkanDevice *device = gst_vulkan_device_new_with_index (instance, i); @@ -649,7 +656,11 @@ setup_h264_encoder (guint32 width, gint32 height, gint sps_id, gint pps_id) return NULL; } - fail_unless (gst_vulkan_encoder_start (enc, &profile, &err)); + fail_unless (gst_vulkan_encoder_quality_level (enc) == -1); + + fail_unless (gst_vulkan_encoder_start (enc, &profile, &quality_props, &err)); + + fail_unless (gst_vulkan_encoder_quality_level (enc) > -1); mbAlignedWidth = GST_ROUND_UP_16 (width); mbAlignedHeight = GST_ROUND_UP_16 (height); @@ -663,24 +674,21 @@ setup_h264_encoder (guint32 width, gint32 height, gint sps_id, gint pps_id) h264_std_sps.frame_crop_right_offset = mbAlignedWidth - width; h264_std_sps.frame_crop_bottom_offset = mbAlignedHeight - height; + /* *INDENT-OFF* */ params_add = (VkVideoEncodeH264SessionParametersAddInfoKHR) { - /* *INDENT-OFF* */ .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR, .pStdSPSs = &h264_std_sps, .stdSPSCount = 1, .pStdPPSs = &h264_std_pps, .stdPPSCount = 1, - /* *INDENT-ON* */ }; - enc_params.h264 = (VkVideoEncodeH264SessionParametersCreateInfoKHR) { - /* *INDENT-OFF* */ .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, .maxStdSPSCount = 1, .maxStdPPSCount = 1, .pParametersAddInfo = ¶ms_add - /* *INDENT-ON* */ }; + /* *INDENT-ON* */ fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc, &enc_params, &err)); diff --git a/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh265.c b/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh265.c index c8ab9eb623..7b93938bad 100644 --- a/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh265.c +++ b/subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh265.c @@ -696,9 +696,10 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id, gint min_ctb_size = 64, max_ctb_size = 16; gint max_tb_size = 0, min_tb_size = 0; gint max_transform_hierarchy; + GstVulkanEncoderQualityProperties quality_props; + /* *INDENT-OFF* */ profile = (GstVulkanVideoProfile) { - /* *INDENT-OFF* */ .profile = { .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .pNext = &profile.codec, @@ -718,8 +719,14 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR, .stdProfileIdc = profile_idc, } - /* *INDENT-ON* */ }; + quality_props = (GstVulkanEncoderQualityProperties) { + .quality_level = -1, + .codec.h265 = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_KHR, + }, + }; + /* *INDENT-ON* */ for (i = 0; i < instance->n_physical_devices; i++) { GstVulkanDevice *device = gst_vulkan_device_new_with_index (instance, i); @@ -750,11 +757,14 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id, return NULL; } - fail_unless (gst_vulkan_encoder_start (enc, &profile, &err)); + fail_unless (gst_vulkan_encoder_quality_level (enc) == -1); + + fail_unless (gst_vulkan_encoder_start (enc, &profile, &quality_props, &err)); + + fail_unless (gst_vulkan_encoder_quality_level (enc) > -1); fail_unless (gst_vulkan_encoder_caps (enc, &enc_caps)); - if (enc_caps.encoder.codec.h265.ctbSizes & VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR) max_ctb_size = 64; @@ -834,8 +844,8 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id, h265_std_pps.pps_seq_parameter_set_id = sps_id; h265_std_pps.pps_pic_parameter_set_id = pps_id; + /* *INDENT-OFF* */ params_add = (VkVideoEncodeH265SessionParametersAddInfoKHR) { - /* *INDENT-OFF* */ .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR, .pStdVPSs = &h265_std_vps, .stdVPSCount = 1, @@ -843,18 +853,15 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id, .stdSPSCount = 1, .pStdPPSs = &h265_std_pps, .stdPPSCount = 1, - /* *INDENT-ON* */ }; - enc_params.h265 = (VkVideoEncodeH265SessionParametersCreateInfoKHR) { - /* *INDENT-OFF* */ .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR, .maxStdVPSCount = 1, .maxStdSPSCount = 1, .maxStdPPSCount = 1, .pParametersAddInfo = ¶ms_add - /* *INDENT-ON* */ }; + /* *INDENT-ON* */ fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc, &enc_params, &err));