From 7484c92dfeb05c4bd1f5b0c8dac1ca68e2f7950f Mon Sep 17 00:00:00 2001 From: Thijs Vermeir Date: Mon, 18 Sep 2006 08:59:17 +0000 Subject: [PATCH] gst/rtsp/: Small cleanups. when multicast is selected as the transport, create UDP sources and connect to the multica... Original commit message from CVS: Based on patch by: Thijs Vermeir * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_state), (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause): * gst/rtsp/rtspconnection.c: (inet_aton): Small cleanups. when multicast is selected as the transport, create UDP sources and connect to the multicast group. Move parsing and setting of caps to a common place. Fixes #349894. --- ChangeLog | 17 +++- gst/rtsp/gstrtspsrc.c | 193 ++++++++++++++++++++++---------------- gst/rtsp/rtspconnection.c | 6 +- 3 files changed, 131 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4be3db1d94..c76ee83d9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-09-18 Wim Taymans + + Based on patch by: Thijs Vermeir + + * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_state), + (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp), + (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_open), + (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause): + * gst/rtsp/rtspconnection.c: (inet_aton): + Small cleanups. + when multicast is selected as the transport, create UDP sources and + connect to the multicast group. + Move parsing and setting of caps to a common place. + Fixes #349894. + 2006-09-17 Stefan Kost * ext/flac/gstflactag.c: @@ -20,7 +35,7 @@ * gst/videofilter/gstvideotemplate.c: * gst/videomixer/videomixer.c: * sys/sunaudio/gstsunaudiosrc.h: - More G_OBJECT macro fixing. + More G_OBJECT macro fixing. 2006-09-16 Wim Taymans diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index a24b26be7e..6aaa7c755b 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -35,7 +35,7 @@ * rtspsrc currently understands SDP as the format of the session description. * For each stream listed in the SDP a new rtp_stream%d pad will be created * with caps derived from the SDP media description. This is a caps of mime type - * "application/x-rtp" that can be connected to any available rtp depayloader + * "application/x-rtp" that can be connected to any available RTP depayloader * element. * * @@ -53,7 +53,7 @@ * * gst-launch rtspsrc location=rtsp://some.server/url ! fakesink * - * Establish a connection to an RTSP server and send the stream to a fakesink. + * Establish a connection to an RTSP server and send the raw RTP packets to a fakesink. * * * @@ -370,26 +370,22 @@ gst_rtspsrc_set_state (GstRTSPSrc * src, GstState state) stream = (GstRTSPStream *) streams->data; - /* first our rtp session manager */ + /* first our RTP session manager */ if (stream->rtpdec) { - if ((ret = - gst_element_set_state (stream->rtpdec, - state)) == GST_STATE_CHANGE_FAILURE) + ret = gst_element_set_state (stream->rtpdec, state); + if (ret == GST_STATE_CHANGE_FAILURE) goto done; } /* then our sources */ if (stream->rtpsrc) { - if ((ret = - gst_element_set_state (stream->rtpsrc, - state)) == GST_STATE_CHANGE_FAILURE) + ret = gst_element_set_state (stream->rtpsrc, state); + if (ret == GST_STATE_CHANGE_FAILURE) goto done; } - if (stream->rtcpsrc) { - if ((ret = - gst_element_set_state (stream->rtcpsrc, - state)) == GST_STATE_CHANGE_FAILURE) + ret = gst_element_set_state (stream->rtcpsrc, state); + if (ret == GST_STATE_CHANGE_FAILURE) goto done; } } @@ -469,7 +465,7 @@ gst_rtspsrc_parse_rtpmap (gchar * rtpmap, gint * payload, gchar ** name, /* * Mapping of caps to and from SDP fields: * - * m= RTP/AVP + * m= RTP/AVP * a=rtpmap: /[/] * a=fmtp: [=];... */ @@ -493,14 +489,14 @@ gst_rtspsrc_media_to_caps (SDPMedia * media) } pt = atoi (payload); + /* dynamic payloads need rtpmap */ if (pt >= 96) { gint payload = 0; gboolean ret; if ((rtpmap = sdp_media_get_attribute_val (media, "rtpmap"))) { - if ((ret = - gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, - ¶ms))) { + ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms); + if (ret) { if (payload != pt) { g_warning ("rtpmap of wrong payload type"); name = NULL; @@ -511,7 +507,7 @@ gst_rtspsrc_media_to_caps (SDPMedia * media) g_warning ("error parsing rtpmap"); } } else { - g_warning ("rtpmap type not given fot dynamic payload %d", pt); + g_warning ("rtpmap type not given for dynamic payload %d", pt); return NULL; } } @@ -576,30 +572,29 @@ gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream, SDPMedia * media, { GstStateChangeReturn ret; GstRTSPSrc *src; - GstCaps *caps; - GstElement *tmp, *rtp, *rtcp; + GstElement *tmp, *rtpsrc, *rtcpsrc; gint tmp_rtp, tmp_rtcp; guint count; src = stream->parent; tmp = NULL; - rtp = NULL; - rtcp = NULL; + rtpsrc = NULL; + rtcpsrc = NULL; count = 0; - /* try to allocate 2 udp ports, the RTP port should be an even + /* 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: - rtp = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL); - if (rtp == NULL) + rtpsrc = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL); + if (rtpsrc == NULL) goto no_udp_rtp_protocol; - ret = gst_element_set_state (rtp, GST_STATE_PAUSED); + ret = gst_element_set_state (rtpsrc, GST_STATE_PAUSED); if (ret == GST_STATE_CHANGE_FAILURE) goto start_rtp_failure; - g_object_get (G_OBJECT (rtp), "port", &tmp_rtp, NULL); + g_object_get (G_OBJECT (rtpsrc), "port", &tmp_rtp, NULL); GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp); /* check if port is even */ @@ -616,7 +611,7 @@ again: gst_element_set_state (tmp, GST_STATE_NULL); gst_object_unref (tmp); } - tmp = rtp; + tmp = rtpsrc; GST_DEBUG_OBJECT (src, "retry %d", count); goto again; } @@ -628,40 +623,35 @@ again: } /* allocate port+1 for RTCP now */ - rtcp = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); - if (rtcp == NULL) + rtcpsrc = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + if (rtcpsrc == NULL) goto no_udp_rtcp_protocol; /* set port */ tmp_rtcp = tmp_rtp + 1; - g_object_set (G_OBJECT (rtcp), "port", tmp_rtcp, NULL); + g_object_set (G_OBJECT (rtcpsrc), "port", tmp_rtcp, NULL); GST_DEBUG_OBJECT (src, "starting RTCP on port %d", tmp_rtcp); - ret = gst_element_set_state (rtcp, GST_STATE_PAUSED); + ret = gst_element_set_state (rtcpsrc, 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 (rtp), "port", rtpport, NULL); - g_object_get (G_OBJECT (rtcp), "port", rtcpport, NULL); + g_object_get (G_OBJECT (rtpsrc), "port", rtpport, NULL); + g_object_get (G_OBJECT (rtcpsrc), "port", rtcpport, NULL); /* this should not happen */ if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp) goto port_error; - /* we manage these elements */ - stream->rtpsrc = rtp; + /* we manage these elements, we set the caps in configure_transport */ + stream->rtpsrc = rtpsrc; gst_rtspsrc_add_element (src, stream->rtpsrc); - stream->rtcpsrc = rtcp; + stream->rtcpsrc = rtcpsrc; gst_rtspsrc_add_element (src, stream->rtcpsrc); - caps = gst_rtspsrc_media_to_caps (media); - - /* set caps */ - g_object_set (G_OBJECT (stream->rtpsrc), "caps", caps, NULL); - return TRUE; /* ERRORS */ @@ -703,13 +693,13 @@ cleanup: gst_element_set_state (tmp, GST_STATE_NULL); gst_object_unref (tmp); } - if (rtp) { - gst_element_set_state (rtp, GST_STATE_NULL); - gst_object_unref (rtp); + if (rtpsrc) { + gst_element_set_state (rtpsrc, GST_STATE_NULL); + gst_object_unref (rtpsrc); } - if (rtcp) { - gst_element_set_state (rtcp, GST_STATE_NULL); - gst_object_unref (rtcp); + if (rtcpsrc) { + gst_element_set_state (rtcpsrc, GST_STATE_NULL); + gst_object_unref (rtcpsrc); } return FALSE; } @@ -734,9 +724,8 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream, /* we manage this element */ gst_rtspsrc_add_element (src, stream->rtpdec); - if ((ret = - gst_element_set_state (stream->rtpdec, - GST_STATE_PAUSED)) != GST_STATE_CHANGE_SUCCESS) + ret = gst_element_set_state (stream->rtpdec, GST_STATE_PAUSED); + if (ret != GST_STATE_CHANGE_SUCCESS) goto start_rtpdec_failure; stream->rtpdecrtp = gst_element_get_pad (stream->rtpdec, "sinkrtp"); @@ -745,17 +734,55 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream, if (transport->lower_transport == RTSP_LOWER_TRANS_TCP) { /* configure for interleaved delivery, nothing needs to be done * here, the loop function will call the chain functions of the - * rtp session manager. */ + * 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); - /* also store the caps in the stream */ + /* also store the caps in the stream, we need this when setting caps on + * outgoing buffers */ stream->caps = gst_rtspsrc_media_to_caps (media); } else { - /* configure for UDP delivery, we need to connect the udp pads to - * the rtp session plugin. */ + /* multicast was selected, create UDP sources and connect to the multicast + * group. */ + if (transport->multicast) { + 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_rtspsrc_add_element (src, stream->rtpsrc); + gst_rtspsrc_add_element (src, stream->rtcpsrc); + } + + /* configure caps on the RTP source element */ + stream->caps = gst_rtspsrc_media_to_caps (media); + g_object_set (G_OBJECT (stream->rtpsrc), "caps", stream->caps, NULL); + + /* 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); @@ -1008,9 +1035,8 @@ gst_rtspsrc_open (GstRTSPSrc * src) /* create OPTIONS */ GST_DEBUG_OBJECT (src, "create options..."); - if ((res = - rtsp_message_init_request (RTSP_OPTIONS, src->location, - &request)) < 0) + res = rtsp_message_init_request (RTSP_OPTIONS, src->location, &request); + if (res < 0) goto create_request_failed; /* send OPTIONS */ @@ -1067,11 +1093,11 @@ gst_rtspsrc_open (GstRTSPSrc * src) /* create DESCRIBE */ GST_DEBUG_OBJECT (src, "create describe..."); - if ((res = - rtsp_message_init_request (RTSP_DESCRIBE, src->location, - &request)) < 0) + res = rtsp_message_init_request (RTSP_DESCRIBE, src->location, &request); + if (res < 0) goto create_request_failed; - /* we accept SDP for now */ + + /* we only accept SDP for now */ rtsp_message_add_header (&request, RTSP_HDR_ACCEPT, "application/sdp"); /* send DESCRIBE */ @@ -1092,7 +1118,7 @@ gst_rtspsrc_open (GstRTSPSrc * src) } } - /* parse SDP */ + /* get message body and parse as SDP */ rtsp_message_get_body (&response, &data, &size); GST_DEBUG_OBJECT (src, "parse sdp..."); @@ -1102,8 +1128,10 @@ gst_rtspsrc_open (GstRTSPSrc * src) if (src->debug) sdp_message_dump (&sdp); - /* we allow all configured protocols */ + /* we initially allow all configured protocols. based on the replies from the + * server we narrow them down. */ protocols = src->protocols; + /* setup streams */ { gint i; @@ -1135,14 +1163,12 @@ gst_rtspsrc_open (GstRTSPSrc * src) } GST_DEBUG_OBJECT (src, "setup %s", setup_url); + /* create SETUP request */ - if ((res = - rtsp_message_init_request (RTSP_SETUP, setup_url, - &request)) < 0) { - g_free (setup_url); - goto create_request_failed; - } + res = rtsp_message_init_request (RTSP_SETUP, setup_url, &request); g_free (setup_url); + if (res < 0) + goto create_request_failed; transports = g_strdup (""); if (protocols & GST_RTSP_PROTO_UDP_UNICAST) { @@ -1150,7 +1176,7 @@ gst_rtspsrc_open (GstRTSPSrc * src) gint rtpport, rtcpport; gchar *trxparams; - /* allocate two udp ports */ + /* allocate two UDP ports */ if (!gst_rtspsrc_stream_setup_rtp (stream, media, &rtpport, &rtcpport)) goto setup_rtp_failed; @@ -1167,6 +1193,9 @@ gst_rtspsrc_open (GstRTSPSrc * src) 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); @@ -1203,18 +1232,21 @@ gst_rtspsrc_open (GstRTSPSrc * src) /* parse transport */ rtsp_transport_parse (resptrans, &transport); - /* update allowed transports for other streams */ + + /* update allowed transports for other streams. once the transport of + * one stream has been determined, we make sure that all other streams + * are configured in the same way */ if (transport.lower_transport == RTSP_LOWER_TRANS_TCP) { GST_DEBUG_OBJECT (src, "stream %d as TCP", i); protocols = GST_RTSP_PROTO_TCP; src->interleaved = TRUE; } else { if (transport.multicast) { - /* disable unicast */ + /* only allow multicast for other streams */ GST_DEBUG_OBJECT (src, "stream %d as MULTICAST", i); protocols = GST_RTSP_PROTO_UDP_MULTICAST; } else { - /* disable multicast */ + /* only allow unicast for other streams */ GST_DEBUG_OBJECT (src, "stream %d as UNICAST", i); protocols = GST_RTSP_PROTO_UDP_UNICAST; } @@ -1314,9 +1346,8 @@ gst_rtspsrc_close (GstRTSPSrc * src) if (src->options & RTSP_PLAY) { /* do TEARDOWN */ - if ((res = - rtsp_message_init_request (RTSP_TEARDOWN, src->location, - &request)) < 0) + res = rtsp_message_init_request (RTSP_TEARDOWN, src->location, &request); + if (res < 0) goto create_request_failed; if (!gst_rtspsrc_send (src, &request, &response, NULL)) @@ -1363,8 +1394,8 @@ gst_rtspsrc_play (GstRTSPSrc * src) GST_DEBUG_OBJECT (src, "PLAY..."); /* do play */ - if ((res = - rtsp_message_init_request (RTSP_PLAY, src->location, &request)) < 0) + res = rtsp_message_init_request (RTSP_PLAY, src->location, &request); + if (res < 0) goto create_request_failed; if (!gst_rtspsrc_send (src, &request, &response, NULL)) @@ -1406,8 +1437,8 @@ gst_rtspsrc_pause (GstRTSPSrc * src) GST_DEBUG_OBJECT (src, "PAUSE..."); /* do pause */ - if ((res = - rtsp_message_init_request (RTSP_PAUSE, src->location, &request)) < 0) + res = rtsp_message_init_request (RTSP_PAUSE, src->location, &request); + if (res < 0) goto create_request_failed; if (!gst_rtspsrc_send (src, &request, &response, NULL)) diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c index 2ab2e5fe23..f773fa2825 100644 --- a/gst/rtsp/rtspconnection.c +++ b/gst/rtsp/rtspconnection.c @@ -45,12 +45,12 @@ #endif #ifdef G_OS_WIN32 -/* note that inet_aton is deprecated on unix because - * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255 - * address. */ static int inet_aton (const char *c, struct in_addr *paddr) { + /* note that inet_addr is deprecated on unix because + * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255 + * address. */ paddr->s_addr = inet_addr (c); if (paddr->s_addr == INADDR_NONE)