mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
h264parse: 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=739992
This commit is contained in:
parent
788297fec3
commit
3910cbe7ce
1 changed files with 172 additions and 0 deletions
|
@ -1197,6 +1197,176 @@ gst_h264_parse_get_par (GstH264Parse * h264parse, gint * num, gint * den)
|
|||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
get_compatible_profile_caps (GstH264SPS * 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_idc) {
|
||||
case GST_H264_PROFILE_EXTENDED:
|
||||
if (sps->constraint_set0_flag) { /* A.2.1 */
|
||||
if (sps->constraint_set1_flag) {
|
||||
static const gchar *profile_array[] =
|
||||
{ "constrained-baseline", "baseline", "main", "high",
|
||||
"high-10", "high-4:2:2", "high-4:4:4", NULL
|
||||
};
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
static const gchar *profile_array[] = { "baseline", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
} else if (sps->constraint_set1_flag) { /* A.2.2 */
|
||||
static const gchar *profile_array[] =
|
||||
{ "main", "high", "high-10", "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_BASELINE:
|
||||
if (sps->constraint_set1_flag) { /* A.2.1 */
|
||||
static const gchar *profile_array[] =
|
||||
{ "constrained-baseline", "main", "high", "high-10", "high-4:2:2",
|
||||
"high-4:4:4", NULL
|
||||
};
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
static const gchar *profile_array[] = { "extended", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_MAIN:
|
||||
{
|
||||
static const gchar *profile_array[] =
|
||||
{ "high", "high-10", "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_HIGH:
|
||||
if (sps->constraint_set1_flag) {
|
||||
static const gchar *profile_array[] =
|
||||
{ "main", "high-10", "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
static const gchar *profile_array[] =
|
||||
{ "high-10", "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_HIGH10:
|
||||
if (sps->constraint_set1_flag) {
|
||||
static const gchar *profile_array[] =
|
||||
{ "main", "high", "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
if (sps->constraint_set3_flag) { /* A.2.8 */
|
||||
static const gchar *profile_array[] =
|
||||
{ "high-10", "high-4:2:2", "high-4:4:4", "high-4:2:2-intra",
|
||||
"high-4:4:4-intra", NULL
|
||||
};
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
static const gchar *profile_array[] =
|
||||
{ "high-4:2:2", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_HIGH_422:
|
||||
if (sps->constraint_set1_flag) {
|
||||
static const gchar *profile_array[] =
|
||||
{ "main", "high", "high-10", "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
if (sps->constraint_set3_flag) { /* A.2.9 */
|
||||
static const gchar *profile_array[] =
|
||||
{ "high-4:2:2", "high-4:4:4", "high-4:4:4-intra", NULL };
|
||||
profiles = profile_array;
|
||||
} else {
|
||||
static const gchar *profile_array[] = { "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_HIGH_444:
|
||||
if (sps->constraint_set1_flag) {
|
||||
static const gchar *profile_array[] =
|
||||
{ "main", "high", "high-10", "high-4:2:2", NULL };
|
||||
profiles = profile_array;
|
||||
} else if (sps->constraint_set3_flag) { /* A.2.10 */
|
||||
static const gchar *profile_array[] = { "high-4:4:4", NULL };
|
||||
profiles = profile_array;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PROFILE_MULTIVIEW_HIGH:
|
||||
/* Fix: should add GST_H264_PROFILE_STEREO_HIGH as compatible
|
||||
* profile if number of views == 2. */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (profiles) {
|
||||
GValue value = G_VALUE_INIT;
|
||||
caps = gst_caps_new_empty_simple ("video/x-h264");
|
||||
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 (GstH264Parse * h264parse, GstCaps * caps, GstH264SPS * sps)
|
||||
{
|
||||
GstCaps *filter_caps, *peer_caps, *compat_caps;
|
||||
|
||||
filter_caps = gst_caps_new_empty_simple ("video/x-h264");
|
||||
peer_caps =
|
||||
gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (h264parse), 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 (h264parse,
|
||||
"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_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
|
||||
{
|
||||
|
@ -1364,6 +1534,8 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
|
|||
gst_codec_utils_h264_caps_set_level_and_profile (caps,
|
||||
map.data + 1, map.size - 1);
|
||||
gst_buffer_unmap (sps_buf, &map);
|
||||
/* relax the profile constraint to find a suitable decoder */
|
||||
ensure_caps_profile (h264parse, caps, sps);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue