vkencoder-private: handle quality level
authorVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Thu, 19 Sep 2024 14:43:09 +0000 (16:43 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 4 Dec 2024 02:17:45 +0000 (02:17 +0000)
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>

subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.c
subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkencoder-private.h
subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkvideo-private.h
subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh264.c
subprojects/gst-plugins-bad/tests/check/libs/vkvideoencodeh265.c

index dad951feefad13f6f67a15903113621aa7c840db..544e73f203b0c70b177f7657de939e2baf3c83a0 100644 (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* */
 
index 5f768d63cb6ec4e4c780ce4b6165b162eb8170f1..7fee56283f55520d13e33d726008808f9808ac53 100644 (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,
index 2c27ecaad376b60125f9c5fcfb5979753db54cac..3ae6a2f6003fe460ab9e0530ddf5ebfba4d40c52 100644 (file)
@@ -63,7 +63,8 @@ typedef enum {
   V(CmdEndVideoCoding)                                                         \
   V(CmdDecodeVideo)                                                            \
   V(CmdEncodeVideo)                                                            \
-  V(GetEncodedVideoSessionParameters)
+  V(GetEncodedVideoSessionParameters)                                          \
+  V(GetPhysicalDeviceVideoEncodeQualityLevelProperties)
 
 struct _GstVulkanVideoFunctions
 {
index 23a8d7c9b99f66eb8382f1e8c6b1ce34b5447d31..808728a0939addc913130a679028be4ed8d8ac62 100644 (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;
 
+  /* *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 = &params_add
-    /* *INDENT-ON* */
   };
+  /* *INDENT-ON* */
 
   fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
           &enc_params, &err));
index c8ab9eb6232d3d2c02fde30c54a5b29e8c7ef70a..7b93938badb98a9ece801cfce5cb5c1c7954cf86 100644 (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;
 
+  /* *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,10 +757,13 @@ 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_caps (enc, &enc_caps));
+  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)
@@ -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 = &params_add
-    /* *INDENT-ON* */
   };
+  /* *INDENT-ON* */
 
   fail_unless (gst_vulkan_encoder_update_video_session_parameters (enc,
           &enc_params, &err));