diff options
author | Sreerenj Balachandran <sreerenj.balachandran@intel.com> | 2015-08-07 05:58:22 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2015-08-07 13:11:53 +0200 |
commit | 69becd734d3f94264f6f0ef2e6147205646c1abd (patch) | |
tree | e50f7be7b6115686c5d2ee5868dd7cd486d917fe /gst | |
parent | ef7a074fa04895208530a2ffd370a8fabb699b2b (diff) | |
download | gstreamer-plugins-bad-69becd734d3f94264f6f0ef2e6147205646c1abd.tar.gz |
h265parse: expose compatible profiles to downstream
Some video bitstreams report a too restrictive set of profiles. If a video
decoder was to strictly follow the indicated profile, it wouldn't support that
stream, whereas it could in theory and in practice. So we should relax the
profile restriction for allowing the decoder to get connected with parser.
https://bugzilla.gnome.org/show_bug.cgi?id=747613
Diffstat (limited to 'gst')
-rw-r--r-- | gst/videoparsers/gsth265parse.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/gst/videoparsers/gsth265parse.c b/gst/videoparsers/gsth265parse.c index 983ffec1d..a11b7fc5d 100644 --- a/gst/videoparsers/gsth265parse.c +++ b/gst/videoparsers/gsth265parse.c @@ -1273,6 +1273,109 @@ get_level_string (guint8 level_idc) } } +static GstCaps * +get_compatible_profile_caps (GstH265SPS * sps) +{ + GstCaps *caps = NULL; + const gchar **profiles = NULL; + gint i; + GValue compat_profiles = G_VALUE_INIT; + g_value_init (&compat_profiles, GST_TYPE_LIST); + + switch (sps->profile_tier_level.profile_idc) { + case GST_H265_PROFILE_MAIN_10: + if (sps->profile_tier_level.profile_compatibility_flag[1]) { + if (sps->profile_tier_level.profile_compatibility_flag[3]) { + static const gchar *profile_array[] = + { "main", "main-still-picture", NULL }; + profiles = profile_array; + } else { + static const gchar *profile_array[] = { "main", NULL }; + profiles = profile_array; + } + } + break; + case GST_H265_PROFILE_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_MAIN_STILL_PICTURE: + { + static const gchar *profile_array[] = { "main", "main-10", NULL + }; + profiles = profile_array; + } + break; + default: + break; + } + + if (profiles) { + GValue value = G_VALUE_INIT; + caps = gst_caps_new_empty_simple ("video/x-h265"); + for (i = 0; profiles[i]; i++) { + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, profiles[i]); + gst_value_list_append_value (&compat_profiles, &value); + g_value_unset (&value); + } + gst_caps_set_value (caps, "profile", &compat_profiles); + g_value_unset (&compat_profiles); + } + + return caps; +} + +/* if downstream didn't support the exact profile indicated in sps header, + * check for the compatible profiles also */ +static void +ensure_caps_profile (GstH265Parse * h265parse, GstCaps * caps, GstH265SPS * sps) +{ + GstCaps *filter_caps, *peer_caps, *compat_caps; + + filter_caps = gst_caps_new_empty_simple ("video/x-h265"); + peer_caps = + gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (h265parse), filter_caps); + + if (peer_caps && !gst_caps_can_intersect (caps, peer_caps)) { + GstStructure *structure; + + compat_caps = get_compatible_profile_caps (sps); + if (compat_caps != NULL) { + GstCaps *res_caps = NULL; + + res_caps = gst_caps_intersect (peer_caps, compat_caps); + + if (res_caps && !gst_caps_is_empty (res_caps)) { + const gchar *profile_str = NULL; + + res_caps = gst_caps_fixate (res_caps); + structure = gst_caps_get_structure (res_caps, 0); + profile_str = gst_structure_get_string (structure, "profile"); + if (profile_str) { + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_str, + NULL); + GST_DEBUG_OBJECT (h265parse, + "Setting compatible profile %s to the caps", profile_str); + } + } + if (res_caps) + gst_caps_unref (res_caps); + gst_caps_unref (compat_caps); + } + } + if (peer_caps) + gst_caps_unref (peer_caps); + gst_caps_unref (filter_caps); +} + static void gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps) { @@ -1445,6 +1548,9 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps) level = get_level_string (sps->profile_tier_level.level_idc); if (level != NULL) gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL); + + /* relax the profile constraint to find a suitable decoder */ + ensure_caps_profile (h265parse, caps, sps); } src_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (h265parse)); |