mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +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;
|
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))) {
|
if ((fval = gst_structure_get_string (s, fname))) {
|
||||||
|
|
||||||
/* "profile" is our internal representation of the notion of
|
/* "profile" is our internal representation of the notion of
|
||||||
|
@ -4170,6 +4216,8 @@ sdp_add_attributes_to_caps (GArray * attributes, GstCaps * caps)
|
||||||
continue;
|
continue;
|
||||||
if (!strcmp (key, "extmap"))
|
if (!strcmp (key, "extmap"))
|
||||||
continue;
|
continue;
|
||||||
|
if (!strcmp (key, "rid"))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* string must be valid UTF8 */
|
/* string must be valid UTF8 */
|
||||||
if (!g_utf8_validate (attr->value, -1, NULL))
|
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;
|
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:
|
* gst_sdp_message_attributes_to_caps:
|
||||||
* @msg: a #GstSDPMessage
|
* @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);
|
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:
|
done:
|
||||||
if (mikey)
|
if (mikey)
|
||||||
gst_mikey_message_unref (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, "
|
"raptor-scheme-id=(string)1, kmax=(string)8192, t=(string)128, p=(string)A, repair-window=(string)200000, "
|
||||||
"a-mid=(string)R1";
|
"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* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
@ -758,6 +771,132 @@ GST_START_TEST (media_from_caps_h264_with_profile_asymmetry_allowed)
|
||||||
gst_sdp_message_free (message);
|
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
|
GST_END_TEST
|
||||||
/*
|
/*
|
||||||
* End of test cases
|
* 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_extmap_pt_100);
|
||||||
tcase_add_test (tc_chain,
|
tcase_add_test (tc_chain,
|
||||||
media_from_caps_h264_with_profile_asymmetry_allowed);
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue