sdp: Handle level-asymmetry-allowed for H264 streams

The ["level-asymmetry-allowed"] field states that the peer wants the
profile specified in the "profile-level-id" fields but doesn't care
about the level. To express this in GStreamer caps term, we add a
"profile" field in the caps, which reuses the usual "profile" semantics
for H.264 streams and, and remove "profile-level-id" and
"level-asymmetry-allowed" fields.

["level-asymmetry-allowed"]: https://www.iana.org/assignments/media-types/video/H264

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1410>
This commit is contained in:
Thibault Saunier 2021-12-03 01:45:49 +00:00
parent f10867dfb5
commit 9ac502c21d
4 changed files with 83 additions and 2 deletions

View file

@ -3,9 +3,9 @@ subdir('fft')
subdir('video')
subdir('audio')
subdir('rtp')
subdir('pbutils')
subdir('sdp')
subdir('rtsp')
subdir('pbutils')
subdir('riff')
subdir('app')
subdir('allocators')

View file

@ -61,6 +61,7 @@
#include <gio/gio.h>
#include <gst/rtp/gstrtppayloads.h>
#include <gst/pbutils/pbutils.h>
#include "gstsdpmessage.h"
#define FREE_STRING(field) g_free (field); (field) = NULL
@ -3540,6 +3541,35 @@ gst_sdp_media_add_rtcp_fb_attributes_from_media (const GstSDPMedia * media,
return GST_SDP_OK;
}
static void
gst_sdp_media_caps_adjust_h264 (GstCaps * caps)
{
long int spsint;
guint8 sps[2];
const gchar *profile_level_id;
GstStructure *s = gst_caps_get_structure (caps, 0);
if (g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "H264") ||
g_strcmp0 (gst_structure_get_string (s, "level-asymmetry-allowed"), "1"))
return;
profile_level_id = gst_structure_get_string (s, "profile-level-id");
if (!profile_level_id)
return;
spsint = strtol (profile_level_id, NULL, 16);
sps[0] = spsint >> 16;
sps[1] = spsint >> 8;
GST_DEBUG ("'level-asymmetry-allowed' is set so we shouldn't care about "
"'profile-level-id' and only set a 'profile' instead");
gst_structure_set (s, "profile", G_TYPE_STRING,
gst_codec_utils_h264_get_profile (sps, 2), NULL);
gst_structure_remove_fields (s, "level-asymmetry-allowed", "profile-level-id",
NULL);
}
/**
* gst_sdp_media_get_caps_from_media:
* @media: a #GstSDPMedia
@ -3714,6 +3744,8 @@ gst_sdp_media_get_caps_from_media (const GstSDPMedia * media, gint pt)
}
}
gst_sdp_media_caps_adjust_h264 (caps);
/* parse rtcp-fb: field */
gst_sdp_media_add_rtcp_fb_attributes_from_media (media, pt, caps);
@ -3960,6 +3992,16 @@ 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 */
if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "H264")
&& !g_strcmp0 (fname, "profile")) {
fname = "level-asymmetry-allowed";
fval = "1";
}
g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
first = FALSE;
}

View file

@ -7,7 +7,7 @@ gst_sdp_headers = files([
])
install_headers(gst_sdp_headers, subdir : 'gstreamer-1.0/gst/sdp/')
sdp_deps = [rtp_dep, gst_dep, gio_dep]
sdp_deps = [rtp_dep, gst_dep, gio_dep, pbutils_dep]
gst_sdp_sources = files(['gstsdpmessage.c', 'gstmikey.c'])
gstsdp = library('gstsdp-@0@'.format(api_version),
gst_sdp_sources,

View file

@ -47,6 +47,16 @@ static const gchar *sdp = "v=0\r\n"
"a=sendrecv\r\n"
"m=audio 1010 TCP 14\r\n";
static const gchar *h264_sdp = "v=0\r\n"
"o=- 992782775729845470 2 IN IP4 127.0.0.1\r\n"
"s=TestH264\r\n"
"t=0 0\r\n"
"m=video 9 UDP/TLS/RTP/SAVPF 96\r\n"
"c=IN IP4 0.0.0.0\r\n"
"a=recvonly\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\n";
static const gchar caps_video_string1[] =
"application/x-unknown, media=(string)video, payload=(int)96, "
"clock-rate=(int)90000, encoding-name=(string)MP4V-ES";
@ -657,6 +667,33 @@ GST_START_TEST (caps_from_media_really_const)
gst_sdp_message_free (message);
}
GST_END_TEST
GST_START_TEST (media_from_caps_h264_with_profile_asymmetry_allowed)
{
GstSDPMessage *message;
glong length = -1;
const GstSDPMedia *result_video;
GstStructure *s_video;
GstCaps *caps_video;
gst_sdp_message_new (&message);
gst_sdp_message_parse_buffer ((guint8 *) h264_sdp, length, message);
result_video = gst_sdp_message_get_media (message, 0);
fail_unless (result_video != NULL);
caps_video = gst_sdp_media_get_caps_from_media (result_video, 96);
s_video = gst_caps_get_structure (caps_video, 0);
fail_if (gst_structure_has_field (s_video, "level-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");
gst_caps_unref (caps_video);
gst_sdp_message_free (message);
}
GST_END_TEST
/*
* End of test cases
@ -681,6 +718,8 @@ sdp_suite (void)
tcase_add_test (tc_chain, media_from_caps_rtcp_fb_pt_100);
tcase_add_test (tc_chain, media_from_caps_rtcp_fb_pt_101);
tcase_add_test (tc_chain, media_from_caps_extmap_pt_100);
tcase_add_test (tc_chain,
media_from_caps_h264_with_profile_asymmetry_allowed);
return s;
}