mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
sdp: support multiple rid parameters
As specified formally in RFC8851 Each rid description is placed in its own caps field in the structure. This is very similar to the already existing extmap-$id sdp<->caps transformations that already exists. The mapping is as follows: a=rid:0 direction ';'-separated params where direction is either 'send' or 'recv' gets put into a caps structure like so: rid-0=(string)<"direction","param1","param2",etc> If there are no rid parameters then the caps structure is generated to only contain the direction as a single string like: rid-0=(string)direction Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1760>
This commit is contained in:
parent
f8016687a4
commit
207769edbb
2 changed files with 326 additions and 0 deletions
|
@ -3991,6 +3991,52 @@ gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* rid values */
|
||||
if (g_str_has_prefix (fname, "rid-")) {
|
||||
const char *rid_id = &fname[strlen ("rid-")];
|
||||
const GValue *arr;
|
||||
|
||||
if (!rid_id || !*rid_id)
|
||||
continue;
|
||||
|
||||
if ((fval = gst_structure_get_string (s, fname))) {
|
||||
char *rid_val = g_strdup_printf ("%s %s", rid_id, fval);
|
||||
gst_sdp_media_add_attribute (media, "rid", rid_val);
|
||||
g_free (rid_val);
|
||||
} else if ((arr = gst_structure_get_value (s, fname))
|
||||
&& GST_VALUE_HOLDS_ARRAY (arr)
|
||||
&& gst_value_array_get_size (arr) > 1) {
|
||||
const gchar *direction, *param;
|
||||
GString *str;
|
||||
guint i, n;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
g_string_append_printf (str, "%s ", rid_id);
|
||||
|
||||
n = gst_value_array_get_size (arr);
|
||||
for (i = 0; i < n; i++) {
|
||||
const GValue *val = gst_value_array_get_value (arr, i);
|
||||
if (i == 0) {
|
||||
direction = g_value_get_string (val);
|
||||
g_string_append_printf (str, "%s", direction);
|
||||
} else {
|
||||
param = g_value_get_string (val);
|
||||
if (i == 1)
|
||||
g_string_append_c (str, ' ');
|
||||
else
|
||||
g_string_append_c (str, ';');
|
||||
g_string_append_printf (str, "%s", param);
|
||||
}
|
||||
}
|
||||
gst_sdp_media_add_attribute (media, "rid", str->str);
|
||||
g_string_free (str, TRUE);
|
||||
} else {
|
||||
GST_WARNING ("caps field %s is an unsupported format", fname);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((fval = gst_structure_get_string (s, fname))) {
|
||||
|
||||
/* "profile" is our internal representation of the notion of
|
||||
|
@ -4170,6 +4216,8 @@ sdp_add_attributes_to_caps (GArray * attributes, GstCaps * caps)
|
|||
continue;
|
||||
if (!strcmp (key, "extmap"))
|
||||
continue;
|
||||
if (!strcmp (key, "rid"))
|
||||
continue;
|
||||
|
||||
/* string must be valid UTF8 */
|
||||
if (!g_utf8_validate (attr->value, -1, NULL))
|
||||
|
@ -4295,6 +4343,138 @@ gst_sdp_media_add_extmap_attributes (GArray * attributes, GstCaps * caps)
|
|||
return GST_SDP_OK;
|
||||
}
|
||||
|
||||
/* parses RID SDP attributes (RFC8851) into caps */
|
||||
static GstSDPResult
|
||||
gst_sdp_media_add_rid_attributes (GArray * attributes, GstCaps * caps)
|
||||
{
|
||||
const gchar *rid;
|
||||
char *p, *to_free;
|
||||
guint i;
|
||||
GstStructure *s;
|
||||
|
||||
g_return_val_if_fail (attributes != NULL, GST_SDP_EINVAL);
|
||||
g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
|
||||
g_return_val_if_fail (gst_caps_is_writable (caps), GST_SDP_EINVAL);
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
for (i = 0; i < attributes->len; i++) {
|
||||
GstSDPAttribute *attr;
|
||||
const char *direction, *params, *id;
|
||||
const char *tmp;
|
||||
|
||||
attr = &g_array_index (attributes, GstSDPAttribute, i);
|
||||
if (strcmp (attr->key, "rid") != 0)
|
||||
continue;
|
||||
|
||||
rid = attr->value;
|
||||
|
||||
/* p is now of the format id dir ;-separated-params */
|
||||
to_free = p = g_strdup (rid);
|
||||
|
||||
PARSE_STRING (p, " ", id);
|
||||
if (id == NULL || *id == '\0') {
|
||||
GST_ERROR ("Invalid rid \'%s\'", to_free);
|
||||
goto next;
|
||||
}
|
||||
tmp = id;
|
||||
while (*tmp && (*tmp == '-' || *tmp == '_' || g_ascii_isalnum (*tmp)))
|
||||
tmp++;
|
||||
if (*tmp != '\0') {
|
||||
GST_ERROR ("Invalid rid-id \'%s\'", id);
|
||||
goto next;
|
||||
}
|
||||
|
||||
SKIP_SPACES (p);
|
||||
|
||||
PARSE_STRING (p, " ", direction);
|
||||
if (direction == NULL || *direction == '\0') {
|
||||
direction = p;
|
||||
params = NULL;
|
||||
} else {
|
||||
SKIP_SPACES (p);
|
||||
|
||||
params = p;
|
||||
}
|
||||
|
||||
if (direction == NULL || *direction == '\0'
|
||||
|| (g_strcmp0 (direction, "send") != 0
|
||||
&& g_strcmp0 (direction, "recv") != 0)) {
|
||||
GST_ERROR ("Invalid rid direction \'%s\'", p);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (params && *params != '\0') {
|
||||
GValue arr = G_VALUE_INIT;
|
||||
GValue val = G_VALUE_INIT;
|
||||
gchar *key;
|
||||
#if !defined(GST_DISABLE_DEBUG)
|
||||
GString *debug_params = g_string_new (NULL);
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
key = g_strdup_printf ("rid-%s", id);
|
||||
|
||||
g_value_init (&arr, GST_TYPE_ARRAY);
|
||||
g_value_init (&val, G_TYPE_STRING);
|
||||
|
||||
g_value_set_string (&val, direction);
|
||||
gst_value_array_append_and_take_value (&arr, &val);
|
||||
val = (GValue) G_VALUE_INIT;
|
||||
|
||||
while (*p) {
|
||||
const char *param;
|
||||
gboolean done = FALSE;
|
||||
|
||||
PARSE_STRING (p, ";", param);
|
||||
|
||||
if (param) {
|
||||
} else if (*p) {
|
||||
param = p;
|
||||
done = TRUE;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
g_value_init (&val, G_TYPE_STRING);
|
||||
g_value_set_string (&val, param);
|
||||
gst_value_array_append_and_take_value (&arr, &val);
|
||||
val = (GValue) G_VALUE_INIT;
|
||||
#if !defined(GST_DISABLE_DEBUG)
|
||||
if (i++ > 0)
|
||||
g_string_append_c (debug_params, ',');
|
||||
g_string_append (debug_params, param);
|
||||
#endif
|
||||
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
|
||||
gst_structure_take_value (s, key, &arr);
|
||||
arr = (GValue) G_VALUE_INIT;
|
||||
#if !defined(GST_DISABLE_DEBUG)
|
||||
{
|
||||
char *debug_str = g_string_free (debug_params, FALSE);
|
||||
GST_DEBUG ("adding caps: %s=<%s,%s>", key, direction, debug_str);
|
||||
g_free (debug_str);
|
||||
}
|
||||
#endif
|
||||
g_free (key);
|
||||
} else {
|
||||
gchar *key;
|
||||
|
||||
key = g_strdup_printf ("rid-%s", id);
|
||||
gst_structure_set (s, key, G_TYPE_STRING, direction, NULL);
|
||||
GST_DEBUG ("adding caps: %s=%s", key, direction);
|
||||
g_free (key);
|
||||
}
|
||||
|
||||
next:
|
||||
g_clear_pointer (&to_free, g_free);
|
||||
}
|
||||
return GST_SDP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_sdp_message_attributes_to_caps:
|
||||
* @msg: a #GstSDPMessage
|
||||
|
@ -4371,6 +4551,11 @@ gst_sdp_media_attributes_to_caps (const GstSDPMedia * media, GstCaps * caps)
|
|||
res = gst_sdp_media_add_extmap_attributes (media->attributes, caps);
|
||||
}
|
||||
|
||||
if (res == GST_SDP_OK) {
|
||||
/* parse media rid fields */
|
||||
res = gst_sdp_media_add_rid_attributes (media->attributes, caps);
|
||||
}
|
||||
|
||||
done:
|
||||
if (mikey)
|
||||
gst_mikey_message_unref (mikey);
|
||||
|
|
|
@ -182,6 +182,19 @@ static const gchar caps_application_raptor_fec_pt_110[] =
|
|||
"raptor-scheme-id=(string)1, kmax=(string)8192, t=(string)128, p=(string)A, repair-window=(string)200000, "
|
||||
"a-mid=(string)R1";
|
||||
|
||||
static const gchar caps_multiple_rid[] =
|
||||
"application/x-unknown, media=(string)video, payload=(int)96, "
|
||||
"clock-rate=(int)90000, encoding-name=(string)VP8, "
|
||||
"rid-h=(string)\"send\", "
|
||||
"rid-m=(string)\"send\", "
|
||||
"rid-l=(string)\"send\", "
|
||||
"a-simulcast=(string)\"send\\ h\\;m\\;l\"";
|
||||
|
||||
static const gchar caps_rid_params[] =
|
||||
"application/x-unknown, media=(string)video, payload=(int)96, "
|
||||
"clock-rate=(int)90000, encoding-name=(string)VP8, "
|
||||
"rid-0=(string)<\"send\",\"max-width=1920\",\"max-height=1080\">, "
|
||||
"rid-1=(string)<\"send\",\"max-width=1280\",\"max-height=720\">";
|
||||
|
||||
/* *INDENT-ON* */
|
||||
|
||||
|
@ -758,6 +771,132 @@ GST_START_TEST (media_from_caps_h264_with_profile_asymmetry_allowed)
|
|||
gst_sdp_message_free (message);
|
||||
}
|
||||
|
||||
GST_END_TEST
|
||||
GST_START_TEST (caps_multiple_rid_parse)
|
||||
{
|
||||
GstSDPMedia media, media2;
|
||||
GstCaps *caps, *expected;
|
||||
|
||||
/* BUG: gst_sdp_media_add_attributes_to_caps() would only set a single rid
|
||||
* string attribute key/value in caps */
|
||||
|
||||
memset (&media, 0, sizeof (media));
|
||||
fail_unless_equals_int (gst_sdp_media_init (&media), GST_SDP_OK);
|
||||
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_set_media (&media, "video"));
|
||||
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_add_format (&media, "96"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rtpmap", "96 VP8/90000"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rid", "h send"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rid", "m send"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rid", "l send"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "simulcast", "send h;m;l"));
|
||||
|
||||
expected = gst_caps_from_string (caps_multiple_rid);
|
||||
fail_unless (gst_caps_is_fixed (expected));
|
||||
fail_unless (expected != NULL);
|
||||
|
||||
caps = gst_sdp_media_get_caps_from_media (&media, 96);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_attributes_to_caps (&media, caps));
|
||||
fail_unless (gst_caps_is_fixed (caps));
|
||||
|
||||
GST_DEBUG (" caps %" GST_PTR_FORMAT, caps);
|
||||
GST_DEBUG ("expected %" GST_PTR_FORMAT, expected);
|
||||
fail_unless (gst_caps_is_equal (caps, expected));
|
||||
|
||||
memset (&media2, 0, sizeof (media2));
|
||||
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_init (&media2));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_set_media_from_caps (caps, &media2));
|
||||
|
||||
gst_clear_caps (&caps);
|
||||
|
||||
caps = gst_sdp_media_get_caps_from_media (&media, 96);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_attributes_to_caps (&media, caps));
|
||||
fail_unless (gst_caps_is_fixed (caps));
|
||||
|
||||
GST_DEBUG (" caps %" GST_PTR_FORMAT, caps);
|
||||
GST_DEBUG ("expected %" GST_PTR_FORMAT, expected);
|
||||
fail_unless (gst_caps_is_equal (caps, expected));
|
||||
|
||||
gst_sdp_media_uninit (&media);
|
||||
gst_sdp_media_uninit (&media2);
|
||||
|
||||
gst_clear_caps (&caps);
|
||||
gst_clear_caps (&expected);
|
||||
}
|
||||
|
||||
GST_END_TEST
|
||||
GST_START_TEST (caps_multiple_rid_parse_with_params)
|
||||
{
|
||||
GstSDPMedia media, media2;
|
||||
GstCaps *caps, *expected;
|
||||
|
||||
/* BUG: gst_sdp_media_add_attributes_to_caps() would only set a single rid
|
||||
* string attribute key/value in caps */
|
||||
|
||||
memset (&media, 0, sizeof (media));
|
||||
fail_unless_equals_int (gst_sdp_media_init (&media), GST_SDP_OK);
|
||||
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_set_media (&media, "video"));
|
||||
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_add_format (&media, "96"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rtpmap", "96 VP8/90000"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rid",
|
||||
"0 send max-width=1920;max-height=1080"));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_add_attribute (&media, "rid",
|
||||
"1 send max-width=1280;max-height=720"));
|
||||
|
||||
expected = gst_caps_from_string (caps_rid_params);
|
||||
fail_unless (gst_caps_is_fixed (expected));
|
||||
fail_unless (expected != NULL);
|
||||
|
||||
caps = gst_sdp_media_get_caps_from_media (&media, 96);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_attributes_to_caps (&media, caps));
|
||||
fail_unless (gst_caps_is_fixed (caps));
|
||||
|
||||
GST_DEBUG (" caps %" GST_PTR_FORMAT, caps);
|
||||
GST_DEBUG ("expected %" GST_PTR_FORMAT, expected);
|
||||
fail_unless (gst_caps_is_equal (caps, expected));
|
||||
|
||||
memset (&media2, 0, sizeof (media2));
|
||||
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_init (&media2));
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_set_media_from_caps (caps, &media2));
|
||||
|
||||
gst_clear_caps (&caps);
|
||||
|
||||
caps = gst_sdp_media_get_caps_from_media (&media, 96);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless_equals_int (GST_SDP_OK,
|
||||
gst_sdp_media_attributes_to_caps (&media, caps));
|
||||
fail_unless (gst_caps_is_fixed (caps));
|
||||
|
||||
GST_DEBUG (" caps %" GST_PTR_FORMAT, caps);
|
||||
GST_DEBUG ("expected %" GST_PTR_FORMAT, expected);
|
||||
fail_unless (gst_caps_is_equal (caps, expected));
|
||||
|
||||
gst_sdp_media_uninit (&media);
|
||||
gst_sdp_media_uninit (&media2);
|
||||
|
||||
gst_clear_caps (&caps);
|
||||
gst_clear_caps (&expected);
|
||||
}
|
||||
|
||||
GST_END_TEST
|
||||
/*
|
||||
* End of test cases
|
||||
|
@ -785,6 +924,8 @@ sdp_suite (void)
|
|||
tcase_add_test (tc_chain, media_from_caps_extmap_pt_100);
|
||||
tcase_add_test (tc_chain,
|
||||
media_from_caps_h264_with_profile_asymmetry_allowed);
|
||||
tcase_add_test (tc_chain, caps_multiple_rid_parse);
|
||||
tcase_add_test (tc_chain, caps_multiple_rid_parse_with_params);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue