vulkan: add basic AV1 encode support

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8841>
This commit is contained in:
Stéphane Cerveau 2024-12-17 18:49:22 +01:00 committed by GStreamer Marge Bot
parent ea133d97a0
commit 167e41c343
9 changed files with 118 additions and 4 deletions

View File

@ -293,6 +293,10 @@ static const struct extension optional_extensions[] = {
OPTIONAL_VIDEO_EXTENSION (VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME,
VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, video_maintenance2),
# endif
# if defined(VK_KHR_video_encode_av1)
OPTIONAL_VIDEO_EXTENSION (VK_KHR_VIDEO_ENCODE_AV1_EXTENSION_NAME,
VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, video_encode_av1),
# endif
#endif /* GST_VULKAN_HAVE_VIDEO_EXTENSIONS */
};

View File

@ -79,6 +79,7 @@ G_DEFINE_TYPE_WITH_CODE (GstVulkanEncoder, gst_vulkan_encoder,
const uint32_t _vk_codec_supported_extensions[] = {
[GST_VK_VIDEO_EXTENSION_ENCODE_H264] = VK_MAKE_VIDEO_STD_VERSION (0, 9, 11),
[GST_VK_VIDEO_EXTENSION_ENCODE_H265] = VK_MAKE_VIDEO_STD_VERSION (0, 9, 12),
[GST_VK_VIDEO_EXTENSION_ENCODE_AV1] = VK_MAKE_VIDEO_STD_VERSION (0, 9, 1),
};
static gboolean
@ -648,6 +649,20 @@ gst_vulkan_encoder_start (GstVulkanEncoder * self,
/* *INDENT-ON* */
};
codec_idx = GST_VK_VIDEO_EXTENSION_ENCODE_H265;
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR:
if (!gst_vulkan_video_profile_is_valid (profile, self->codec)) {
g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
"Invalid profile");
return FALSE;
}
priv->caps.encoder.codec.av1 = (VkVideoEncodeAV1CapabilitiesKHR) {
/* *INDENT-OFF* */
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR,
/* *INDENT-ON* */
};
codec_idx = GST_VK_VIDEO_EXTENSION_ENCODE_AV1;
break;
default:
g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
@ -919,7 +934,6 @@ gst_vulkan_encoder_video_session_parameters_overrides (GstVulkanEncoder * self,
gboolean write;
g_return_val_if_fail (GST_IS_VULKAN_ENCODER (self), FALSE);
g_return_val_if_fail (params != NULL && feedback != NULL, FALSE);
priv = gst_vulkan_encoder_get_instance_private (self);
if (!priv->started)
@ -927,6 +941,7 @@ gst_vulkan_encoder_video_session_parameters_overrides (GstVulkanEncoder * self,
switch (self->codec) {
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
g_return_val_if_fail (params != NULL && feedback != NULL, FALSE);
if (params->h264.sType !=
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR) {
gst_vulkan_error_to_g_error (GST_VULKAN_ERROR, error,
@ -940,6 +955,7 @@ gst_vulkan_encoder_video_session_parameters_overrides (GstVulkanEncoder * self,
}
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR:
g_return_val_if_fail (params != NULL && feedback != NULL, FALSE);
if (params->h265.sType !=
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR) {
gst_vulkan_error_to_g_error (GST_VULKAN_ERROR, error,
@ -953,6 +969,10 @@ gst_vulkan_encoder_video_session_parameters_overrides (GstVulkanEncoder * self,
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_KHR;
}
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR:
g_return_val_if_fail (params == NULL && feedback == NULL, FALSE);
write = TRUE;
break;
default:
return FALSE;
}
@ -1373,6 +1393,8 @@ static const struct
VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME},
{VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR,
VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME},
{VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR,
VK_KHR_VIDEO_ENCODE_AV1_EXTENSION_NAME},
};
/**

View File

@ -132,6 +132,7 @@ union _GstVulkanEncoderParameters
/*< private >*/
VkVideoEncodeH264SessionParametersCreateInfoKHR h264;
VkVideoEncodeH265SessionParametersCreateInfoKHR h265;
VkVideoEncodeAV1SessionParametersCreateInfoKHR av1;
};
union _GstVulkanEncoderParametersOverrides
@ -154,6 +155,7 @@ struct _GstVulkanEncoderQualityPoperties
{
VkVideoEncodeH264QualityLevelPropertiesKHR h264;
VkVideoEncodeH265QualityLevelPropertiesKHR h265;
VkVideoEncodeAV1QualityLevelPropertiesKHR av1;
} codec;
};

View File

@ -43,6 +43,9 @@ gboolean gst_vulkan_physical_device_has_feature_video_mainten
gboolean gst_vulkan_physical_device_has_feature_video_maintenance2
(GstVulkanPhysicalDevice * device);
gboolean gst_vulkan_physical_device_has_feature_video_encode_av1
(GstVulkanPhysicalDevice * device);
static inline void
vk_link_struct (gpointer chain, gconstpointer in)
{

View File

@ -87,6 +87,9 @@ struct _GstVulkanPhysicalDevicePrivate
#if defined (VK_KHR_video_maintenance2)
VkPhysicalDeviceVideoMaintenance2FeaturesKHR videomaintenance2;
#endif
#if defined (VK_KHR_video_encode_av1)
VkPhysicalDeviceVideoEncodeAV1FeaturesKHR video_encoder_av1;
#endif
};
static void
@ -571,6 +574,12 @@ dump_features_extras (GstVulkanPhysicalDevice * device,
videoMaintenance2);
}
#endif
#if defined (VK_KHR_video_encode_av1)
if (chain->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_AV1_FEATURES_KHR) {
DEBUG_BOOL_STRUCT ("support for", &priv->video_encoder_av1, videoEncodeAV1);
}
#endif
}
static gboolean
@ -1074,12 +1083,17 @@ add_extra_features (GstVulkanPhysicalDevice * device)
#if defined (VK_KHR_video_maintenance1)
priv->videomaintenance1.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR;
vk_link_struct (&priv->features13, &priv->videomaintenance1);
vk_link_struct (&priv->features12, &priv->videomaintenance1);
#endif
#if defined (VK_KHR_video_maintenance2)
priv->videomaintenance2.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR;
vk_link_struct (&priv->features13, &priv->videomaintenance2);
vk_link_struct (&priv->features12, &priv->videomaintenance2);
#endif
#if defined (VK_KHR_video_encode_av1)
priv->video_encoder_av1.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_AV1_FEATURES_KHR;
vk_link_struct (&priv->features12, &priv->video_encoder_av1);
#endif
}
#endif /* VK_API_VERSION_1_2 */
@ -1502,6 +1516,21 @@ gboolean
return FALSE;
}
gboolean
gst_vulkan_physical_device_has_feature_video_encode_av1 (GstVulkanPhysicalDevice
* device)
{
#if defined (VK_KHR_video_encode_av1)
GstVulkanPhysicalDevicePrivate *priv;
g_return_val_if_fail (GST_IS_VULKAN_PHYSICAL_DEVICE (device), FALSE);
priv = GET_PRIV (device);
return priv->video_encoder_av1.videoEncodeAV1;
#endif
return FALSE;
}
/**
* gst_vulkan_physical_device_get_api_version:
* @device: a #GstVulkanPhysicalDevice

View File

@ -45,6 +45,10 @@ const VkExtensionProperties _vk_codec_extensions[] = {
[GST_VK_VIDEO_EXTENSION_ENCODE_H265] = {
.extensionName = VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME,
.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION,
},
[GST_VK_VIDEO_EXTENSION_ENCODE_AV1] = {
.extensionName = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME,
.specVersion = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION,
}
};

View File

@ -45,6 +45,7 @@ typedef enum {
GST_VK_VIDEO_EXTENSION_DECODE_H265,
GST_VK_VIDEO_EXTENSION_ENCODE_H264,
GST_VK_VIDEO_EXTENSION_ENCODE_H265,
GST_VK_VIDEO_EXTENSION_ENCODE_AV1,
} GST_VK_VIDEO_EXTENSIONS;
#define GST_VULKAN_VIDEO_FN_LIST(V) \
@ -73,7 +74,7 @@ struct _GstVulkanVideoFunctions
#undef DEFINE_FUNCTION
};
extern const VkExtensionProperties _vk_codec_extensions[4];
extern const VkExtensionProperties _vk_codec_extensions[5];
extern const VkComponentMapping _vk_identity_component_map;
gboolean gst_vulkan_video_get_vk_functions (GstVulkanInstance * instance,

View File

@ -39,6 +39,8 @@ static const struct {
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR },
{ GST_VULKAN_VIDEO_OPERATION_ENCODE, VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR, "video/x-h265",
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR },
{ GST_VULKAN_VIDEO_OPERATION_ENCODE, VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR, "video/x-av1",
VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PROFILE_INFO_KHR },
};
static const struct {
@ -92,6 +94,14 @@ static const struct {
{ STD_VIDEO_H265_PROFILE_IDC_SCC_EXTENSIONS, "scc-extensions" },
};
static const struct {
StdVideoAV1Profile vk_profile;
const char *profile_str;
} av1_profile_map[] = {
{ STD_VIDEO_AV1_PROFILE_MAIN, "main" },
{ STD_VIDEO_AV1_PROFILE_HIGH, "high" },
{ STD_VIDEO_AV1_PROFILE_PROFESSIONAL, "professional" },
};
/* *INDENT-ON* */
/**
@ -168,6 +178,16 @@ gst_vulkan_video_profile_to_caps (const GstVulkanVideoProfile * profile)
}
}
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR:
if (profile->codec.av1enc.sType == video_codecs_map[i].stype) {
int j;
for (j = 0; j < G_N_ELEMENTS (av1_profile_map); j++) {
if (profile->codec.av1enc.stdProfile
== av1_profile_map[j].vk_profile)
profile_str = av1_profile_map[j].profile_str;
}
}
break;
default:
break;
}
@ -336,6 +356,22 @@ gst_vulkan_video_profile_from_caps (GstVulkanVideoProfile * profile,
}
break;
}
case VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR:{
int j;
profile->codec.av1enc.sType = video_codecs_map[i].stype;
profile->codec.av1enc.stdProfile = STD_VIDEO_AV1_PROFILE_INVALID;
profile->profile.pNext = &profile->codec;
profile_str = gst_structure_get_string (structure, "profile");
for (j = 0; profile_str && j < G_N_ELEMENTS (av1_profile_map); j++) {
if (g_strcmp0 (profile_str, av1_profile_map[j].profile_str) == 0) {
profile->codec.av1enc.stdProfile = av1_profile_map[j].vk_profile;
break;
}
}
break;
}
default:
profile->usage.decode.pNext = NULL;
break;

View File

@ -65,6 +65,12 @@ struct _GstVulkanVideoProfile
* Since: 1.26
**/
VkVideoEncodeH265ProfileInfoKHR h265enc;
/**
* GstVulkanVideoProfile.usage.codec.av1enc:
*
* Since: 1.28
**/
VkVideoEncodeAV1ProfileInfoKHR av1enc;
} codec;
gpointer _reserved[GST_PADDING];
};
@ -100,6 +106,13 @@ struct _GstVulkanVideoCapabilities
/*< private >*/
VkVideoEncodeH264CapabilitiesKHR h264;
VkVideoEncodeH265CapabilitiesKHR h265;
/**
* _GstVulkanVideoCapabilities.encoder.codec.av1:
*
* Since: 1.28
**/
VkVideoEncodeAV1CapabilitiesKHR av1;
} codec;
} encoder;
};