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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1440>
This commit is contained in:
Víctor Manuel Jáquez Leal 2021-12-14 19:36:56 +01:00
parent 11791f7ce5
commit 168ad9f58f

View file

@ -3636,6 +3636,77 @@ static GstH265Profile
return get_extension_profile (profiles, G_N_ELEMENTS (profiles), ptl); return get_extension_profile (profiles, G_N_ELEMENTS (profiles), 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])
profiles[i++] = GST_H265_PROFILE_MAIN;
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN_10
|| ptl->profile_compatibility_flag[2])
profiles[i++] = GST_H265_PROFILE_MAIN_10;
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE
|| ptl->profile_compatibility_flag[3])
profiles[i++] = GST_H265_PROFILE_MAIN_STILL_PICTURE;
if (ptl->profile_idc == GST_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSION
|| ptl->profile_compatibility_flag[4])
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])
append_profile (profiles, &i, get_high_throughput_profile (ptl));
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MULTIVIEW_MAIN
|| ptl->profile_compatibility_flag[6])
append_profile (profiles, &i, get_multiview_profile (ptl));
if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCALABLE_MAIN
|| ptl->profile_compatibility_flag[7])
append_profile (profiles, &i, get_scalable_profile (ptl));
if (ptl->profile_idc == GST_H265_PROFILE_IDC_3D_MAIN
|| ptl->profile_compatibility_flag[8])
append_profile (profiles, &i, get_3d_profile (ptl));
if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING
|| 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]) {
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]) {
append_profile (profiles, &i,
get_screen_content_coding_extensions_high_throughput_profile (ptl));
}
*len = i;
}
/** /**
* gst_h265_profile_tier_level_get_profile: * gst_h265_profile_tier_level_get_profile:
* @ptl: a #GstH265ProfileTierLevel * @ptl: a #GstH265ProfileTierLevel
@ -3648,52 +3719,11 @@ static GstH265Profile
GstH265Profile GstH265Profile
gst_h265_profile_tier_level_get_profile (const GstH265ProfileTierLevel * ptl) gst_h265_profile_tier_level_get_profile (const GstH265ProfileTierLevel * ptl)
{ {
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN guint len;
|| ptl->profile_compatibility_flag[1]) GstH265Profile profiles[GST_H265_PROFILE_MAX] = { GST_H265_PROFILE_INVALID, };
return GST_H265_PROFILE_MAIN;
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MAIN_10 gst_h265_profile_tier_level_get_profiles (ptl, profiles, &len);
|| ptl->profile_compatibility_flag[2]) return profiles[0];
return 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;
if (ptl->profile_idc == GST_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSION
|| ptl->profile_compatibility_flag[4])
return 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);
if (ptl->profile_idc == GST_H265_PROFILE_IDC_MULTIVIEW_MAIN
|| ptl->profile_compatibility_flag[6])
return get_multiview_profile (ptl);
if (ptl->profile_idc == GST_H265_PROFILE_IDC_SCALABLE_MAIN
|| ptl->profile_compatibility_flag[7])
return get_scalable_profile (ptl);
if (ptl->profile_idc == GST_H265_PROFILE_IDC_3D_MAIN
|| ptl->profile_compatibility_flag[8])
return 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);
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);
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);
return GST_H265_PROFILE_INVALID;
} }
/** /**
@ -4318,78 +4348,106 @@ gst_h265_parser_insert_sei_hevc (GstH265Parser * parser, guint8 nal_length_size,
GstH265Profile GstH265Profile
gst_h265_get_profile_from_sps (GstH265SPS * sps) gst_h265_get_profile_from_sps (GstH265SPS * sps)
{ {
GstH265Profile p; 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;
p = gst_h265_profile_tier_level_get_profile (&sps->profile_tier_level); g_return_val_if_fail (sps != NULL, GST_H265_PROFILE_INVALID);
if (p == GST_H265_PROFILE_INVALID) { tmp_ptl = sps->profile_tier_level;
GstH265ProfileTierLevel tmp_ptl = sps->profile_tier_level; chroma_format_idc = sps->chroma_format_idc;
guint chroma_format_idc = sps->chroma_format_idc; bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
guint bit_depth_luma = sps->bit_depth_luma_minus8 + 8; bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
guint bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
/* Set the conformance indicators based on chroma_format_idc / bit_depth */ gst_h265_profile_tier_level_get_profiles (&sps->profile_tier_level, profiles,
switch (chroma_format_idc) { &len);
case 0:
tmp_ptl.max_monochrome_constraint_flag = 1; for (i = 0; i < len && i < G_N_ELEMENTS (profiles); i++) {
tmp_ptl.max_420chroma_constraint_flag = 1; switch (profiles[i]) {
tmp_ptl.max_422chroma_constraint_flag = 1; case GST_H265_PROFILE_INVALID:
break; break;
case GST_H265_PROFILE_MAIN:
case 1: case GST_H265_PROFILE_MAIN_STILL_PICTURE:
tmp_ptl.max_monochrome_constraint_flag = 0; /* A.3.2 or A.3.5 */
tmp_ptl.max_420chroma_constraint_flag = 1; if (chroma_format_idc == 1
tmp_ptl.max_422chroma_constraint_flag = 1; && bit_depth_luma == 8 && bit_depth_chroma == 8)
return profiles[i];
break; break;
case GST_H265_PROFILE_MAIN_10:
case 2: /* A.3.3 */
tmp_ptl.max_monochrome_constraint_flag = 0; if (chroma_format_idc == 1
tmp_ptl.max_420chroma_constraint_flag = 0; && bit_depth_luma >= 8 && bit_depth_luma <= 10
tmp_ptl.max_422chroma_constraint_flag = 1; && bit_depth_chroma >= 8 && bit_depth_chroma <= 10)
return profiles[i];
break; 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: default:
g_assert_not_reached (); return profiles[i];
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;
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;
p = gst_h265_profile_tier_level_get_profile (&tmp_ptl);
} }
return p; /* 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;
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;
}
/* first profile of the synthetic ptl */
return gst_h265_profile_tier_level_get_profile (&tmp_ptl);
} }