summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2006-10-06 12:55:53 +0000
committerWim Taymans <wim.taymans@gmail.com>2006-10-06 12:55:53 +0000
commita600d3112001db36e6aee35d2b39903bf0ed9d07 (patch)
tree82f32f101b71cb0ce5c4ca4a4688b24441f963fc /gst
parent751222f5aaa74a456763f1a3b1d488a680620286 (diff)
gst/rtsp/gstrtspsrc.*: Rework how the transport string is constructed, try to share channels and udp ports.
Original commit message from CVS: * gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type), (gst_rtspsrc_class_init), (gst_rtspsrc_init), (gst_rtspsrc_create_stream), (gst_rtspsrc_media_to_caps), (gst_rtspsrc_alloc_udp_ports), (gst_rtspsrc_stream_configure_transport), (find_stream_by_channel), (gst_rtspsrc_push_event), (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_create_transports_string), (gst_rtspsrc_configure_transports), (gst_rtspsrc_open), (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state): * gst/rtsp/gstrtspsrc.h: Rework how the transport string is constructed, try to share channels and udp ports. Make most of the stuff less dependant on RTP as we are also going to use it for RDT. Add support for transport specific session managers. * gst/rtsp/rtspconnection.c: (rtsp_connection_flush): Implement _flush(). * gst/rtsp/rtspdefs.c: (rtsp_strresult): * gst/rtsp/rtspdefs.h: Add generic error return code. * gst/rtsp/rtspext.h: Add support for pluggable tranport strings. * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_before_send), (rtsp_ext_wms_after_send), (rtsp_ext_wms_parse_sdp), (rtsp_ext_wms_get_context): Detect WMServer and activate the extension. * gst/rtsp/rtsptransport.c: (rtsp_transport_get_mime), (rtsp_transport_get_manager), (rtsp_transport_parse): * gst/rtsp/rtsptransport.h: Added methods to get mime/manager for certain transports.
Diffstat (limited to 'gst')
-rw-r--r--gst/rtsp/gstrtspsrc.c587
-rw-r--r--gst/rtsp/gstrtspsrc.h35
-rw-r--r--gst/rtsp/rtspconnection.c22
-rw-r--r--gst/rtsp/rtspdefs.c1
-rw-r--r--gst/rtsp/rtspdefs.h29
-rw-r--r--gst/rtsp/rtspext.h3
-rw-r--r--gst/rtsp/rtspextwms.c60
-rw-r--r--gst/rtsp/rtsptransport.c43
-rw-r--r--gst/rtsp/rtsptransport.h13
9 files changed, 552 insertions, 241 deletions
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
index 0ea88313..70c6aa07 100644
--- a/gst/rtsp/gstrtspsrc.c
+++ b/gst/rtsp/gstrtspsrc.c
@@ -96,6 +96,9 @@
#include "sdp.h"
#include "rtspextwms.h"
+#ifdef WITH_EXT_REAL
+#include "rtspextreal.h"
+#endif
GST_DEBUG_CATEGORY_STATIC (rtspsrc_debug);
#define GST_CAT_DEFAULT (rtspsrc_debug)
@@ -109,11 +112,10 @@ GST_ELEMENT_DETAILS ("RTSP packet receiver",
"Thijs Vermeir <thijs.vermeir@barco.com>\n"
"Lutz Mueller <lutz@topfrose.de>");
-static GstStaticPadTemplate rtptemplate =
-GST_STATIC_PAD_TEMPLATE ("rtp_stream%d",
+static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("stream%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
- GST_STATIC_CAPS ("application/x-rtp"));
+ GST_STATIC_CAPS ("application/x-rtp; application/x-rdt"));
enum
{
@@ -122,7 +124,7 @@ enum
};
#define DEFAULT_LOCATION NULL
-#define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP
+#define DEFAULT_PROTOCOLS RTSP_LOWER_TRANS_UDP | RTSP_LOWER_TRANS_UDP_MCAST | RTSP_LOWER_TRANS_TCP
#define DEFAULT_DEBUG FALSE
#define DEFAULT_RETRY 20
#define DEFAULT_TIMEOUT 5000000
@@ -143,9 +145,9 @@ gst_rtsp_proto_get_type (void)
{
static GType rtsp_proto_type = 0;
static const GFlagsValue rtsp_proto[] = {
- {GST_RTSP_PROTO_UDP_UNICAST, "UDP Unicast Mode", "udp-unicast"},
- {GST_RTSP_PROTO_UDP_MULTICAST, "UDP Multicast Mode", "udp-multicast"},
- {GST_RTSP_PROTO_TCP, "TCP interleaved mode", "tcp"},
+ {RTSP_LOWER_TRANS_UDP, "UDP Unicast Mode", "udp-unicast"},
+ {RTSP_LOWER_TRANS_UDP_MCAST, "UDP Multicast Mode", "udp-multicast"},
+ {RTSP_LOWER_TRANS_TCP, "TCP interleaved mode", "tcp"},
{0, NULL, NULL},
};
@@ -233,9 +235,9 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
DEFAULT_LOCATION, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
- g_param_spec_flags ("protocols", "Protocols", "Allowed protocols",
- GST_TYPE_RTSP_PROTO, DEFAULT_PROTOCOLS,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_param_spec_flags ("protocols", "Protocols",
+ "Allowed lower transport protocols", GST_TYPE_RTSP_PROTO,
+ DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_DEBUG,
g_param_spec_boolean ("debug", "Debug",
@@ -272,6 +274,9 @@ gst_rtspsrc_init (GstRTSPSrc * src, GstRTSPSrcClass * g_class)
/* install WMS extension by default */
src->extension = rtsp_ext_wms_get_context ();
+#ifdef WITH_EXT_REAL
+ src->extension = rtsp_ext_real_get_context ();
+#endif
src->extension->src = (gpointer) src;
}
@@ -414,8 +419,9 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
GST_DEBUG_OBJECT (src, " control: %s", GST_STR_NULL (control_url));
if (control_url != NULL) {
- /* FIXME, what if the control_url starts with a '/' or a non rtsp: protocol? */
- /* check absolute/relative URL */
+ /* If the control_url starts with a '/' or a non rtsp: protocol we will most
+ * likely build a URL that the server will fail to understand, this is ok,
+ * we will fail then. */
if (g_str_has_prefix (control_url, "rtsp://"))
stream->setup_url = g_strdup (control_url);
else if (src->content_base)
@@ -565,7 +571,7 @@ gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media)
goto no_rtpmap;
}
- caps = gst_caps_new_simple ("application/x-rtp",
+ caps = gst_caps_new_simple ("application/x-unknown",
"media", G_TYPE_STRING, media->media, "payload", G_TYPE_INT, pt, NULL);
s = gst_caps_get_structure (caps, 0);
@@ -627,34 +633,34 @@ no_rtpmap:
}
static gboolean
-gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream,
+gst_rtspsrc_alloc_udp_ports (GstRTSPStream * stream,
gint * rtpport, gint * rtcpport)
{
- GstStateChangeReturn ret;
GstRTSPSrc *src;
- GstElement *tmp, *rtpsrc, *rtcpsrc;
+ GstStateChangeReturn ret;
+ GstElement *tmp, *udpsrc0, *udpsrc1;
gint tmp_rtp, tmp_rtcp;
guint count;
src = stream->parent;
tmp = NULL;
- rtpsrc = NULL;
- rtcpsrc = NULL;
+ udpsrc0 = NULL;
+ udpsrc1 = NULL;
count = 0;
/* try to allocate 2 UDP ports, the RTP port should be an even
* number and the RTCP port should be the next (uneven) port */
again:
- rtpsrc = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL);
- if (rtpsrc == NULL)
- goto no_udp_rtp_protocol;
+ udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL);
+ if (udpsrc0 == NULL)
+ goto no_udp_protocol;
- ret = gst_element_set_state (rtpsrc, GST_STATE_PAUSED);
+ ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
if (ret == GST_STATE_CHANGE_FAILURE)
- goto start_rtp_failure;
+ goto start_udp_failure;
- g_object_get (G_OBJECT (rtpsrc), "port", &tmp_rtp, NULL);
+ g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp);
/* check if port is even */
@@ -671,7 +677,7 @@ again:
gst_element_set_state (tmp, GST_STATE_NULL);
gst_object_unref (tmp);
}
- tmp = rtpsrc;
+ tmp = udpsrc0;
GST_DEBUG_OBJECT (src, "retry %d", count);
goto again;
}
@@ -683,50 +689,45 @@ again:
}
/* allocate port+1 for RTCP now */
- rtcpsrc = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
- if (rtcpsrc == NULL)
+ udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
+ if (udpsrc1 == NULL)
goto no_udp_rtcp_protocol;
/* set port */
tmp_rtcp = tmp_rtp + 1;
- g_object_set (G_OBJECT (rtcpsrc), "port", tmp_rtcp, NULL);
+ g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
GST_DEBUG_OBJECT (src, "starting RTCP on port %d", tmp_rtcp);
- ret = gst_element_set_state (rtcpsrc, GST_STATE_PAUSED);
+ ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
/* FIXME, this could fail if the next port is not free, we
* should retry with another port then */
if (ret == GST_STATE_CHANGE_FAILURE)
goto start_rtcp_failure;
/* all fine, do port check */
- g_object_get (G_OBJECT (rtpsrc), "port", rtpport, NULL);
- g_object_get (G_OBJECT (rtcpsrc), "port", rtcpport, NULL);
+ g_object_get (G_OBJECT (udpsrc0), "port", rtpport, NULL);
+ g_object_get (G_OBJECT (udpsrc1), "port", rtcpport, NULL);
/* this should not happen */
if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp)
goto port_error;
- /* configure a timeout */
- g_object_set (G_OBJECT (rtpsrc), "timeout", src->timeout, NULL);
-
- /* we manage these elements, we set the caps in configure_transport */
- stream->rtpsrc = rtpsrc;
- stream->rtcpsrc = rtcpsrc;
-
- gst_bin_add (GST_BIN_CAST (src), stream->rtpsrc);
- gst_bin_add (GST_BIN_CAST (src), stream->rtcpsrc);
+ /* we keep these elements, we configure all in configure_transport when the
+ * server told us to really use the UDP ports. */
+ stream->udpsrc[0] = udpsrc0;
+ stream->udpsrc[1] = udpsrc1;
return TRUE;
/* ERRORS */
-no_udp_rtp_protocol:
+no_udp_protocol:
{
- GST_DEBUG_OBJECT (src, "could not get UDP source for RTP");
+ GST_DEBUG_OBJECT (src, "could not get UDP source");
goto cleanup;
}
-start_rtp_failure:
+start_udp_failure:
{
- GST_DEBUG_OBJECT (src, "could not start UDP source for RTP");
+ GST_DEBUG_OBJECT (src, "could not start UDP source");
goto cleanup;
}
no_ports:
@@ -757,13 +758,13 @@ cleanup:
gst_element_set_state (tmp, GST_STATE_NULL);
gst_object_unref (tmp);
}
- if (rtpsrc) {
- gst_element_set_state (rtpsrc, GST_STATE_NULL);
- gst_object_unref (rtpsrc);
+ if (udpsrc0) {
+ gst_element_set_state (udpsrc0, GST_STATE_NULL);
+ gst_object_unref (udpsrc0);
}
- if (rtcpsrc) {
- gst_element_set_state (rtcpsrc, GST_STATE_NULL);
- gst_object_unref (rtcpsrc);
+ if (udpsrc1) {
+ gst_element_set_state (udpsrc1, GST_STATE_NULL);
+ gst_object_unref (udpsrc1);
}
return FALSE;
}
@@ -774,115 +775,209 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
RTSPTransport * transport)
{
GstRTSPSrc *src;
- GstPad *pad;
+ GstPad *outpad = NULL;
GstPadTemplate *template;
GstStateChangeReturn ret;
gchar *name;
+ GstStructure *s;
+ const gchar *mime, *manager;
+ RTSPResult res;
src = stream->parent;
- GST_DEBUG ("configuring RTP transport for stream %p", stream);
+ GST_DEBUG_OBJECT (src, "configuring transport for stream %p", stream);
+
+ s = gst_caps_get_structure (stream->caps, 0);
+
+ if ((res = rtsp_transport_get_mime (transport->trans, &mime)) < 0)
+ goto no_mime;
+ if (!mime)
+ goto no_mime;
+
+ GST_DEBUG_OBJECT (src, "setting mime to %s", mime);
+ /* configure the final mime type */
+ gst_structure_set_name (s, mime);
+
+ if ((res = rtsp_transport_get_manager (transport->trans, &manager)) < 0)
+ goto no_manager;
- /* FIXME, the session manager needs to be shared with all the streams */
- if (!(stream->rtpdec = gst_element_factory_make ("rtpdec", NULL)))
- goto no_element;
+ if (manager) {
+ GST_DEBUG_OBJECT (src, "using manager %s", manager);
+ /* FIXME, the session manager needs to be shared with all the streams */
+ if (!(stream->sess = gst_element_factory_make (manager, NULL)))
+ goto no_element;
- /* we manage this element */
- gst_bin_add (GST_BIN_CAST (src), stream->rtpdec);
+ /* we manage this element */
+ gst_bin_add (GST_BIN_CAST (src), stream->sess);
- ret = gst_element_set_state (stream->rtpdec, GST_STATE_PAUSED);
- if (ret != GST_STATE_CHANGE_SUCCESS)
- goto start_rtpdec_failure;
+ ret = gst_element_set_state (stream->sess, GST_STATE_PAUSED);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ goto start_session_failure;
- stream->rtpdecrtp = gst_element_get_pad (stream->rtpdec, "sinkrtp");
- stream->rtpdecrtcp = gst_element_get_pad (stream->rtpdec, "sinkrtcp");
+ stream->channelpad[0] = gst_element_get_pad (stream->sess, "sinkrtp");
+ stream->channelpad[1] = gst_element_get_pad (stream->sess, "sinkrtcp");
+ }
if (transport->lower_transport == RTSP_LOWER_TRANS_TCP) {
+ gint i;
+
/* configure for interleaved delivery, nothing needs to be done
* here, the loop function will call the chain functions of the
- * RTP session manager. */
- stream->rtpchannel = transport->interleaved.min;
- stream->rtcpchannel = transport->interleaved.max;
- GST_DEBUG ("stream %p on channels %d-%d", stream,
- stream->rtpchannel, stream->rtcpchannel);
+ * session manager. */
+ stream->channel[0] = transport->interleaved.min;
+ stream->channel[1] = transport->interleaved.max;
+ GST_DEBUG_OBJECT (src, "stream %p on channels %d-%d", stream,
+ stream->channel[0], stream->channel[1]);
+
+ /* we can remove the allocated UDP ports now */
+ for (i = 0; i < 2; i++) {
+ if (stream->udpsrc[i]) {
+ gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
+ gst_object_unref (stream->udpsrc[i]);
+ stream->udpsrc[i] = NULL;
+ }
+ }
+ /* no session manager, send data to srcpad directly */
+ if (!stream->channelpad[0]) {
+ GST_DEBUG_OBJECT (src, "no manager, creating pad");
+
+ name = g_strdup_printf ("stream%d", stream->id);
+ template = gst_static_pad_template_get (&rtptemplate);
+ stream->srcpad = gst_pad_new_from_template (template, name);
+ gst_object_unref (template);
+ g_free (name);
+
+ gst_pad_use_fixed_caps (stream->srcpad);
+ gst_pad_set_caps (stream->srcpad, stream->caps);
+
+ stream->channelpad[0] = gst_object_ref (stream->srcpad);
+ gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+ } else {
+ GST_DEBUG_OBJECT (src, "using manager source pad");
+ outpad = gst_element_get_pad (stream->sess, "srcrtp");
+ }
} else {
/* multicast was selected, create UDP sources and join the multicast
* group. */
if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST) {
gchar *uri;
- /* creating RTP source */
- uri =
- g_strdup_printf ("udp://%s:%d", transport->destination,
- transport->port.min);
- stream->rtpsrc = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
- g_free (uri);
- if (stream->rtpsrc == NULL)
- goto no_element;
-
- /* creating RTCP source */
- uri =
- g_strdup_printf ("udp://%s:%d", transport->destination,
- transport->port.max);
- stream->rtcpsrc = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
- g_free (uri);
- if (stream->rtcpsrc == NULL)
- goto no_element;
-
- /* change state */
- gst_element_set_state (stream->rtpsrc, GST_STATE_PAUSED);
- gst_element_set_state (stream->rtcpsrc, GST_STATE_PAUSED);
-
- /* we manage these elements */
- gst_bin_add (GST_BIN_CAST (src), stream->rtpsrc);
- gst_bin_add (GST_BIN_CAST (src), stream->rtcpsrc);
+ GST_DEBUG_OBJECT (src, "creating UDP sources for multicast");
+
+ /* creating UDP source */
+ if (transport->port.min != -1) {
+ uri = g_strdup_printf ("udp://%s:%d", transport->destination,
+ transport->port.min);
+ stream->udpsrc[0] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ g_free (uri);
+ if (stream->udpsrc[0] == NULL)
+ goto no_element;
+
+ /* change state */
+ gst_element_set_state (stream->udpsrc[0], GST_STATE_PAUSED);
+ }
+
+ /* creating another UDP source */
+ if (transport->port.max != -1) {
+ uri = g_strdup_printf ("udp://%s:%d", transport->destination,
+ transport->port.max);
+ stream->udpsrc[1] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ g_free (uri);
+ if (stream->udpsrc[1] == NULL)
+ goto no_element;
+
+ gst_element_set_state (stream->udpsrc[1], GST_STATE_PAUSED);
+ }
}
- /* set caps */
- g_object_set (G_OBJECT (stream->rtpsrc), "caps", stream->caps, NULL);
+ /* we manage the UDP elements now. For unicast, the UDP sources where
+ * allocated in the stream when we suggested a transport. */
+ if (stream->udpsrc[0]) {
+ GstPad *pad;
- /* configure for UDP delivery, we need to connect the UDP pads to
- * the RTP session plugin. */
- pad = gst_element_get_pad (stream->rtpsrc, "src");
- gst_pad_link (pad, stream->rtpdecrtp);
- gst_object_unref (pad);
+ gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]);
- pad = gst_element_get_pad (stream->rtcpsrc, "src");
- gst_pad_link (pad, stream->rtpdecrtcp);
- gst_object_unref (pad);
- }
+ GST_DEBUG_OBJECT (src, "setting up UDP source");
- pad = gst_element_get_pad (stream->rtpdec, "srcrtp");
- if (stream->caps) {
- gst_pad_use_fixed_caps (pad);
- gst_pad_set_caps (pad, stream->caps);
+ /* set caps */
+ g_object_set (G_OBJECT (stream->udpsrc[0]), "caps", stream->caps, NULL);
+
+ /* configure a timeout on the UDP port */
+ g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->timeout,
+ NULL);
+
+ if (stream->channelpad[0]) {
+ GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager");
+ /* configure for UDP delivery, we need to connect the UDP pads to
+ * the session plugin. */
+ pad = gst_element_get_pad (stream->udpsrc[0], "src");
+ gst_pad_link (pad, stream->channelpad[0]);
+ gst_object_unref (pad);
+
+ outpad = gst_element_get_pad (stream->sess, "srcrtp");
+ } else {
+ GST_DEBUG_OBJECT (src, "using UDP src pad as output");
+ outpad = gst_element_get_pad (stream->udpsrc[0], "src");
+ }
+ }
+
+ if (stream->udpsrc[1]) {
+ gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[1]);
+
+ if (stream->channelpad[1]) {
+ GstPad *pad;
+
+ GST_DEBUG_OBJECT (src, "connecting UDP source 1 to manager");
+
+ pad = gst_element_get_pad (stream->udpsrc[1], "src");
+ gst_pad_link (pad, stream->channelpad[1]);
+ gst_object_unref (pad);
+ }
+ }
}
- /* create ghostpad */
- name = g_strdup_printf ("rtp_stream%d", stream->id);
- template = gst_static_pad_template_get (&rtptemplate);
- stream->srcpad = gst_ghost_pad_new_from_template (name, pad, template);
- gst_object_unref (template);
- g_free (name);
+ if (outpad && !stream->srcpad) {
+ GST_DEBUG_OBJECT (src, "creating ghostpad");
- gst_object_unref (pad);
+ gst_pad_use_fixed_caps (outpad);
+ gst_pad_set_caps (outpad, stream->caps);
+ /* create ghostpad */
+ name = g_strdup_printf ("stream%d", stream->id);
+ template = gst_static_pad_template_get (&rtptemplate);
+ stream->srcpad = gst_ghost_pad_new_from_template (name, outpad, template);
+ gst_object_unref (template);
+ g_free (name);
+
+ gst_object_unref (outpad);
+
+ /* and add */
+ gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+ }
/* mark pad as ok */
stream->last_ret = GST_FLOW_OK;
- /* and add */
- gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
return TRUE;
/* ERRORS */
+no_mime:
+ {
+ GST_DEBUG_OBJECT (src, "unknown transport");
+ return FALSE;
+ }
+no_manager:
+ {
+ GST_DEBUG_OBJECT (src, "cannot get a session manager");
+ return FALSE;
+ }
no_element:
{
GST_DEBUG_OBJECT (src, "no rtpdec element found");
return FALSE;
}
-start_rtpdec_failure:
+start_session_failure:
{
- GST_DEBUG_OBJECT (src, "could not start RTP session");
+ GST_DEBUG_OBJECT (src, "could not start session");
return FALSE;
}
}
@@ -892,7 +987,7 @@ find_stream_by_channel (GstRTSPStream * stream, gconstpointer a)
{
gint channel = GPOINTER_TO_INT (a);
- if (stream->rtpchannel == channel || stream->rtcpchannel == channel)
+ if (stream->channel[0] == channel || stream->channel[1] == channel)
return 0;
return -1;
@@ -944,10 +1039,21 @@ gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event)
if (ostream->srcpad == NULL)
continue;
- gst_event_ref (event);
- gst_pad_push_event (ostream->rtpdecrtp, event);
- gst_event_ref (event);
- gst_pad_push_event (ostream->rtpdecrtcp, event);
+ if (ostream->channelpad[0]) {
+ gst_event_ref (event);
+ if (GST_PAD_IS_SRC (ostream->channelpad[0]))
+ gst_pad_push_event (ostream->channelpad[0], event);
+ else
+ gst_pad_send_event (ostream->channelpad[0], event);
+ }
+
+ if (ostream->channelpad[1]) {
+ gst_event_ref (event);
+ if (GST_PAD_IS_SRC (ostream->channelpad[1]))
+ gst_pad_push_event (ostream->channelpad[1], event);
+ else
+ gst_pad_send_event (ostream->channelpad[1], event);
+ }
}
gst_event_unref (event);
}
@@ -984,11 +1090,11 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
goto unknown_stream;
stream = (GstRTSPStream *) lstream->data;
- if (channel == stream->rtpchannel) {
- outpad = stream->rtpdecrtp;
+ if (channel == stream->channel[0]) {
+ outpad = stream->channelpad[0];
caps = stream->caps;
- } else if (channel == stream->rtcpchannel) {
- outpad = stream->rtpdecrtcp;
+ } else if (channel == stream->channel[1]) {
+ outpad = stream->channelpad[1];
}
/* take a look at the body to figure out what we have */
@@ -999,7 +1105,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
/* channels are not correct on some servers, do extra check */
if (data[1] >= 200 && data[1] <= 204) {
/* hmm RTCP message switch to the RTCP pad of the same stream. */
- outpad = stream->rtpdecrtcp;
+ outpad = stream->channelpad[1];
}
/* we have no clue what this is, just ignore then. */
@@ -1027,7 +1133,10 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
channel);
/* chain to the peer pad */
- ret = gst_pad_chain (outpad, buf);
+ if (GST_PAD_IS_SINK (outpad))
+ ret = gst_pad_chain (outpad, buf);
+ else
+ ret = gst_pad_push (outpad, buf);
/* combine all stream flows */
ret = gst_rtspsrc_combine_flows (src, stream, ret);
@@ -1311,6 +1420,136 @@ no_setup:
}
}
+static RTSPResult
+gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
+ RTSPLowerTrans protocols, gchar ** transports)
+{
+ gchar *result;
+ RTSPResult res;
+
+ *transports = NULL;
+ if (src->extension && src->extension->get_transports)
+ if ((res =
+ src->extension->get_transports (src->extension, protocols,
+ transports)) < 0)
+ goto failed;
+
+ /* extension listed transports, use those */
+ if (*transports != NULL)
+ return RTSP_OK;
+
+ result = g_strdup ("");
+ if (protocols & RTSP_LOWER_TRANS_UDP) {
+ gchar *new;
+
+ GST_DEBUG_OBJECT (src, "adding UDP unicast");
+
+ new =
+ g_strconcat (result, "RTP/AVP/UDP;unicast;client_port=%%u1-%%u2", NULL);
+ g_free (result);
+ result = new;
+ }
+ if (protocols & RTSP_LOWER_TRANS_UDP_MCAST) {
+ gchar *new;
+
+ GST_DEBUG_OBJECT (src, "adding UDP multicast");
+
+ /* we don't have to allocate any UDP ports yet, if the selected transport
+ * turns out to be multicast we can create them and join the multicast
+ * group indicated in the transport reply */
+ new = g_strconcat (result, result[0] ? "," : "",
+ "RTP/AVP/UDP;multicast", NULL);
+ g_free (result);
+ result = new;
+ }
+ if (protocols & RTSP_LOWER_TRANS_TCP) {
+ gchar *new;
+
+ GST_DEBUG_OBJECT (src, "adding TCP");
+
+ new = g_strconcat (result, result[0] ? "," : "",
+ "RTP/AVP/TCP;unicast;interleaved=%%i1-%%i2", NULL);
+ g_free (result);
+ result = new;
+ }
+ *transports = result;
+
+ return RTSP_OK;
+
+ /* ERRORS */
+failed:
+ {
+ return res;
+ }
+}
+
+static RTSPResult
+gst_rtspsrc_configure_transports (GstRTSPStream * stream, gchar ** transports)
+{
+ GstRTSPSrc *src;
+ gint nr_udp, nr_int;
+ gchar *next, *p;
+ gint rtpport = 0, rtcpport = 0;
+ GString *str;
+
+ src = stream->parent;
+
+ /* find number of placeholders first */
+ if (strstr (*transports, "%%i2"))
+ nr_int = 2;
+ else if (strstr (*transports, "%%i1"))
+ nr_int = 1;
+ else
+ nr_int = 0;
+
+ if (strstr (*transports, "%%u2"))
+ nr_udp = 2;
+ else if (strstr (*transports, "%%u1"))
+ nr_udp = 1;
+ else
+ nr_udp = 0;
+
+ if (nr_udp == 0 && nr_int == 0)
+ goto done;
+
+ if (nr_udp > 0) {
+ if (!gst_rtspsrc_alloc_udp_ports (stream, &rtpport, &rtcpport))
+ goto failed;
+ }
+
+ str = g_string_new ("");
+ p = *transports;
+ while ((next = strstr (p, "%%"))) {
+ g_string_append_len (str, p, next - p);
+ if (next[2] == 'u') {
+ if (next[3] == '1')
+ g_string_append_printf (str, "%d", rtpport);
+ else if (next[3] == '2')
+ g_string_append_printf (str, "%d", rtcpport);
+ }
+ if (next[2] == 'i') {
+ if (next[3] == '1')
+ g_string_append_printf (str, "%d", src->free_channel);
+ else if (next[3] == '2')
+ g_string_append_printf (str, "%d", src->free_channel + 1);
+ }
+
+ p = next + 4;
+ }
+
+ g_free (*transports);
+ *transports = g_string_free (str, FALSE);
+
+done:
+ return RTSP_OK;
+
+ /* ERRORS */
+failed:
+ {
+ return RTSP_ERROR;
+ }
+}
+
static gboolean
gst_rtspsrc_open (GstRTSPSrc * src)
{
@@ -1321,7 +1560,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
guint size;
gint i, n_streams;
SDPMessage sdp = { 0 };
- GstRTSPProto protocols;
+ RTSPLowerTrans protocols;
GstRTSPStream *stream = NULL;
gchar *respcont = NULL;
@@ -1396,8 +1635,8 @@ gst_rtspsrc_open (GstRTSPSrc * src)
if (src->extension && src->extension->parse_sdp)
src->extension->parse_sdp (src->extension, &sdp);
- /* we initially allow all configured protocols. based on the replies from the
- * server we narrow them down. */
+ /* we initially allow all configured lower transports. based on the
+ * replies from the server we narrow them down. */
protocols = src->protocols;
/* setup streams */
@@ -1440,54 +1679,15 @@ gst_rtspsrc_open (GstRTSPSrc * src)
if (res < 0)
goto create_request_failed;
- transports = g_strdup ("");
- if (protocols & GST_RTSP_PROTO_UDP_UNICAST) {
- gchar *new;
- gint rtpport, rtcpport;
- gchar *trxparams;
-
- /* allocate two UDP ports */
- if (!gst_rtspsrc_stream_setup_rtp (stream, &rtpport, &rtcpport))
- goto setup_rtp_failed;
-
- GST_DEBUG_OBJECT (src, "setting up RTP ports %d-%d", rtpport, rtcpport);
+ /* create a string with all the transports */
+ res = gst_rtspsrc_create_transports_string (src, protocols, &transports);
+ if (res < 0)
+ goto setup_transport_failed;
- trxparams = g_strdup_printf ("client_port=%d-%d", rtpport, rtcpport);
- new = g_strconcat (transports, "RTP/AVP/UDP;unicast;", trxparams, NULL);
- g_free (trxparams);
- g_free (transports);
- transports = new;
- }
- if (protocols & GST_RTSP_PROTO_UDP_MULTICAST) {
- gchar *new;
-
- GST_DEBUG_OBJECT (src, "setting up MULTICAST");
-
- /* we don't hav to allocate any UDP ports yet, if the selected transport
- * turns out to be multicast we can create them and join the multicast
- * group indicated in the transport reply */
- new =
- g_strconcat (transports, transports[0] ? "," : "",
- "RTP/AVP/UDP;multicast", NULL);
- g_free (transports);
- transports = new;
- }
- if (protocols & GST_RTSP_PROTO_TCP) {
- gchar *new, *interleaved;
- gint channel;
-
- GST_DEBUG_OBJECT (src, "setting up TCP");
-
- /* the channels for this stream is by default the next available number */
- channel = i * 2;
- interleaved = g_strdup_printf ("interleaved=%d-%d", channel, channel + 1);
- new =
- g_strconcat (transports, transports[0] ? "," : "",
- "RTP/AVP/TCP;unicast;", interleaved, NULL);
- g_free (interleaved);
- g_free (transports);
- transports = new;
- }
+ /* replace placeholders with real values */
+ res = gst_rtspsrc_configure_transports (stream, &transports);
+ if (res < 0)
+ goto setup_transport_failed;
/* select transport, copy is made when adding to header */
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
@@ -1506,7 +1706,8 @@ gst_rtspsrc_open (GstRTSPSrc * src)
goto no_transport;
/* parse transport */
- rtsp_transport_parse (resptrans, &transport);
+ if (rtsp_transport_parse (resptrans, &transport) != RTSP_OK)
+ continue;
/* update allowed transports for other streams. once the transport of
* one stream has been determined, we make sure that all other streams
@@ -1514,18 +1715,24 @@ gst_rtspsrc_open (GstRTSPSrc * src)
switch (transport.lower_transport) {
case RTSP_LOWER_TRANS_TCP:
GST_DEBUG_OBJECT (src, "stream %d as TCP interleaved", i);
- protocols = GST_RTSP_PROTO_TCP;
+ protocols = RTSP_LOWER_TRANS_TCP;
src->interleaved = TRUE;
+ /* update free channels */
+ src->free_channel =
+ MAX (transport.interleaved.min, src->free_channel);
+ src->free_channel =
+ MAX (transport.interleaved.max, src->free_channel);
+ src->free_channel++;
break;
case RTSP_LOWER_TRANS_UDP_MCAST:
/* only allow multicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as UDP multicast", i);
- protocols = GST_RTSP_PROTO_UDP_MULTICAST;
+ protocols = RTSP_LOWER_TRANS_UDP_MCAST;
break;
case RTSP_LOWER_TRANS_UDP:
/* only allow unicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as UDP unicast", i);
- protocols = GST_RTSP_PROTO_UDP_UNICAST;
+ protocols = RTSP_LOWER_TRANS_UDP;
break;
default:
GST_DEBUG_OBJECT (src, "stream %d unknown transport %d", i,
@@ -1612,10 +1819,10 @@ wrong_content_type:
("Server does not support SDP, got %s.", respcont));
goto cleanup_error;
}
-setup_rtp_failed:
+setup_transport_failed:
{
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
- ("Could not setup rtp."));
+ ("Could not setup transport."));
goto cleanup_error;
}
no_transport:
@@ -1843,7 +2050,8 @@ gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message)
GST_DEBUG_OBJECT (bin, "timeout on UDP port");
gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_RECONNECT);
/* FIXME, we post an error message now to inform the user
- * that nothing happened. It's most likely a firewall thing. */
+ * that nothing happened. It's most likely a firewall thing. Ideally we
+ * notify the thread and redo the setup with only TCP. */
GST_ELEMENT_ERROR (rtspsrc, RESOURCE, READ, (NULL),
("Could not receive any UDP packets for %.4f seconds, maybe your "
"firewall is blocking it.",
@@ -1870,14 +2078,21 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
+ /* the first free channel for interleaved mode */
+ rtspsrc->free_channel = 0;
rtspsrc->interleaved = FALSE;
gst_segment_init (&rtspsrc->segment, GST_FORMAT_TIME);
if (!gst_rtspsrc_open (rtspsrc))
goto open_failed;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ rtsp_connection_flush (rtspsrc->connection, FALSE);
gst_rtspsrc_play (rtspsrc);
break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ rtsp_connection_flush (rtspsrc->connection, TRUE);
+ break;
default:
break;
}
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
index 8a9c74fe..94b9ed3d 100644
--- a/gst/rtsp/gstrtspsrc.h
+++ b/gst/rtsp/gstrtspsrc.h
@@ -72,21 +72,6 @@ typedef struct _GstRTSPSrcClass GstRTSPSrcClass;
#define GST_RTSP_LOOP_WAIT(rtsp) (g_cond_wait(GST_RTSP_LOOP_GET_COND (rtsp), GST_OBJECT_GET_LOCK (rtsp)))
#define GST_RTSP_LOOP_SIGNAL(rtsp) (g_cond_signal(GST_RTSP_LOOP_GET_COND (rtsp)))
-/**
- * GstRTSPProto:
- * @GST_RTSP_PROTO_UDP_UNICAST: Use unicast UDP transfer.
- * @GST_RTSP_PROTO_UDP_MULTICAST: Use multicast UDP transfer
- * @GST_RTSP_PROTO_TCP: Use TCP transfer.
- *
- * Flags with allowed protocols for the datatransfer.
- */
-typedef enum
-{
- GST_RTSP_PROTO_UDP_UNICAST = (1 << 0),
- GST_RTSP_PROTO_UDP_MULTICAST = (1 << 1),
- GST_RTSP_PROTO_TCP = (1 << 2),
-} GstRTSPProto;
-
typedef struct _GstRTSPStream GstRTSPStream;
struct _GstRTSPStream {
@@ -99,21 +84,18 @@ struct _GstRTSPStream {
GstFlowReturn last_ret;
/* for interleaved mode */
- gint rtpchannel;
- gint rtcpchannel;
+ gint channel[2];
GstCaps *caps;
+ GstPad *channelpad[2];
- /* our udp sources for RTP */
- GstElement *rtpsrc;
- GstElement *rtcpsrc;
+ /* our udp sources */
+ GstElement *udpsrc[2];
/* our udp sink back to the server */
- GstElement *rtcpsink;
+ GstElement *udpsink;
- /* the RTP decoder */
- GstElement *rtpdec;
- GstPad *rtpdecrtp;
- GstPad *rtpdecrtcp;
+ /* the session manager */
+ GstElement *sess;
/* state */
gint pt;
@@ -132,6 +114,7 @@ struct _GstRTSPSrc {
GStaticRecMutex *stream_rec_lock;
GstSegment segment;
gboolean running;
+ gint free_channel;
/* cond to signal loop */
GCond *loop_cond;
@@ -144,7 +127,7 @@ struct _GstRTSPSrc {
gchar *location;
RTSPUrl *url;
gchar *content_base;
- GstRTSPProto protocols;
+ RTSPLowerTrans protocols;
gboolean debug;
guint retry;
guint64 timeout;
diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c
index e939a55d..27cc3ebb 100644
--- a/gst/rtsp/rtspconnection.c
+++ b/gst/rtsp/rtspconnection.c
@@ -753,3 +753,25 @@ rtsp_connection_free (RTSPConnection * conn)
return RTSP_OK;
}
+
+RTSPResult
+rtsp_connection_flush (RTSPConnection * conn, gboolean flush)
+{
+ g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
+
+ if (flush) {
+ SEND_COMMAND (conn, CONTROL_STOP);
+ } else {
+ while (TRUE) {
+ gchar command;
+ int res;
+
+ READ_COMMAND (conn, command, res);
+ if (res <= 0) {
+ /* no more commands */
+ break;
+ }
+ }
+ }
+ return RTSP_OK;
+}
diff --git a/gst/rtsp/rtspdefs.c b/gst/rtsp/rtspdefs.c
index 706e5aad..0138d792 100644
--- a/gst/rtsp/rtspdefs.c
+++ b/gst/rtsp/rtspdefs.c
@@ -51,6 +51,7 @@ extern int h_errno;
static const gchar *rtsp_results[] = {
"OK",
/* errors */
+ "Generic error",
"Invalid parameter specified",
"Operation interrupted",
"Out of memory",
diff --git a/gst/rtsp/rtspdefs.h b/gst/rtsp/rtspdefs.h
index 4067488c..229fc42a 100644
--- a/gst/rtsp/rtspdefs.h
+++ b/gst/rtsp/rtspdefs.h
@@ -53,20 +53,21 @@ if (G_UNLIKELY ((res = (stmt)) != RTSP_OK)) goto label
typedef enum {
RTSP_OK = 0,
/* errors */
- RTSP_EINVAL = -1,
- RTSP_EINTR = -2,
- RTSP_ENOMEM = -3,
- RTSP_ERESOLV = -4,
- RTSP_ENOTIMPL = -5,
- RTSP_ESYS = -6,
- RTSP_EPARSE = -7,
- RTSP_EWSASTART = -8,
- RTSP_EWSAVERSION = -9,
- RTSP_EEOF = -10,
- RTSP_ENET = -11,
- RTSP_ENOTIP = -12,
-
- RTSP_ELAST = -13,
+ RTSP_ERROR = -1,
+ RTSP_EINVAL = -2,
+ RTSP_EINTR = -3,
+ RTSP_ENOMEM = -4,
+ RTSP_ERESOLV = -5,
+ RTSP_ENOTIMPL = -6,
+ RTSP_ESYS = -7,
+ RTSP_EPARSE = -8,
+ RTSP_EWSASTART = -9,
+ RTSP_EWSAVERSION = -10,
+ RTSP_EEOF = -11,
+ RTSP_ENET = -12,
+ RTSP_ENOTIP = -13,
+
+ RTSP_ELAST = -14,
} RTSPResult;
typedef enum {
diff --git a/gst/rtsp/rtspext.h b/gst/rtsp/rtspext.h
index 779c109b..3f41f310 100644
--- a/gst/rtsp/rtspext.h
+++ b/gst/rtsp/rtspext.h
@@ -45,6 +45,7 @@
#include <glib.h>
+#include "rtsptransport.h"
#include "sdp.h"
G_BEGIN_DECLS
@@ -65,6 +66,8 @@ struct _RTSPExtensionCtx
RTSPResult (*parse_sdp) (RTSPExtensionCtx *ctx, SDPMessage *sdp);
RTSPResult (*setup_media) (RTSPExtensionCtx *ctx, SDPMedia *media);
+ RTSPResult (*get_transports) (RTSPExtensionCtx *ctx, RTSPLowerTrans protocols, gchar **transport);
+
RTSPResult (*stream_select) (RTSPExtensionCtx *ctx);
};
diff --git a/gst/rtsp/rtspextwms.c b/gst/rtsp/rtspextwms.c
index 3769fcdb..81964e1e 100644
--- a/gst/rtsp/rtspextwms.c
+++ b/gst/rtsp/rtspextwms.c
@@ -45,22 +45,72 @@
#include "gstrtspsrc.h"
#include "rtspextwms.h"
+#define SERVER_PREFIX "WMServer/"
+#define HEADER_PREFIX "data:application/vnd.ms.wms-hdr.asfv1;base64,"
+
typedef struct _RTSPExtWMSCtx RTSPExtWMSCtx;
struct _RTSPExtWMSCtx
{
RTSPExtensionCtx ctx;
+
+ gboolean active;
};
-#define HEADER_PREFIX "data:application/vnd.ms.wms-hdr.asfv1;base64,"
+static RTSPResult
+rtsp_ext_wms_before_send (RTSPExtensionCtx * ctx, RTSPMessage * request)
+{
+ RTSPExtWMSCtx *rext = (RTSPExtWMSCtx *) ctx;
+
+ switch (request->type_data.request.method) {
+ case RTSP_OPTIONS:
+ {
+ /* activate ourselves with the first request */
+ rext->active = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ return RTSP_OK;
+}
+
+static RTSPResult
+rtsp_ext_wms_after_send (RTSPExtensionCtx * ctx, RTSPMessage * req,
+ RTSPMessage * resp)
+{
+ RTSPExtWMSCtx *rext = (RTSPExtWMSCtx *) ctx;
+
+ switch (req->type_data.request.method) {
+ case RTSP_OPTIONS:
+ {
+ gchar *server = NULL;
+
+ rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server);
+ if (g_str_has_prefix (server, SERVER_PREFIX))
+ rext->active = TRUE;
+ else
+ rext->active = FALSE;
+ break;
+ }
+ default:
+ break;
+ }
+ return RTSP_OK;
+}
+
static RTSPResult
rtsp_ext_wms_parse_sdp (RTSPExtensionCtx * ctx, SDPMessage * sdp)
{
GstRTSPSrc *src = (GstRTSPSrc *) ctx->src;
+ RTSPExtWMSCtx *rext = (RTSPExtWMSCtx *) ctx;
gchar *config, *maxps;
gint i;
+ if (!rext->active)
+ return RTSP_OK;
+
for (i = 0; (config = sdp_message_get_attribute_val_n (sdp, "pgmpu", i)); i++) {
if (g_str_has_prefix (config, HEADER_PREFIX)) {
config += strlen (HEADER_PREFIX);
@@ -86,9 +136,9 @@ rtsp_ext_wms_parse_sdp (RTSPExtensionCtx * ctx, SDPMessage * sdp)
/* ERRORS */
no_config:
{
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Could not find config SDP field."));
- return RTSP_ENOTIMPL;
+ GST_DEBUG_OBJECT (src, "Could not find config SDP field, deactivating.");
+ rext->active = FALSE;
+ return RTSP_OK;
}
}
@@ -99,6 +149,8 @@ rtsp_ext_wms_get_context (void)
res = g_new0 (RTSPExtWMSCtx, 1);
res->ctx.parse_sdp = rtsp_ext_wms_parse_sdp;
+ res->ctx.before_send = rtsp_ext_wms_before_send;
+ res->ctx.after_send = rtsp_ext_wms_after_send;
return (RTSPExtensionCtx *) res;
}
diff --git a/gst/rtsp/rtsptransport.c b/gst/rtsp/rtsptransport.c
index f9848c48..e833080a 100644
--- a/gst/rtsp/rtsptransport.c
+++ b/gst/rtsp/rtsptransport.c
@@ -50,13 +50,14 @@ typedef struct
const gchar *name;
const RTSPTransMode mode;
const gchar *gst_mime;
+ const gchar *manager;
} RTSPTransMap;
static const RTSPTransMap transports[] = {
- {"rtp", RTSP_TRANS_RTP, "application/x-rtp"},
- {"x-real-rdt", RTSP_TRANS_RDT, "application/x-rdt"},
- {"x-pn-tng", RTSP_TRANS_RDT, "application/x-rdt"},
- {NULL, RTSP_TRANS_UNKNOWN, "application/x-unknown"}
+ {"rtp", RTSP_TRANS_RTP, "application/x-rtp", "rtpdec"},
+ {"x-real-rdt", RTSP_TRANS_RDT, "application/x-rdt", NULL},
+ {"x-pn-tng", RTSP_TRANS_RDT, "application/x-rdt", NULL},
+ {NULL, RTSP_TRANS_UNKNOWN, NULL, NULL}
};
typedef struct
@@ -118,6 +119,36 @@ rtsp_transport_init (RTSPTransport * transport)
return RTSP_OK;
}
+RTSPResult
+rtsp_transport_get_mime (RTSPTransMode trans, const gchar ** mime)
+{
+ gint i;
+
+ g_return_val_if_fail (mime != NULL, RTSP_EINVAL);
+
+ for (i = 0; transports[i].name; i++)
+ if (transports[i].mode == trans)
+ break;
+ *mime = transports[i].gst_mime;
+
+ return RTSP_OK;
+}
+
+RTSPResult
+rtsp_transport_get_manager (RTSPTransMode trans, const gchar ** manager)
+{
+ gint i;
+
+ g_return_val_if_fail (manager != NULL, RTSP_EINVAL);
+
+ for (i = 0; transports[i].name; i++)
+ if (transports[i].mode == trans)
+ break;
+ *manager = transports[i].manager;
+
+ return RTSP_OK;
+}
+
static void
parse_mode (RTSPTransport * transport, gchar * str)
{
@@ -163,11 +194,11 @@ rtsp_transport_parse (const gchar * str, RTSPTransport * transport)
if (strstr (split[0], transports[i].name))
break;
transport->trans = transports[i].mode;
- for (i = 1; profiles[i].name; i++)
+ for (i = 0; profiles[i].name; i++)
if (strstr (split[0], profiles[i].name))
break;
transport->profile = profiles[i].profile;
- for (i = 1; ltrans[i].name; i++)
+ for (i = 0; ltrans[i].name; i++)
if (strstr (split[0], ltrans[i].name))
break;
transport->lower_transport = ltrans[i].ltrans;
diff --git a/gst/rtsp/rtsptransport.h b/gst/rtsp/rtsptransport.h
index 32a347b7..84c0996e 100644
--- a/gst/rtsp/rtsptransport.h
+++ b/gst/rtsp/rtsptransport.h
@@ -85,7 +85,7 @@ typedef struct _RTSPTransport {
gboolean append;
RTSPRange interleaved;
- /* mulitcast specific */
+ /* multicast specific */
gint ttl;
/* UDP specific */
@@ -97,12 +97,15 @@ typedef struct _RTSPTransport {
} RTSPTransport;
-RTSPResult rtsp_transport_new (RTSPTransport **transport);
-RTSPResult rtsp_transport_init (RTSPTransport *transport);
+RTSPResult rtsp_transport_new (RTSPTransport **transport);
+RTSPResult rtsp_transport_init (RTSPTransport *transport);
-RTSPResult rtsp_transport_parse (const gchar *str, RTSPTransport *transport);
+RTSPResult rtsp_transport_parse (const gchar *str, RTSPTransport *transport);
-RTSPResult rtsp_transport_free (RTSPTransport *transport);
+RTSPResult rtsp_transport_get_mime (RTSPTransMode trans, const gchar **mime);
+RTSPResult rtsp_transport_get_manager (RTSPTransMode trans, const gchar **manager);
+
+RTSPResult rtsp_transport_free (RTSPTransport *transport);
G_END_DECLS