h265parse: Add support for compatible profiles of extensions

From decoder's capability point of view as defined by the h265 specification,
accept peer profile caps.
This commit is contained in:
Seungha Yang 2019-07-20 22:38:46 +09:00
parent 4fa5a82762
commit 5e7dbdf585
2 changed files with 205 additions and 39 deletions

View file

@ -136,6 +136,9 @@ typedef enum {
GST_H265_PROFILE_SCALABLE_MONOCHROME_16, GST_H265_PROFILE_SCALABLE_MONOCHROME_16,
GST_H265_PROFILE_SCALABLE_MAIN_444, GST_H265_PROFILE_SCALABLE_MAIN_444,
GST_H265_PROFILE_3D_MAIN, GST_H265_PROFILE_3D_MAIN,
/* end of the profiles */
GST_H265_PROFILE_MAX
} GstH265Profile; } GstH265Profile;
/** /**

View file

@ -1664,59 +1664,221 @@ get_level_string (guint8 level_idc)
} }
} }
static inline guint64
profile_to_flag (GstH265Profile p)
{
return (guint64) 1 << (guint64) p;
}
static GstCaps * static GstCaps *
get_compatible_profile_caps (GstH265SPS * sps) get_compatible_profile_caps (GstH265SPS * sps, GstH265Profile profile)
{ {
GstCaps *caps = NULL; GstCaps *caps = NULL;
const gchar **profiles = NULL;
gint i; gint i;
GValue compat_profiles = G_VALUE_INIT; GValue compat_profiles = G_VALUE_INIT;
guint64 profiles = 0;
g_value_init (&compat_profiles, GST_TYPE_LIST); g_value_init (&compat_profiles, GST_TYPE_LIST);
switch (sps->profile_tier_level.profile_idc) { /* Relaxing profiles condition based on decoder capability specified by spec */
case GST_H265_PROFILE_IDC_MAIN_10: if (sps->profile_tier_level.profile_compatibility_flag[1])
if (sps->profile_tier_level.profile_compatibility_flag[1]) { profiles |= profile_to_flag (GST_H265_PROFILE_MAIN);
if (sps->profile_tier_level.profile_compatibility_flag[3]) {
static const gchar *profile_array[] = if (sps->profile_tier_level.profile_compatibility_flag[2])
{ "main", "main-still-picture", NULL }; profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_10);
profiles = profile_array;
} else { if (sps->profile_tier_level.profile_compatibility_flag[3])
static const gchar *profile_array[] = { "main", NULL }; profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_STILL_PICTURE);
profiles = profile_array;
} switch (profile) {
} case GST_H265_PROFILE_MAIN_10:
break;
case GST_H265_PROFILE_IDC_MAIN:
if (sps->profile_tier_level.profile_compatibility_flag[3]) {
static const gchar *profile_array[] =
{ "main-still-picture", "main-10", NULL
};
profiles = profile_array;
} else {
static const gchar *profile_array[] = { "main-10", NULL };
profiles = profile_array;
}
break;
case GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE:
{ {
static const gchar *profile_array[] = { "main", "main-10", NULL /* A.3.5 */
}; profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_12);
profiles = profile_array; profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_10);
} profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_10);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_12);
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10);
/* H.11.1.1 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCALABLE_MAIN_10);
break; break;
}
case GST_H265_PROFILE_MAIN:
{
/* A.3.3 */
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_10);
/* A.3.5 */
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_10);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_10);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_12);
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444);
profiles |=
profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
/* G.11.1.1 */
profiles |= profile_to_flag (GST_H265_PROFILE_MULTIVIEW_MAIN);
/* H.11.1.1 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCALABLE_MAIN);
profiles |= profile_to_flag (GST_H265_PROFILE_SCALABLE_MAIN_10);
/* I.11.1.1 */
profiles |= profile_to_flag (GST_H265_PROFILE_3D_MAIN);
break;
}
case GST_H265_PROFILE_MAIN_STILL_PICTURE:
{
/* A.3.2, A.3.4 */
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_10);
/* A.3.5 */
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_10);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_10);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_12);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_10_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_12_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_10_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_422_12_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_10_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_12_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_16_INTRA);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_STILL_PICTURE);
profiles |= profile_to_flag (GST_H265_PROFILE_MAIN_444_16_STILL_PICTURE);
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444);
profiles |=
profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
break;
}
case GST_H265_PROFILE_MONOCHROME:
{
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10);
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444);
profiles |=
profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
break;
}
case GST_H265_PROFILE_MAIN_444:
{
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444);
profiles |=
profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10);
break;
}
case GST_H265_PROFILE_MAIN_444_10:
{
/* A.3.7 */
profiles |= profile_to_flag (GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10);
break;
}
case GST_H265_PROFILE_HIGH_THROUGHPUT_444:
{
/* A.3.7 */
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
break;
}
case GST_H265_PROFILE_HIGH_THROUGHPUT_444_10:
{
/* A.3.7 */
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10);
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
break;
}
case GST_H265_PROFILE_HIGH_THROUGHPUT_444_14:
{
/* A.3.7 */
profiles |=
profile_to_flag
(GST_H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14);
break;
}
default: default:
break; break;
} }
if (profiles) { if (profiles) {
GValue value = G_VALUE_INIT; GValue value = G_VALUE_INIT;
const gchar *profile_str;
caps = gst_caps_new_empty_simple ("video/x-h265"); caps = gst_caps_new_empty_simple ("video/x-h265");
for (i = 0; profiles[i]; i++) {
for (i = GST_H265_PROFILE_MAIN; i < GST_H265_PROFILE_MAX; i++) {
if ((profiles & profile_to_flag (i)) == profile_to_flag (i)) {
profile_str = get_profile_string (i);
if (G_UNLIKELY (profile_str == NULL)) {
GST_FIXME ("Unhandled profile index %d", i);
continue;
}
g_value_init (&value, G_TYPE_STRING); g_value_init (&value, G_TYPE_STRING);
g_value_set_string (&value, profiles[i]); g_value_set_string (&value, profile_str);
gst_value_list_append_value (&compat_profiles, &value); gst_value_list_append_value (&compat_profiles, &value);
g_value_unset (&value); g_value_unset (&value);
} }
}
gst_caps_set_value (caps, "profile", &compat_profiles); gst_caps_set_value (caps, "profile", &compat_profiles);
g_value_unset (&compat_profiles); g_value_unset (&compat_profiles);
} }
@ -1727,7 +1889,8 @@ get_compatible_profile_caps (GstH265SPS * sps)
/* if downstream didn't support the exact profile indicated in sps header, /* if downstream didn't support the exact profile indicated in sps header,
* check for the compatible profiles also */ * check for the compatible profiles also */
static void static void
ensure_caps_profile (GstH265Parse * h265parse, GstCaps * caps, GstH265SPS * sps) ensure_caps_profile (GstH265Parse * h265parse, GstCaps * caps, GstH265SPS * sps,
GstH265Profile profile)
{ {
GstCaps *peer_caps, *compat_caps; GstCaps *peer_caps, *compat_caps;
@ -1747,7 +1910,7 @@ ensure_caps_profile (GstH265Parse * h265parse, GstCaps * caps, GstH265SPS * sps)
if (peer_caps && !gst_caps_can_intersect (caps, peer_caps)) { if (peer_caps && !gst_caps_can_intersect (caps, peer_caps)) {
GstStructure *structure; GstStructure *structure;
compat_caps = get_compatible_profile_caps (sps); compat_caps = get_compatible_profile_caps (sps, profile);
if (compat_caps != NULL) { if (compat_caps != NULL) {
GstCaps *res_caps = NULL; GstCaps *res_caps = NULL;
@ -2028,7 +2191,7 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps)
gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL); gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
/* relax the profile constraint to find a suitable decoder */ /* relax the profile constraint to find a suitable decoder */
ensure_caps_profile (h265parse, caps, sps); ensure_caps_profile (h265parse, caps, sps, p);
} }
if (s if (s