From 168ad9f58f6dfbdb588fa3e07158be5c3f13a50e Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Tue, 14 Dec 2021 19:36:56 +0100 Subject: [PATCH] codecparsers: h265parser: Verify all possible profiles. It's possible a HEVC stream to have multiple profiles given the compatibility bits. Instead of returning a single profile, internal gst_h265_profile_tier_level_get_profiles() returns an array with all it possible profiles. Profiles are appended into the array only if the generated profile is not invalid. gst_h265_profile_tier_level_get_profile() is rewritten in terms of gst_h265_profile_tier_level_get_profiles(), returning the first profile found the array. And gst_h265_get_profile_from_sps() is also rewritten in terms of gst_h265_profile_tier_level_get_profiles(), but traversing the array verifying if the proposed profile is actually valid by Annex A.3.x of the specification. Part-of: --- .../gst-libs/gst/codecparsers/gsth265parser.c | 238 +++++++++++++-------- 1 file changed, 148 insertions(+), 90 deletions(-) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c index 11bf6e7..dcd7c39 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c @@ -3636,64 +3636,94 @@ static GstH265Profile return get_extension_profile (profiles, G_N_ELEMENTS (profiles), ptl); } -/** - * gst_h265_profile_tier_level_get_profile: - * @ptl: a #GstH265ProfileTierLevel - * - * Return the H265 profile defined in @ptl. - * - * Returns: a #GstH265Profile - * Since: 1.14 - */ -GstH265Profile -gst_h265_profile_tier_level_get_profile (const GstH265ProfileTierLevel * ptl) +static inline void +append_profile (GstH265Profile profiles[GST_H265_PROFILE_MAX], guint * idx, + GstH265Profile profile) +{ + if (profile == GST_H265_PROFILE_INVALID) + return; + profiles[*idx++] = profile; +} + +static void +gst_h265_profile_tier_level_get_profiles (const GstH265ProfileTierLevel * ptl, + GstH265Profile profiles[GST_H265_PROFILE_MAX], guint * len) { + guint i = 0; + + /* keep profile check in asc order */ + if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN || ptl->profile_compatibility_flag[1]) - return GST_H265_PROFILE_MAIN; + profiles[i++] = GST_H265_PROFILE_MAIN; if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN_10 || ptl->profile_compatibility_flag[2]) - return GST_H265_PROFILE_MAIN_10; + profiles[i++] = GST_H265_PROFILE_MAIN_10; if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE || ptl->profile_compatibility_flag[3]) - return GST_H265_PROFILE_MAIN_STILL_PICTURE; + profiles[i++] = GST_H265_PROFILE_MAIN_STILL_PICTURE; if (ptl->profile_idc == GST_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSION || ptl->profile_compatibility_flag[4]) - return get_format_range_extension_profile (ptl); + append_profile (profiles, &i, get_format_range_extension_profile (ptl)); if (ptl->profile_idc == GST_H265_PROFILE_IDC_HIGH_THROUGHPUT || ptl->profile_compatibility_flag[5]) - return get_high_throughput_profile (ptl); + append_profile (profiles, &i, get_high_throughput_profile (ptl)); if (ptl->profile_idc == GST_H265_PROFILE_IDC_MULTIVIEW_MAIN || ptl->profile_compatibility_flag[6]) - return get_multiview_profile (ptl); + append_profile (profiles, &i, get_multiview_profile (ptl)); if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCALABLE_MAIN || ptl->profile_compatibility_flag[7]) - return get_scalable_profile (ptl); + append_profile (profiles, &i, get_scalable_profile (ptl)); if (ptl->profile_idc == GST_H265_PROFILE_IDC_3D_MAIN || ptl->profile_compatibility_flag[8]) - return get_3d_profile (ptl); + append_profile (profiles, &i, get_3d_profile (ptl)); if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING - || ptl->profile_compatibility_flag[9]) - return get_screen_content_coding_extensions_profile (ptl); + || ptl->profile_compatibility_flag[9]) { + append_profile (profiles, &i, + get_screen_content_coding_extensions_profile (ptl)); + } if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCALABLE_FORMAT_RANGE_EXTENSION - || ptl->profile_compatibility_flag[10]) - return get_scalable_format_range_extensions_profile (ptl); + || ptl->profile_compatibility_flag[10]) { + append_profile (profiles, &i, + get_scalable_format_range_extensions_profile (ptl)); + } if (ptl->profile_idc == GST_H265_PROFILE_IDC_HIGH_THROUGHPUT_SCREEN_CONTENT_CODING_EXTENSION - || ptl->profile_compatibility_flag[11]) - return get_screen_content_coding_extensions_high_throughput_profile (ptl); + || ptl->profile_compatibility_flag[11]) { + append_profile (profiles, &i, + get_screen_content_coding_extensions_high_throughput_profile (ptl)); + } - return GST_H265_PROFILE_INVALID; + *len = i; +} + +/** + * gst_h265_profile_tier_level_get_profile: + * @ptl: a #GstH265ProfileTierLevel + * + * Return the H265 profile defined in @ptl. + * + * Returns: a #GstH265Profile + * Since: 1.14 + */ +GstH265Profile +gst_h265_profile_tier_level_get_profile (const GstH265ProfileTierLevel * ptl) +{ + guint len; + GstH265Profile profiles[GST_H265_PROFILE_MAX] = { GST_H265_PROFILE_INVALID, }; + + gst_h265_profile_tier_level_get_profiles (ptl, profiles, &len); + return profiles[0]; } /** @@ -4318,78 +4348,106 @@ gst_h265_parser_insert_sei_hevc (GstH265Parser * parser, guint8 nal_length_size, GstH265Profile gst_h265_get_profile_from_sps (GstH265SPS * sps) { - GstH265Profile p; - - p = gst_h265_profile_tier_level_get_profile (&sps->profile_tier_level); - - if (p == GST_H265_PROFILE_INVALID) { - GstH265ProfileTierLevel tmp_ptl = sps->profile_tier_level; - guint chroma_format_idc = sps->chroma_format_idc; - guint bit_depth_luma = sps->bit_depth_luma_minus8 + 8; - guint bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8; - - /* Set the conformance indicators based on chroma_format_idc / bit_depth */ - switch (chroma_format_idc) { - case 0: - tmp_ptl.max_monochrome_constraint_flag = 1; - tmp_ptl.max_420chroma_constraint_flag = 1; - tmp_ptl.max_422chroma_constraint_flag = 1; - break; + GstH265Profile profiles[GST_H265_PROFILE_MAX] = { GST_H265_PROFILE_INVALID, }; + GstH265ProfileTierLevel tmp_ptl; + guint i, len = 0; + guint chroma_format_idc, bit_depth_luma, bit_depth_chroma; - case 1: - tmp_ptl.max_monochrome_constraint_flag = 0; - tmp_ptl.max_420chroma_constraint_flag = 1; - tmp_ptl.max_422chroma_constraint_flag = 1; - break; + g_return_val_if_fail (sps != NULL, GST_H265_PROFILE_INVALID); - case 2: - tmp_ptl.max_monochrome_constraint_flag = 0; - tmp_ptl.max_420chroma_constraint_flag = 0; - tmp_ptl.max_422chroma_constraint_flag = 1; - break; + tmp_ptl = sps->profile_tier_level; + chroma_format_idc = sps->chroma_format_idc; + bit_depth_luma = sps->bit_depth_luma_minus8 + 8; + bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8; - case 3: - tmp_ptl.max_monochrome_constraint_flag = 0; - tmp_ptl.max_420chroma_constraint_flag = 0; - tmp_ptl.max_422chroma_constraint_flag = 0; - break; + gst_h265_profile_tier_level_get_profiles (&sps->profile_tier_level, profiles, + &len); - default: - g_assert_not_reached (); + for (i = 0; i < len && i < G_N_ELEMENTS (profiles); i++) { + switch (profiles[i]) { + case GST_H265_PROFILE_INVALID: break; + case GST_H265_PROFILE_MAIN: + case GST_H265_PROFILE_MAIN_STILL_PICTURE: + /* A.3.2 or A.3.5 */ + if (chroma_format_idc == 1 + && bit_depth_luma == 8 && bit_depth_chroma == 8) + return profiles[i]; + break; + case GST_H265_PROFILE_MAIN_10: + /* A.3.3 */ + if (chroma_format_idc == 1 + && bit_depth_luma >= 8 && bit_depth_luma <= 10 + && bit_depth_chroma >= 8 && bit_depth_chroma <= 10) + return profiles[i]; + break; + default: + return profiles[i]; } + } - tmp_ptl.max_8bit_constraint_flag = 1; - tmp_ptl.max_10bit_constraint_flag = 1; - tmp_ptl.max_12bit_constraint_flag = 1; - tmp_ptl.max_14bit_constraint_flag = 1; - - if (bit_depth_luma > 8 || bit_depth_chroma > 8) - tmp_ptl.max_8bit_constraint_flag = 0; - - if (bit_depth_luma > 10 || bit_depth_chroma > 10) - tmp_ptl.max_10bit_constraint_flag = 0; - - if (bit_depth_luma > 12 || bit_depth_chroma > 12) - tmp_ptl.max_12bit_constraint_flag = 0; - - if (tmp_ptl.profile_idc == GST_H265_PROFILE_IDC_HIGH_THROUGHPUT - || tmp_ptl.profile_idc == GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING - || tmp_ptl.profile_idc == - GST_H265_PROFILE_IDC_SCALABLE_FORMAT_RANGE_EXTENSION - || tmp_ptl.profile_idc == - GST_H265_PROFILE_IDC_HIGH_THROUGHPUT_SCREEN_CONTENT_CODING_EXTENSION - || tmp_ptl.profile_compatibility_flag[5] - || tmp_ptl.profile_compatibility_flag[9] - || tmp_ptl.profile_compatibility_flag[10] - || tmp_ptl.profile_compatibility_flag[11]) { - if (bit_depth_luma > 14 || bit_depth_chroma > 14) - tmp_ptl.max_14bit_constraint_flag = 0; - } else - tmp_ptl.max_14bit_constraint_flag = 0; + /* Invalid profile: */ + /* Set the conformance indicators based on chroma_format_idc / bit_depth */ + switch (chroma_format_idc) { + case 0: + tmp_ptl.max_monochrome_constraint_flag = 1; + tmp_ptl.max_420chroma_constraint_flag = 1; + tmp_ptl.max_422chroma_constraint_flag = 1; + break; + + case 1: + tmp_ptl.max_monochrome_constraint_flag = 0; + tmp_ptl.max_420chroma_constraint_flag = 1; + tmp_ptl.max_422chroma_constraint_flag = 1; + break; + + case 2: + tmp_ptl.max_monochrome_constraint_flag = 0; + tmp_ptl.max_420chroma_constraint_flag = 0; + tmp_ptl.max_422chroma_constraint_flag = 1; + break; + + case 3: + tmp_ptl.max_monochrome_constraint_flag = 0; + tmp_ptl.max_420chroma_constraint_flag = 0; + tmp_ptl.max_422chroma_constraint_flag = 0; + break; + + default: + g_assert_not_reached (); + break; + } + + tmp_ptl.max_8bit_constraint_flag = 1; + tmp_ptl.max_10bit_constraint_flag = 1; + tmp_ptl.max_12bit_constraint_flag = 1; + tmp_ptl.max_14bit_constraint_flag = 1; + + if (bit_depth_luma > 8 || bit_depth_chroma > 8) + tmp_ptl.max_8bit_constraint_flag = 0; + + if (bit_depth_luma > 10 || bit_depth_chroma > 10) + tmp_ptl.max_10bit_constraint_flag = 0; - p = gst_h265_profile_tier_level_get_profile (&tmp_ptl); + if (bit_depth_luma > 12 || bit_depth_chroma > 12) + tmp_ptl.max_12bit_constraint_flag = 0; + + if (tmp_ptl.profile_idc == GST_H265_PROFILE_IDC_HIGH_THROUGHPUT + || tmp_ptl.profile_idc == GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING + || tmp_ptl.profile_idc == + GST_H265_PROFILE_IDC_SCALABLE_FORMAT_RANGE_EXTENSION + || tmp_ptl.profile_idc == + GST_H265_PROFILE_IDC_HIGH_THROUGHPUT_SCREEN_CONTENT_CODING_EXTENSION + || tmp_ptl.profile_compatibility_flag[5] + || tmp_ptl.profile_compatibility_flag[9] + || tmp_ptl.profile_compatibility_flag[10] + || tmp_ptl.profile_compatibility_flag[11]) { + if (bit_depth_luma > 14 || bit_depth_chroma > 14) + tmp_ptl.max_14bit_constraint_flag = 0; + } else { + tmp_ptl.max_14bit_constraint_flag = 0; } - return p; + /* first profile of the synthetic ptl */ + return gst_h265_profile_tier_level_get_profile (&tmp_ptl); } -- 2.7.4