mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 16:08:51 +00:00
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:
parent
f10867dfb5
commit
9ac502c21d
4 changed files with 83 additions and 2 deletions
|
@ -3,9 +3,9 @@ subdir('fft')
|
||||||
subdir('video')
|
subdir('video')
|
||||||
subdir('audio')
|
subdir('audio')
|
||||||
subdir('rtp')
|
subdir('rtp')
|
||||||
|
subdir('pbutils')
|
||||||
subdir('sdp')
|
subdir('sdp')
|
||||||
subdir('rtsp')
|
subdir('rtsp')
|
||||||
subdir('pbutils')
|
|
||||||
subdir('riff')
|
subdir('riff')
|
||||||
subdir('app')
|
subdir('app')
|
||||||
subdir('allocators')
|
subdir('allocators')
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include <gst/rtp/gstrtppayloads.h>
|
#include <gst/rtp/gstrtppayloads.h>
|
||||||
|
#include <gst/pbutils/pbutils.h>
|
||||||
#include "gstsdpmessage.h"
|
#include "gstsdpmessage.h"
|
||||||
|
|
||||||
#define FREE_STRING(field) g_free (field); (field) = NULL
|
#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;
|
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:
|
* gst_sdp_media_get_caps_from_media:
|
||||||
* @media: a #GstSDPMedia
|
* @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 */
|
/* parse rtcp-fb: field */
|
||||||
gst_sdp_media_add_rtcp_fb_attributes_from_media (media, pt, caps);
|
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))) {
|
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);
|
g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ gst_sdp_headers = files([
|
||||||
])
|
])
|
||||||
install_headers(gst_sdp_headers, subdir : 'gstreamer-1.0/gst/sdp/')
|
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'])
|
gst_sdp_sources = files(['gstsdpmessage.c', 'gstmikey.c'])
|
||||||
gstsdp = library('gstsdp-@0@'.format(api_version),
|
gstsdp = library('gstsdp-@0@'.format(api_version),
|
||||||
gst_sdp_sources,
|
gst_sdp_sources,
|
||||||
|
|
|
@ -47,6 +47,16 @@ static const gchar *sdp = "v=0\r\n"
|
||||||
"a=sendrecv\r\n"
|
"a=sendrecv\r\n"
|
||||||
"m=audio 1010 TCP 14\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[] =
|
static const gchar caps_video_string1[] =
|
||||||
"application/x-unknown, media=(string)video, payload=(int)96, "
|
"application/x-unknown, media=(string)video, payload=(int)96, "
|
||||||
"clock-rate=(int)90000, encoding-name=(string)MP4V-ES";
|
"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_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
|
GST_END_TEST
|
||||||
/*
|
/*
|
||||||
* End of test cases
|
* 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_100);
|
||||||
tcase_add_test (tc_chain, media_from_caps_rtcp_fb_pt_101);
|
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_extmap_pt_100);
|
||||||
|
tcase_add_test (tc_chain,
|
||||||
|
media_from_caps_h264_with_profile_asymmetry_allowed);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue