mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-05-18 00:12:46 +00:00
Merge branch 'sdp-h264-profile-level-id' into 'main'
sdp: Improve h.264 caps <-> media accuracy See merge request gstreamer/gstreamer!3616
This commit is contained in:
commit
9766a56225
|
@ -3563,8 +3563,8 @@ gst_sdp_media_add_rtcp_fb_attributes_from_media (const GstSDPMedia * media,
|
|||
static void
|
||||
gst_sdp_media_caps_adjust_h264 (GstCaps * caps)
|
||||
{
|
||||
long int spsint;
|
||||
guint8 sps[2];
|
||||
gint64 spsint;
|
||||
guint8 sps[3];
|
||||
const gchar *profile_level_id;
|
||||
GstStructure *s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
|
@ -3576,19 +3576,109 @@ gst_sdp_media_caps_adjust_h264 (GstCaps * caps)
|
|||
if (!profile_level_id)
|
||||
return;
|
||||
|
||||
spsint = strtol (profile_level_id, NULL, 16);
|
||||
spsint = g_ascii_strtoll (profile_level_id, NULL, 16);
|
||||
sps[0] = spsint >> 16;
|
||||
sps[1] = spsint >> 8;
|
||||
sps[1] = (spsint >> 8) & 0xff;
|
||||
sps[2] = spsint & 0xff;
|
||||
|
||||
GST_DEBUG ("'level-asymmetry-allowed' is set so we shouldn't care about "
|
||||
"'profile-level-id' and only set a 'profile' instead");
|
||||
"'profile-level-id' and only set a 'profile' and 'level' instead");
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING,
|
||||
gst_codec_utils_h264_get_profile (sps, 2), NULL);
|
||||
gst_codec_utils_h264_get_profile (sps, 3), "level", G_TYPE_STRING,
|
||||
gst_codec_utils_h264_get_level (sps, 3), NULL);
|
||||
|
||||
gst_structure_remove_fields (s, "level-asymmetry-allowed", "profile-level-id",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
gst_sdp_media_h264_profile_level_id_from_profile_and_level (const gchar *
|
||||
profile, const gchar * level)
|
||||
{
|
||||
gint csf0, csf1, csf2, csf3, csf4, csf5, profile_iop, reserved_zero_2bits;
|
||||
gint profile_idc = 0;
|
||||
guint8 level_idc = 0;
|
||||
|
||||
csf0 = csf1 = csf2 = csf3 = csf4 = csf5 = reserved_zero_2bits = profile_iop =
|
||||
0;
|
||||
|
||||
g_return_val_if_fail (profile != NULL, NULL);
|
||||
|
||||
if (level != NULL) {
|
||||
level_idc = gst_codec_utils_h264_get_level_idc (level);
|
||||
if (!strcmp (level, "1b")) {
|
||||
csf3 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp (profile, "baseline")) {
|
||||
profile_idc = 66;
|
||||
} else if (!strcmp (profile, "constrained-baseline")) {
|
||||
profile_idc = 66;
|
||||
csf1 = 1;
|
||||
} else if (!strcmp (profile, "main")) {
|
||||
profile_idc = 77;
|
||||
} else if (!strcmp (profile, "extended")) {
|
||||
profile_idc = 88;
|
||||
} else if (!strcmp (profile, "high")) {
|
||||
profile_idc = 100;
|
||||
} else if (!strcmp (profile, "constrained-high")) {
|
||||
profile_idc = 100;
|
||||
csf4 = 1;
|
||||
csf5 = 1;
|
||||
} else if (!strcmp (profile, "progressive-high")) {
|
||||
profile_idc = 100;
|
||||
csf4 = 1;
|
||||
} else if (!strcmp (profile, "high-10")) {
|
||||
profile_idc = 110;
|
||||
} else if (!strcmp (profile, "high-10-intra")) {
|
||||
profile_idc = 110;
|
||||
csf3 = 1;
|
||||
} else if (!strcmp (profile, "progressive-high-10")) {
|
||||
profile_idc = 110;
|
||||
csf4 = 1;
|
||||
} else if (g_str_has_prefix (profile, "high-4:2:2")) {
|
||||
profile_idc = 122;
|
||||
if (!strcmp (profile, "high-4:2:2-intra")) {
|
||||
csf3 = 1;
|
||||
}
|
||||
} else if (g_str_has_prefix (profile, "high-4:4:4")) {
|
||||
profile_idc = 244;
|
||||
if (!strcmp (profile, "high-4:4:4-intra")) {
|
||||
csf3 = 1;
|
||||
}
|
||||
} else if (!strcmp (profile, "cavlc-4:4:4-intra")) {
|
||||
profile_idc = 44;
|
||||
} else if (!strcmp (profile, "multiview-high")) {
|
||||
profile_idc = 118;
|
||||
} else if (!strcmp (profile, "stereo-high")) {
|
||||
profile_idc = 128;
|
||||
} else if (!strcmp (profile, "scalable-baseline")) {
|
||||
profile_idc = 83;
|
||||
} else if (!strcmp (profile, "scalable-constrained-baseline")) {
|
||||
profile_idc = 83;
|
||||
csf5 = 1;
|
||||
} else if (!strcmp (profile, "scalable-high")) {
|
||||
profile_idc = 86;
|
||||
} else if (!strcmp (profile, "scalable-high-intra")) {
|
||||
profile_idc = 86;
|
||||
csf3 = 1;
|
||||
} else if (!strcmp (profile, "scalable-constrained-high")) {
|
||||
profile_idc = 86;
|
||||
csf5 = 1;
|
||||
} else {
|
||||
GST_FIXME ("H.264 profile %s to profile-level-id translation unimplemented",
|
||||
profile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
profile_iop |=
|
||||
(csf0 << 7) | (csf1 << 6) | (csf2 << 5) | (csf3 << 4) | (csf4 << 3) |
|
||||
(csf5 << 2) | (reserved_zero_2bits << 1);
|
||||
|
||||
return g_strdup_printf ("%02X%02X%02X", profile_idc, profile_iop, level_idc);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_sdp_media_get_caps_from_media:
|
||||
* @media: a #GstSDPMedia
|
||||
|
@ -4073,10 +4163,19 @@ gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
|
|||
if ((fval = gst_structure_get_string (s, fname))) {
|
||||
|
||||
/* "profile" is our internal representation of the notion of
|
||||
* "level-asymmetry-allowed" with caps, convert it back to the SDP
|
||||
* representation */
|
||||
* "level-asymmetry-allowed" and "profile-level-id" with caps, convert it
|
||||
* back to the SDP representation */
|
||||
if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "H264")
|
||||
&& !g_strcmp0 (fname, "profile")) {
|
||||
gchar *profile_level_id =
|
||||
gst_sdp_media_h264_profile_level_id_from_profile_and_level (fval,
|
||||
gst_structure_get_string (s, "level"));
|
||||
if (profile_level_id != NULL) {
|
||||
g_string_append_printf (fmtp, "%sprofile-level-id=%s",
|
||||
first ? "" : ";", profile_level_id);
|
||||
g_free (profile_level_id);
|
||||
first = FALSE;
|
||||
}
|
||||
fname = "level-asymmetry-allowed";
|
||||
fval = "1";
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <gst/sdp/gstsdpmessage.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const gchar *sdp = "v=0\r\n"
|
||||
|
@ -763,6 +764,11 @@ GST_START_TEST (media_from_caps_h264_with_profile_asymmetry_allowed)
|
|||
const GstSDPMedia *result_video;
|
||||
GstStructure *s_video;
|
||||
GstCaps *caps_video;
|
||||
GstSDPMedia media;
|
||||
GstSDPResult ret = GST_SDP_OK;
|
||||
const gchar *fmtp;
|
||||
gboolean profile_level_id_found = FALSE;
|
||||
gchar **pairs;
|
||||
|
||||
gst_sdp_message_new (&message);
|
||||
gst_sdp_message_parse_buffer ((guint8 *) h264_sdp, length, message);
|
||||
|
@ -777,7 +783,60 @@ GST_START_TEST (media_from_caps_h264_with_profile_asymmetry_allowed)
|
|||
fail_if (gst_structure_has_field (s_video, "profile-level-id"));
|
||||
fail_unless_equals_string (gst_structure_get_string (s_video, "profile"),
|
||||
"constrained-baseline");
|
||||
fail_unless_equals_string (gst_structure_get_string (s_video, "level"),
|
||||
"3.1");
|
||||
|
||||
/* Check that the conversion from caps to SDP preserved the profile and level
|
||||
* caps fields, through the profile-level-id SDP sub-attribute of the fmtp
|
||||
* attribute. */
|
||||
memset (&media, 0, sizeof (media));
|
||||
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_init (&media));
|
||||
|
||||
ret = gst_sdp_media_set_media_from_caps (caps_video, &media);
|
||||
fail_unless (ret == GST_SDP_OK);
|
||||
|
||||
fmtp = gst_sdp_media_get_attribute_val (&media, "fmtp");
|
||||
fail_unless (fmtp != NULL);
|
||||
pairs = g_strsplit (fmtp, ";", 0);
|
||||
for (int i = 0; pairs[i]; i++) {
|
||||
gchar *valpos;
|
||||
const gchar *val, *key;
|
||||
valpos = strstr (pairs[i], "=");
|
||||
if (valpos) {
|
||||
/* we have a '=' and thus a value, remove the '=' with \0 */
|
||||
*valpos = '\0';
|
||||
/* value is everything between '=' and ';'. We split the pairs at ;
|
||||
* boundaries so we can take the remainder of the value. Some servers
|
||||
* put spaces around the value which we strip off here. Alternatively
|
||||
* we could strip those spaces in the depayloaders should these spaces
|
||||
* actually carry any meaning in the future. */
|
||||
val = g_strstrip (valpos + 1);
|
||||
} else {
|
||||
/* simple <param>;.. is translated into <param>=1;... */
|
||||
val = "1";
|
||||
}
|
||||
/* strip the key of spaces, convert key to lowercase but not the value. */
|
||||
key = g_strstrip (pairs[i]);
|
||||
if (!strcmp (key, "profile-level-id")) {
|
||||
gint64 spsint;
|
||||
guint8 sps[3];
|
||||
spsint = g_ascii_strtoll (val, NULL, 16);
|
||||
sps[0] = spsint >> 16;
|
||||
sps[1] = (spsint >> 8) & 0xff;
|
||||
sps[2] = spsint & 0xff;
|
||||
|
||||
fail_unless_equals_string (gst_codec_utils_h264_get_profile (sps, 3),
|
||||
"constrained-baseline");
|
||||
fail_unless_equals_string (gst_codec_utils_h264_get_level (sps, 3),
|
||||
"3.1");
|
||||
profile_level_id_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_strfreev (pairs);
|
||||
fail_unless (profile_level_id_found);
|
||||
|
||||
gst_sdp_media_uninit (&media);
|
||||
gst_caps_unref (caps_video);
|
||||
gst_sdp_message_free (message);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue