*
* a=fmtp:(payload) (param)[=(value)];...
*
+ * Note that the extmap attribute is set only by gst_sdp_media_attributes_to_caps().
+ *
* Returns: a #GstCaps, or %NULL if an error happened
*
* Since: 1.8
*
* a=rtcp-fb:(payload) (param1) [param2]...
*
+ * a=extmap:(id)[/direction] (extensionname) (extensionattributes)
+ *
* Returns: a #GstSDPResult.
*
* Since: 1.8
}
}
- /* collect all other properties and add them to fmtp or attributes */
+ /* collect all other properties and add them to fmtp, extmap or attributes */
fmtp = g_string_new ("");
g_string_append_printf (fmtp, "%d ", caps_pt);
first = TRUE;
continue;
}
+ /* extmap */
+ if (g_str_has_prefix (fname, "extmap-")) {
+ gchar *endptr;
+ guint id = strtoull (fname + 7, &endptr, 10);
+ const GValue *arr;
+
+ if (*endptr != '\0' || id == 0 || id == 15 || id > 9999)
+ continue;
+
+ if ((fval = gst_structure_get_string (s, fname))) {
+ gchar *extmap = g_strdup_printf ("%u %s", id, fval);
+ gst_sdp_media_add_attribute (media, "extmap", extmap);
+ g_free (extmap);
+ } else if ((arr = gst_structure_get_value (s, fname))
+ && G_VALUE_HOLDS (arr, GST_TYPE_ARRAY)
+ && gst_value_array_get_size (arr) == 3) {
+ const GValue *val;
+ const gchar *direction, *extensionname, *extensionattributes;
+
+ val = gst_value_array_get_value (arr, 0);
+ direction = g_value_get_string (val);
+
+ val = gst_value_array_get_value (arr, 1);
+ extensionname = g_value_get_string (val);
+
+ val = gst_value_array_get_value (arr, 2);
+ extensionattributes = g_value_get_string (val);
+
+ if (!extensionname || *extensionname == '\0')
+ continue;
+
+ if (direction && *direction != '\0' && extensionattributes
+ && *extensionattributes != '\0') {
+ gchar *extmap =
+ g_strdup_printf ("%u/%s %s %s", id, direction, extensionname,
+ extensionattributes);
+ gst_sdp_media_add_attribute (media, "extmap", extmap);
+ g_free (extmap);
+ } else if (direction && *direction != '\0') {
+ gchar *extmap =
+ g_strdup_printf ("%u/%s %s", id, direction, extensionname);
+ gst_sdp_media_add_attribute (media, "extmap", extmap);
+ g_free (extmap);
+ } else if (extensionattributes && *extensionattributes != '\0') {
+ gchar *extmap = g_strdup_printf ("%u %s %s", id, extensionname,
+ extensionattributes);
+ gst_sdp_media_add_attribute (media, "extmap", extmap);
+ g_free (extmap);
+ } else {
+ gchar *extmap = g_strdup_printf ("%u %s", id, extensionname);
+ gst_sdp_media_add_attribute (media, "extmap", extmap);
+ g_free (extmap);
+ }
+ }
+ continue;
+ }
+
if ((fval = gst_structure_get_string (s, fname))) {
g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
first = FALSE;
continue;
if (!strcmp (key, "key-mgmt"))
continue;
+ if (!strcmp (key, "extmap"))
+ continue;
/* string must be valid UTF8 */
if (!g_utf8_validate (attr->value, -1, NULL))
return GST_SDP_OK;
}
+static GstSDPResult
+gst_sdp_media_add_extmap_attributes (GArray * attributes, GstCaps * caps)
+{
+ const gchar *extmap;
+ gchar *p, *tmp, *to_free;
+ guint id, 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);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ for (i = 0; i < attributes->len; i++) {
+ GstSDPAttribute *attr;
+ const gchar *direction, *extensionname, *extensionattributes;
+
+ attr = &g_array_index (attributes, GstSDPAttribute, i);
+ if (strcmp (attr->key, "extmap") != 0)
+ continue;
+
+ extmap = attr->value;
+
+ /* p is now of the format id[/direction] extensionname [extensionattributes] */
+ to_free = p = g_strdup (extmap);
+
+ id = strtoul (p, &tmp, 10);
+ if (id == 0 || id == 15 || id > 9999 || (*tmp != ' ' && *tmp != '/')) {
+ GST_ERROR ("Invalid extmap '%s'", to_free);
+ goto next;
+ } else if (*tmp == '/') {
+ p = tmp;
+ p++;
+
+ PARSE_STRING (p, " ", direction);
+
+ /* Invalid format */
+ if (direction == NULL || *direction == '\0') {
+ GST_ERROR ("Invalid extmap '%s'", to_free);
+ goto next;
+ }
+ } else {
+ /* At the space */
+ p = tmp;
+ direction = "";
+ }
+
+ SKIP_SPACES (p);
+
+ tmp = strstr (p, " ");
+ if (tmp == NULL) {
+ extensionname = p;
+ extensionattributes = "";
+ } else {
+ extensionname = p;
+ *tmp = '\0';
+ p = tmp + 1;
+ SKIP_SPACES (p);
+ extensionattributes = p;
+ }
+
+ if (extensionname == NULL || *extensionname == '\0') {
+ GST_ERROR ("Invalid extmap '%s'", to_free);
+ goto next;
+ }
+
+ if (*direction != '\0' || *extensionattributes != '\0') {
+ GValue arr = G_VALUE_INIT;
+ GValue val = G_VALUE_INIT;
+ gchar *key;
+
+ key = g_strdup_printf ("extmap-%u", 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_value (&arr, &val);
+
+ g_value_set_string (&val, extensionname);
+ gst_value_array_append_value (&arr, &val);
+
+ g_value_set_string (&val, extensionattributes);
+ gst_value_array_append_value (&arr, &val);
+
+ gst_structure_set_value (s, key, &arr);
+ g_value_unset (&val);
+ g_value_unset (&arr);
+ GST_DEBUG ("adding caps: %s=<%s,%s,%s>", key, direction, extensionname,
+ extensionattributes);
+ g_free (key);
+ } else {
+ gchar *key;
+
+ key = g_strdup_printf ("extmap-%u", id);
+ gst_structure_set (s, key, G_TYPE_STRING, extensionname, NULL);
+ GST_DEBUG ("adding caps: %s=%s", key, extensionname);
+ g_free (key);
+ }
+
+ next:
+ g_free (to_free);
+ }
+ return GST_SDP_OK;
+}
+
/**
* gst_sdp_message_attributes_to_caps:
* @msg: a #GstSDPMessage
res = sdp_add_attributes_to_caps (msg->attributes, caps);
+ if (res == GST_SDP_OK) {
+ /* parse global extmap field */
+ res = gst_sdp_media_add_extmap_attributes (msg->attributes, caps);
+ }
+
done:
if (mikey)
gst_mikey_message_unref (mikey);
res = sdp_add_attributes_to_caps (media->attributes, caps);
+ if (res == GST_SDP_OK) {
+ /* parse media extmap field */
+ res = gst_sdp_media_add_extmap_attributes (media->attributes, caps);
+ }
+
done:
if (mikey)
gst_mikey_message_unref (mikey);
"clock-rate=(int)90000, encoding-name=(string)H264, "
"rtcp-fb-nack=(boolean)true, rtcp-fb-nack-pli=(boolean)true";
+static const gchar * sdp_extmap = "v=0\r\n"
+ "o=- 123456 2 IN IP4 127.0.0.1 \r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=maxptime:60\r\n"
+ "a=sendrecv\r\n"
+ "m=video 1 UDP/TLS/RTP/SAVPF 100 101 102\r\n"
+ "c=IN IP4 1.1.1.1\r\n"
+ "a=rtpmap:100 VP8/90000\r\n"
+ "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n"
+ "a=extmap:3/recvonly http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"
+ "a=extmap:4 urn:3gpp:video-orientation attributes\r\n";
+
+static const gchar caps_video_extmap_pt_100[] =
+ "application/x-unknown, media=(string)video, payload=(int)100, "
+ "clock-rate=(int)90000, encoding-name=(string)VP8, "
+ "extmap-2=urn:ietf:params:rtp-hdrext:toffset, "
+ "extmap-3=(string)<\"recvonly\",\"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\",\"\">, "
+ "extmap-4=(string)<\"\",\"urn:3gpp:video-orientation\",\"attributes\">";
+
/* *INDENT-ON* */
GST_START_TEST (boxed)
gst_sdp_message_free (message);
}
+GST_END_TEST
+GST_START_TEST (caps_from_media_extmap)
+{
+ GstSDPMessage *message;
+ glong length = -1;
+ const GstSDPMedia *media1;
+ GstCaps *caps1;
+ GstCaps *result1;
+
+ gst_sdp_message_new (&message);
+ gst_sdp_message_parse_buffer ((guint8 *) sdp_extmap, length, message);
+
+ media1 = gst_sdp_message_get_media (message, 0);
+ fail_unless (media1 != NULL);
+
+ caps1 = gst_sdp_media_get_caps_from_media (media1, 100);
+ gst_sdp_media_attributes_to_caps (media1, caps1);
+ result1 = gst_caps_from_string (caps_video_extmap_pt_100);
+ fail_unless (gst_caps_is_strictly_equal (caps1, result1));
+
+ gst_caps_unref (result1);
+ gst_caps_unref (caps1);
+
+ gst_sdp_message_free (message);
+}
+
+GST_END_TEST
+GST_START_TEST (media_from_caps_extmap_pt_100)
+{
+ GstSDPResult ret = GST_SDP_OK;
+ GstSDPMessage *message;
+ glong length = -1;
+ GstSDPMedia *media_caps;
+ const GstSDPMedia *media_sdp;
+ GstCaps *caps;
+ const gchar *attr_val_caps1, *attr_val_caps2, *attr_val_caps3;
+ const gchar *attr_val_sdp1, *attr_val_sdp2, *attr_val_sdp3;
+
+ caps = gst_caps_from_string (caps_video_extmap_pt_100);
+
+ gst_sdp_media_new (&media_caps);
+ fail_unless (media_caps != NULL);
+
+ ret = gst_sdp_media_set_media_from_caps (caps, media_caps);
+ fail_unless (ret == GST_SDP_OK);
+ gst_caps_unref (caps);
+
+ gst_sdp_message_new (&message);
+ gst_sdp_message_parse_buffer ((guint8 *) sdp_extmap, length, message);
+
+ media_sdp = gst_sdp_message_get_media (message, 0);
+ fail_unless (media_sdp != NULL);
+
+ attr_val_caps1 = gst_sdp_media_get_attribute_val_n (media_caps, "extmap", 0);
+ attr_val_caps2 = gst_sdp_media_get_attribute_val_n (media_caps, "extmap", 1);
+ attr_val_caps3 = gst_sdp_media_get_attribute_val_n (media_caps, "extmap", 2);
+
+ attr_val_sdp1 = gst_sdp_media_get_attribute_val_n (media_sdp, "extmap", 0);
+ attr_val_sdp2 = gst_sdp_media_get_attribute_val_n (media_sdp, "extmap", 1);
+ attr_val_sdp3 = gst_sdp_media_get_attribute_val_n (media_sdp, "extmap", 2);
+
+ fail_if (g_strcmp0 (attr_val_caps1, attr_val_sdp1) != 0);
+ fail_if (g_strcmp0 (attr_val_caps2, attr_val_sdp2) != 0);
+ fail_if (g_strcmp0 (attr_val_caps3, attr_val_sdp3) != 0);
+
+ gst_sdp_media_free (media_caps);
+ gst_sdp_message_free (message);
+}
+
GST_END_TEST
GST_START_TEST (caps_from_media_really_const)
{
tcase_add_test (tc_chain, media_from_caps);
tcase_add_test (tc_chain, caps_from_media_rtcp_fb);
tcase_add_test (tc_chain, caps_from_media_rtcp_fb_all);
+ tcase_add_test (tc_chain, caps_from_media_extmap);
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);
return s;
}