vkencoder-private: handle quality level

It creates a new structure for passing the codec quality structure at _start(),
where it will be filled. The quality level can be set or changed according
encoder limits.

Later the quality level will be set at _update_session_parameters() and at each
frame encoding. That's why it has to be set at _start().

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8007>
This commit is contained in:
Víctor Manuel Jáquez Leal 2024-09-19 16:43:09 +02:00 committed by GStreamer Marge Bot
parent d63ec09b5e
commit ab6aafb076
5 changed files with 122 additions and 21 deletions

View file

@ -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* */

View file

@ -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,

View file

@ -63,7 +63,8 @@ typedef enum {
V(CmdEndVideoCoding) \
V(CmdDecodeVideo) \
V(CmdEncodeVideo) \
V(GetEncodedVideoSessionParameters)
V(GetEncodedVideoSessionParameters) \
V(GetPhysicalDeviceVideoEncodeQualityLevelProperties)
struct _GstVulkanVideoFunctions
{

View file

@ -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;
profile = (GstVulkanVideoProfile) {
/* *INDENT-OFF* */
profile = (GstVulkanVideoProfile) {
.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;
params_add = (VkVideoEncodeH264SessionParametersAddInfoKHR) {
/* *INDENT-OFF* */
params_add = (VkVideoEncodeH264SessionParametersAddInfoKHR) {
.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 = &params_add
/* *INDENT-ON* */
};
/* *INDENT-ON* */
fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
&enc_params, &err));

View file

@ -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;
profile = (GstVulkanVideoProfile) {
/* *INDENT-OFF* */
profile = (GstVulkanVideoProfile) {
.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;
params_add = (VkVideoEncodeH265SessionParametersAddInfoKHR) {
/* *INDENT-OFF* */
params_add = (VkVideoEncodeH265SessionParametersAddInfoKHR) {
.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 = &params_add
/* *INDENT-ON* */
};
/* *INDENT-ON* */
fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
&enc_params, &err));