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
continue;
if (!strcmp (key, "extmap"))
continue;
+ if (!strcmp (key, "rid"))
+ continue;
/* string must be valid UTF8 */
if (!g_utf8_validate (attr->value, -1, NULL))
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
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);
"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* */
}
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
*/
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;
}