diff --git a/girs/GstPbutils-1.0.gir b/girs/GstPbutils-1.0.gir index bb1678cdaa..a8b7dac51f 100644 --- a/girs/GstPbutils-1.0.gir +++ b/girs/GstPbutils-1.0.gir @@ -3517,6 +3517,110 @@ is expected to have the same format as for gst_codec_utils_h264_get_profile(). + + Sets the level, tier and profile in @caps if it can be determined from +@decoder_configuration. See gst_codec_utils_h266_get_level(), +gst_codec_utils_h266_get_tier() and gst_codec_utils_h266_get_profile() +for more details on the parameters. + + + %TRUE if the level, tier, profile could be set, %FALSE otherwise. + + + + + the #GstCaps to which the level, tier and profile are to be added + + + + Pointer to the VvcDecoderConfigurationRecord struct as defined in ISO/IEC 14496-15 + + + + + + Length of the data available in @decoder_configuration. + + + + + + Converts the level indication (general_level_idc) in the stream's +ptl_record structure into a string. + + + The level as a const string, or %NULL if there is an error. + + + + + Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + + + + + + Length of the data available in @ptl_record. + + + + + + Transform a level string from the caps into the level_idc + + + the level_idc or 0 if the level is unknown + + + + + A level string from caps + + + + + + Converts the profile indication (general_profile_idc) in the stream's +ptl_record structure into a string. + + + The profile as a const string, or %NULL if there is an error. + + + + + Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + + + + + + Length of the data available in @ptl_record + + + + + + Converts the tier indication (general_tier_flag) in the stream's +ptl_record structure into a string. + + + The tier as a const string, or %NULL if there is an error. + + + + + Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + + + + + + Length of the data available in @ptl_record. + + + + Sets the level and profile in @caps if it can be determined from @vis_obj_seq. See gst_codec_utils_mpeg4video_get_level() and diff --git a/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.c b/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.c index 563784aae7..4cd10c81f6 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.c @@ -1544,6 +1544,304 @@ gst_codec_utils_h265_caps_set_level_tier_and_profile (GstCaps * caps, return (level != NULL && tier != NULL && profile != NULL); } +/** + * gst_codec_utils_h266_get_profile: + * @ptl_record: (array length=len): Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + * @len: Length of the data available in @ptl_record + * + * Converts the profile indication (general_profile_idc) in the stream's + * ptl_record structure into a string. + * + * Returns: (nullable): The profile as a const string, or %NULL if there is an error. + * + * Since: 1.26 + */ +const gchar * +gst_codec_utils_h266_get_profile (const guint8 * ptl_record, guint len) +{ + gint profile_idc; + + g_return_val_if_fail (ptl_record != NULL, NULL); + + if (len < 2) + return NULL; + + GST_MEMDUMP ("VvcPTLRecord", ptl_record, len); + + profile_idc = (ptl_record[1] & 0xFE) >> 1; + + if (!profile_idc) + return NULL; + + switch (profile_idc) { + case 1: + return "main-10"; + break; + case 2: + return "main-12"; + break; + case 10: + return "main-12-intra"; + break; + case 17: + return "multilayer-main-10"; + break; + case 33: + return "main-444-10"; + break; + case 34: + return "main-444-12"; + break; + case 35: + return "main-444-16"; + break; + case 42: + return "main-444-12-intra"; + break; + case 43: + return "main-444-16-intra"; + break; + case 49: + return "multilayer-main-444-10"; + break; + case 65: + return "main-10-still-picture"; + break; + case 66: + return "main-12-still-picture"; + break; + case 97: + return "main-444-10-still-picture"; + break; + case 98: + return "main-444-12-still-picture"; + break; + case 99: + return "main-444-16-still-picture"; + break; + default: + return NULL; + } +} + +/** + * gst_codec_utils_h266_get_tier: + * @ptl_record: (array length=len): Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + * @len: Length of the data available in @ptl_record. + * + * Converts the tier indication (general_tier_flag) in the stream's + * ptl_record structure into a string. + * + * Returns: (nullable): The tier as a const string, or %NULL if there is an error. + * + * Since: 1.26 + */ +const gchar * +gst_codec_utils_h266_get_tier (const guint8 * ptl_record, guint len) +{ + const gchar *tier = NULL; + gint tier_flag = 0; + + g_return_val_if_fail (ptl_record != NULL, NULL); + + if (len < 2) + return NULL; + + GST_MEMDUMP ("VvcPTLRecord", ptl_record, len); + + tier_flag = ptl_record[1] & 0x01; + + if (tier_flag) + tier = "high"; + else + tier = "main"; + + return tier; +} + +/** + * gst_codec_utils_h266_get_level: + * @ptl_record: (array length=len): Pointer to the VvcPTLRecord structure as defined in ISO/IEC 14496-15. + * @len: Length of the data available in @ptl_record. + * + * Converts the level indication (general_level_idc) in the stream's + * ptl_record structure into a string. + * + * Returns: (nullable): The level as a const string, or %NULL if there is an error. + * + * Since: 1.26 + */ +const gchar * +gst_codec_utils_h266_get_level (const guint8 * ptl_record, guint len) +{ + guint8 level_idc; + + g_return_val_if_fail (ptl_record != NULL, NULL); + + if (len < 3) + return NULL; + + GST_MEMDUMP ("VvcPTLRecord", ptl_record, len); + + level_idc = ptl_record[2]; + + if (!level_idc) + return NULL; + + switch (level_idc) { + case 16: + return "1"; + break; + case 32: + return "2"; + break; + case 35: + return "2.1"; + break; + case 48: + return "3"; + break; + case 51: + return "3.1"; + break; + case 64: + return "4"; + break; + case 67: + return "4.1"; + break; + case 80: + return "5"; + break; + case 83: + return "5.1"; + break; + case 86: + return "5.2"; + break; + case 96: + return "6"; + break; + case 99: + return "6.1"; + break; + case 102: + return "6.2"; + break; + case 105: + return "6.3"; + break; + default: + return NULL; + } +} + +/** + * gst_codec_utils_h266_get_level_idc: + * @level: A level string from caps + * + * Transform a level string from the caps into the level_idc + * + * Returns: the level_idc or 0 if the level is unknown + * + * Since: 1.26 + */ +guint8 +gst_codec_utils_h266_get_level_idc (const gchar * level) +{ + g_return_val_if_fail (level != NULL, 0); + + if (!strcmp (level, "1")) + return 16; + else if (!strcmp (level, "2")) + return 32; + else if (!strcmp (level, "2.1")) + return 35; + else if (!strcmp (level, "3")) + return 48; + else if (!strcmp (level, "3.1")) + return 51; + else if (!strcmp (level, "4")) + return 64; + else if (!strcmp (level, "4.1")) + return 67; + else if (!strcmp (level, "5")) + return 80; + else if (!strcmp (level, "5.1")) + return 83; + else if (!strcmp (level, "5.2")) + return 86; + else if (!strcmp (level, "6")) + return 96; + else if (!strcmp (level, "6.1")) + return 99; + else if (!strcmp (level, "6.2")) + return 102; + else if (!strcmp (level, "6.3")) + return 105; + + + GST_WARNING ("Invalid level %s", level); + return 0; +} + +/** + * gst_codec_utils_h266_caps_set_level_tier_and_profile: + * @caps: the #GstCaps to which the level, tier and profile are to be added + * @decoder_configuration: (array length=len): Pointer to the VvcDecoderConfigurationRecord struct as defined in ISO/IEC 14496-15 + * @len: Length of the data available in @decoder_configuration. + * + * Sets the level, tier and profile in @caps if it can be determined from + * @decoder_configuration. See gst_codec_utils_h266_get_level(), + * gst_codec_utils_h266_get_tier() and gst_codec_utils_h266_get_profile() + * for more details on the parameters. + * + * Returns: %TRUE if the level, tier, profile could be set, %FALSE otherwise. + * + * Since: 1.26 + */ +gboolean +gst_codec_utils_h266_caps_set_level_tier_and_profile (GstCaps * caps, + const guint8 * decoder_configuration, guint len) +{ + const gchar *level, *tier, *profile; + gboolean ptl_present_flag; + const guint8 *ptl_record; + + g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); + g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE); + g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_NAME (caps, "video/x-h266"), FALSE); + g_return_val_if_fail (decoder_configuration != NULL, FALSE); + + if (len < 5) + return FALSE; + + ptl_present_flag = decoder_configuration[0] & 0x01; + if (!ptl_present_flag) + return FALSE; + + ptl_record = decoder_configuration + 4; + len -= 4; + + level = gst_codec_utils_h266_get_level (ptl_record, len); + if (level != NULL) + gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL); + + tier = gst_codec_utils_h266_get_tier (ptl_record, len); + if (tier != NULL) + gst_caps_set_simple (caps, "tier", G_TYPE_STRING, tier, NULL); + + profile = gst_codec_utils_h266_get_profile (ptl_record, len); + if (profile != NULL) + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL); + + GST_LOG ("profile : %s", (profile) ? profile : "---"); + GST_LOG ("tier : %s", (tier) ? tier : "---"); + GST_LOG ("level : %s", (level) ? level : "---"); + + return (level != NULL && tier != NULL && profile != NULL); +} + /** * gst_codec_utils_av1_get_seq_level_idx: * @level: A level string from caps diff --git a/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.h b/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.h index 076b45f187..0da17a8328 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/pbutils/codec-utils.h @@ -97,6 +97,28 @@ gboolean gst_codec_utils_h265_caps_set_level_tier_and_profile (GstCaps const guint8 * profile_tier_level, guint len); +/* H.266 */ + +GST_PBUTILS_API +const gchar * gst_codec_utils_h266_get_profile (const guint8 * ptl_record, + guint len); + +GST_PBUTILS_API +const gchar * gst_codec_utils_h266_get_tier (const guint8 * ptl_record, + guint len); + +GST_PBUTILS_API +const gchar * gst_codec_utils_h266_get_level (const guint8 * ptl_record, + guint len); + +GST_PBUTILS_API +guint8 gst_codec_utils_h266_get_level_idc (const gchar * level); + +GST_PBUTILS_API +gboolean gst_codec_utils_h266_caps_set_level_tier_and_profile (GstCaps * caps, + const guint8 * decoder_configuration, + guint len); + /* AV1 */ GST_PBUTILS_API diff --git a/subprojects/gst-plugins-base/tests/check/libs/pbutils.c b/subprojects/gst-plugins-base/tests/check/libs/pbutils.c index d6ed343011..8329ccb800 100644 --- a/subprojects/gst-plugins-base/tests/check/libs/pbutils.c +++ b/subprojects/gst-plugins-base/tests/check/libs/pbutils.c @@ -1118,6 +1118,65 @@ GST_START_TEST (test_pb_utils_h264_get_profile_flags_level) GST_END_TEST; +GST_START_TEST (test_pb_utils_h266_caps_set_level_tier_and_profile) +{ + GstCaps *caps; + GstStructure *s; + const guint8 good_config[] = + { 0xff, 0x00, 0x61, 0x1f, 0x01, 0x02, 0x50, 0x80 }; + const guint8 short_config[] = { 0xff, 0x00, 0x61, 0x1f }; + const guint8 no_ptl_config[] = { 0xfe, 0xba, 0xbe, 0xef }; + const guint8 short_config_no_level[] = { 0xff, 0x00, 0x61, 0x1f, 0x01, 0x02 }; + + /* Happy path */ + caps = gst_caps_new_empty_simple ("video/x-h266"); + fail_unless (gst_codec_utils_h266_caps_set_level_tier_and_profile (caps, + good_config, sizeof (good_config))); + s = gst_caps_get_structure (caps, 0); + + fail_unless_equals_string (gst_structure_get_string (s, "profile"), + "main-10"); + fail_unless_equals_string (gst_structure_get_string (s, "level"), "5"); + fail_unless_equals_string (gst_structure_get_string (s, "tier"), "main"); + gst_caps_unref (caps); + + /* Too short to have profile-tier-level */ + caps = gst_caps_new_empty_simple ("video/x-h266"); + fail_unless (!gst_codec_utils_h266_caps_set_level_tier_and_profile (caps, + short_config, sizeof (short_config))); + s = gst_caps_get_structure (caps, 0); + + fail_unless_equals_string (gst_structure_get_string (s, "profile"), NULL); + fail_unless_equals_string (gst_structure_get_string (s, "level"), NULL); + fail_unless_equals_string (gst_structure_get_string (s, "tier"), NULL); + gst_caps_unref (caps); + + /* ptl_present_flag = FALSE */ + caps = gst_caps_new_empty_simple ("video/x-h266"); + fail_unless (!gst_codec_utils_h266_caps_set_level_tier_and_profile (caps, + no_ptl_config, sizeof (no_ptl_config))); + s = gst_caps_get_structure (caps, 0); + + fail_unless_equals_string (gst_structure_get_string (s, "profile"), NULL); + fail_unless_equals_string (gst_structure_get_string (s, "level"), NULL); + fail_unless_equals_string (gst_structure_get_string (s, "tier"), NULL); + gst_caps_unref (caps); + + /* Too short to parse level */ + caps = gst_caps_new_empty_simple ("video/x-h266"); + fail_unless (!gst_codec_utils_h266_caps_set_level_tier_and_profile (caps, + short_config_no_level, sizeof (short_config_no_level))); + s = gst_caps_get_structure (caps, 0); + + fail_unless_equals_string (gst_structure_get_string (s, "profile"), + "main-10"); + fail_unless_equals_string (gst_structure_get_string (s, "level"), NULL); + fail_unless_equals_string (gst_structure_get_string (s, "tier"), "main"); + gst_caps_unref (caps); +} + +GST_END_TEST; + #define PROFILE_TIER_LEVEL_LEN 11 static void @@ -1712,6 +1771,8 @@ libgstpbutils_suite (void) tcase_add_test (tc_chain, test_pb_utils_h265_profiles); tcase_add_test (tc_chain, test_pb_utils_caps_mime_codec); tcase_add_test (tc_chain, test_pb_utils_caps_from_mime_codec); + tcase_add_test (tc_chain, test_pb_utils_h266_caps_set_level_tier_and_profile); + return s; }