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]; GstVulkanEncoderPicture *slots[32];
guint32 quality;
gboolean started; gboolean started;
gboolean session_reset; gboolean session_reset;
@ -222,6 +224,7 @@ gst_vulkan_encoder_new_video_session_parameters (GstVulkanEncoder * self,
{ {
GstVulkanEncoderPrivate *priv; GstVulkanEncoderPrivate *priv;
VkVideoSessionParametersCreateInfoKHR session_params_info; VkVideoSessionParametersCreateInfoKHR session_params_info;
VkVideoEncodeQualityLevelInfoKHR quality_info;
VkResult res; VkResult res;
VkVideoSessionParametersKHR session_params; VkVideoSessionParametersKHR session_params;
@ -234,9 +237,14 @@ gst_vulkan_encoder_new_video_session_parameters (GstVulkanEncoder * self,
return NULL; return NULL;
/* *INDENT-OFF* */ /* *INDENT-OFF* */
quality_info = (VkVideoEncodeQualityLevelInfoKHR) {
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR,
.pNext = params,
.qualityLevel = priv->quality,
};
session_params_info = (VkVideoSessionParametersCreateInfoKHR) { session_params_info = (VkVideoSessionParametersCreateInfoKHR) {
.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
.pNext = params, .pNext = &quality_info,
.videoSession = priv->session.session->handle, .videoSession = priv->session.session->handle,
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -406,6 +414,30 @@ gst_vulkan_encoder_profile_caps (GstVulkanEncoder * self)
return gst_caps_ref (priv->profile_caps); 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: * gst_vulkan_encoder_stop:
* @self: a #GstVulkanEncoder * @self: a #GstVulkanEncoder
@ -448,6 +480,7 @@ gst_vulkan_encoder_stop (GstVulkanEncoder * self)
* gst_vulkan_encoder_start: * gst_vulkan_encoder_start:
* @self: a #GstVulkanEncoder * @self: a #GstVulkanEncoder
* @profile: a #GstVulkanVideoProfile * @profile: a #GstVulkanVideoProfile
* @codec_quality_props: codec specific quality structure to fetch
* @error: (out) : an error result in case of failure or %NULL * @error: (out) : an error result in case of failure or %NULL
* *
* Start the encoding session according to a valid Vulkan profile * Start the encoding session according to a valid Vulkan profile
@ -457,7 +490,8 @@ gst_vulkan_encoder_stop (GstVulkanEncoder * self)
*/ */
gboolean gboolean
gst_vulkan_encoder_start (GstVulkanEncoder * self, gst_vulkan_encoder_start (GstVulkanEncoder * self,
GstVulkanVideoProfile * profile, GError ** error) GstVulkanVideoProfile * profile,
GstVulkanEncoderQualityProperties * codec_quality_props, GError ** error)
{ {
GstVulkanEncoderPrivate *priv; GstVulkanEncoderPrivate *priv;
VkResult res; VkResult res;
@ -467,10 +501,13 @@ gst_vulkan_encoder_start (GstVulkanEncoder * self,
int codec_idx; int codec_idx;
GstVulkanCommandPool *cmd_pool; GstVulkanCommandPool *cmd_pool;
VkQueryPoolVideoEncodeFeedbackCreateInfoKHR query_create; VkQueryPoolVideoEncodeFeedbackCreateInfoKHR query_create;
VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR quality_info;
VkVideoEncodeQualityLevelPropertiesKHR quality_props;
GError *query_err = NULL; GError *query_err = NULL;
g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE); g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE);
g_return_val_if_fail (profile != NULL, 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); priv = gst_vulkan_encoder_get_instance_private (self);
@ -652,6 +689,31 @@ gst_vulkan_encoder_start (GstVulkanEncoder * self,
!(priv->caps. !(priv->caps.
caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); 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* */ /* *INDENT-OFF* */
session_create = (VkVideoSessionCreateInfoKHR) { session_create = (VkVideoSessionCreateInfoKHR) {
@ -943,6 +1005,7 @@ gst_vulkan_encoder_encode (GstVulkanEncoder * self, GstVideoInfo * info,
VkVideoReferenceSlotInfoKHR ref_slots[37]; VkVideoReferenceSlotInfoKHR ref_slots[37];
GstVulkanCommandBuffer *cmd_buf; GstVulkanCommandBuffer *cmd_buf;
GArray *barriers; GArray *barriers;
VkVideoEncodeQualityLevelInfoKHR quality_info;
g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE); g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE);
g_return_val_if_fail (info != NULL && pic != NULL, 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; goto bail;
/* *INDENT-OFF* */ /* *INDENT-OFF* */
quality_info = (VkVideoEncodeQualityLevelInfoKHR) {
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR,
.pNext = NULL,
.qualityLevel = priv->quality,
};
coding_ctrl = (VkVideoCodingControlInfoKHR) { coding_ctrl = (VkVideoCodingControlInfoKHR) {
.sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, .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* */ /* *INDENT-ON* */

View file

@ -33,6 +33,7 @@ GType gst_vulkan_encoder_get_type (void);
typedef struct _GstVulkanEncoder GstVulkanEncoder; typedef struct _GstVulkanEncoder GstVulkanEncoder;
typedef struct _GstVulkanEncoderClass GstVulkanEncoderClass; typedef struct _GstVulkanEncoderClass GstVulkanEncoderClass;
typedef struct _GstVulkanEncoderQualityPoperties GstVulkanEncoderQualityProperties;
typedef union _GstVulkanEncoderParameters GstVulkanEncoderParameters; typedef union _GstVulkanEncoderParameters GstVulkanEncoderParameters;
typedef union _GstVulkanEncoderParametersOverrides GstVulkanEncoderParametersOverrides; typedef union _GstVulkanEncoderParametersOverrides GstVulkanEncoderParametersOverrides;
typedef union _GstVulkanEncoderParametersFeedback GstVulkanEncoderParametersFeedback; typedef union _GstVulkanEncoderParametersFeedback GstVulkanEncoderParametersFeedback;
@ -121,6 +122,16 @@ union _GstVulkanEncoderParametersFeedback
VkVideoEncodeH265SessionParametersFeedbackInfoKHR h265; VkVideoEncodeH265SessionParametersFeedbackInfoKHR h265;
}; };
struct _GstVulkanEncoderQualityPoperties
{
gint32 quality_level;
union
{
VkVideoEncodeH264QualityLevelPropertiesKHR h264;
VkVideoEncodeH265QualityLevelPropertiesKHR h265;
} codec;
};
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVulkanEncoder, gst_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVulkanEncoder, gst_object_unref)
GST_VULKAN_API GST_VULKAN_API
@ -130,6 +141,7 @@ GstVulkanEncoder * gst_vulkan_encoder_create_from_queue (GstVulkanQueue
GST_VULKAN_API GST_VULKAN_API
gboolean gst_vulkan_encoder_start (GstVulkanEncoder * self, gboolean gst_vulkan_encoder_start (GstVulkanEncoder * self,
GstVulkanVideoProfile * profile, GstVulkanVideoProfile * profile,
GstVulkanEncoderQualityProperties * codec_quality_props,
GError ** error); GError ** error);
GST_VULKAN_API GST_VULKAN_API
gboolean gst_vulkan_encoder_stop (GstVulkanEncoder * self); gboolean gst_vulkan_encoder_stop (GstVulkanEncoder * self);
@ -160,6 +172,9 @@ gboolean gst_vulkan_encoder_caps (GstVulkanEncode
GstVulkanVideoCapabilities * caps); GstVulkanVideoCapabilities * caps);
GST_VULKAN_API GST_VULKAN_API
GstCaps * gst_vulkan_encoder_profile_caps (GstVulkanEncoder * self); GstCaps * gst_vulkan_encoder_profile_caps (GstVulkanEncoder * self);
GST_VULKAN_API
gint32 gst_vulkan_encoder_quality_level (GstVulkanEncoder * self);
GST_VULKAN_API GST_VULKAN_API
gboolean gst_vulkan_encoder_picture_init (GstVulkanEncoderPicture * pic, gboolean gst_vulkan_encoder_picture_init (GstVulkanEncoderPicture * pic,
GstVulkanEncoder * self, GstVulkanEncoder * self,

View file

@ -63,7 +63,8 @@ typedef enum {
V(CmdEndVideoCoding) \ V(CmdEndVideoCoding) \
V(CmdDecodeVideo) \ V(CmdDecodeVideo) \
V(CmdEncodeVideo) \ V(CmdEncodeVideo) \
V(GetEncodedVideoSessionParameters) V(GetEncodedVideoSessionParameters) \
V(GetPhysicalDeviceVideoEncodeQualityLevelProperties)
struct _GstVulkanVideoFunctions 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; StdVideoH264ProfileIdc profile_idc = STD_VIDEO_H264_PROFILE_IDC_HIGH;
GstVulkanEncoderParameters enc_params; GstVulkanEncoderParameters enc_params;
VkVideoEncodeH264SessionParametersAddInfoKHR params_add; VkVideoEncodeH264SessionParametersAddInfoKHR params_add;
GstVulkanEncoderQualityProperties quality_props;
/* *INDENT-OFF* */
profile = (GstVulkanVideoProfile) { profile = (GstVulkanVideoProfile) {
/* *INDENT-OFF* */
.profile = { .profile = {
.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,
.pNext = &profile.usage.encode, .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, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR,
.stdProfileIdc = profile_idc, .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++) { for (i = 0; i < instance->n_physical_devices; i++) {
GstVulkanDevice *device = gst_vulkan_device_new_with_index (instance, 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; 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); mbAlignedWidth = GST_ROUND_UP_16 (width);
mbAlignedHeight = GST_ROUND_UP_16 (height); 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_right_offset = mbAlignedWidth - width;
h264_std_sps.frame_crop_bottom_offset = mbAlignedHeight - height; h264_std_sps.frame_crop_bottom_offset = mbAlignedHeight - height;
/* *INDENT-OFF* */
params_add = (VkVideoEncodeH264SessionParametersAddInfoKHR) { params_add = (VkVideoEncodeH264SessionParametersAddInfoKHR) {
/* *INDENT-OFF* */
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR,
.pStdSPSs = &h264_std_sps, .pStdSPSs = &h264_std_sps,
.stdSPSCount = 1, .stdSPSCount = 1,
.pStdPPSs = &h264_std_pps, .pStdPPSs = &h264_std_pps,
.stdPPSCount = 1, .stdPPSCount = 1,
/* *INDENT-ON* */
}; };
enc_params.h264 = (VkVideoEncodeH264SessionParametersCreateInfoKHR) { enc_params.h264 = (VkVideoEncodeH264SessionParametersCreateInfoKHR) {
/* *INDENT-OFF* */
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
.maxStdSPSCount = 1, .maxStdSPSCount = 1,
.maxStdPPSCount = 1, .maxStdPPSCount = 1,
.pParametersAddInfo = &params_add .pParametersAddInfo = &params_add
/* *INDENT-ON* */
}; };
/* *INDENT-ON* */
fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc, fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
&enc_params, &err)); &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 min_ctb_size = 64, max_ctb_size = 16;
gint max_tb_size = 0, min_tb_size = 0; gint max_tb_size = 0, min_tb_size = 0;
gint max_transform_hierarchy; gint max_transform_hierarchy;
GstVulkanEncoderQualityProperties quality_props;
/* *INDENT-OFF* */
profile = (GstVulkanVideoProfile) { profile = (GstVulkanVideoProfile) {
/* *INDENT-OFF* */
.profile = { .profile = {
.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,
.pNext = &profile.codec, .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, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR,
.stdProfileIdc = profile_idc, .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++) { for (i = 0; i < instance->n_physical_devices; i++) {
GstVulkanDevice *device = gst_vulkan_device_new_with_index (instance, 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; 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)); fail_unless (gst_vulkan_encoder_caps (enc, &enc_caps));
if (enc_caps.encoder.codec.h265.ctbSizes if (enc_caps.encoder.codec.h265.ctbSizes
& VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR) & VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR)
max_ctb_size = 64; 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_seq_parameter_set_id = sps_id;
h265_std_pps.pps_pic_parameter_set_id = pps_id; h265_std_pps.pps_pic_parameter_set_id = pps_id;
/* *INDENT-OFF* */
params_add = (VkVideoEncodeH265SessionParametersAddInfoKHR) { params_add = (VkVideoEncodeH265SessionParametersAddInfoKHR) {
/* *INDENT-OFF* */
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR,
.pStdVPSs = &h265_std_vps, .pStdVPSs = &h265_std_vps,
.stdVPSCount = 1, .stdVPSCount = 1,
@ -843,18 +853,15 @@ setup_h265_encoder (uint32_t width, uint32_t height, gint vps_id,
.stdSPSCount = 1, .stdSPSCount = 1,
.pStdPPSs = &h265_std_pps, .pStdPPSs = &h265_std_pps,
.stdPPSCount = 1, .stdPPSCount = 1,
/* *INDENT-ON* */
}; };
enc_params.h265 = (VkVideoEncodeH265SessionParametersCreateInfoKHR) { enc_params.h265 = (VkVideoEncodeH265SessionParametersCreateInfoKHR) {
/* *INDENT-OFF* */
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
.maxStdVPSCount = 1, .maxStdVPSCount = 1,
.maxStdSPSCount = 1, .maxStdSPSCount = 1,
.maxStdPPSCount = 1, .maxStdPPSCount = 1,
.pParametersAddInfo = &params_add .pParametersAddInfo = &params_add
/* *INDENT-ON* */
}; };
/* *INDENT-ON* */
fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc, fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
&enc_params, &err)); &enc_params, &err));