diff options
| -rw-r--r-- | ChangeLog | 38 | ||||
| -rw-r--r-- | gst/rtsp/gstrtspsrc.c | 587 | ||||
| -rw-r--r-- | gst/rtsp/gstrtspsrc.h | 35 | ||||
| -rw-r--r-- | gst/rtsp/rtspconnection.c | 22 | ||||
| -rw-r--r-- | gst/rtsp/rtspdefs.c | 1 | ||||
| -rw-r--r-- | gst/rtsp/rtspdefs.h | 29 | ||||
| -rw-r--r-- | gst/rtsp/rtspext.h | 3 | ||||
| -rw-r--r-- | gst/rtsp/rtspextwms.c | 60 | ||||
| -rw-r--r-- | gst/rtsp/rtsptransport.c | 43 | ||||
| -rw-r--r-- | gst/rtsp/rtsptransport.h | 13 | 
10 files changed, 590 insertions, 241 deletions
| @@ -1,3 +1,41 @@ +2006-10-06  Wim Taymans  <wim@fluendo.com> + +	* 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. +  2006-10-05  Tim-Philipp Müller  <tim at centricular dot net>  	* ext/cairo/gsttimeoverlay.c: 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 | 
