From fab65082da699260f216073b1f74d9d7855a9b46 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 24 May 2009 19:34:52 +0200 Subject: [PATCH] rtsp: add support for dynamic elements Add support for dynamic elements. Don't set live pipelines back to paused. --- gst/rtsp-server/rtsp-media-factory.c | 51 ++++++++++++------- gst/rtsp-server/rtsp-media.c | 99 +++++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-media.h | 3 ++ 3 files changed, 115 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 69991ae..2a5833d 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -402,39 +402,52 @@ static void collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, GstRTSPMedia *media) { - GstElement *element, *pay; + GstElement *element, *elem; GstPad * pad; gint i; GstRTSPMediaStream *stream; + gboolean have_elem; element = media->element; - for (i = 0; ; i++) { + have_elem = TRUE; + for (i = 0; have_elem ; i++) { gchar *name; + have_elem = FALSE; + name = g_strdup_printf ("pay%d", i); - if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { - /* no more payloaders found, we have found all the streams and we can - * end the loop */ - g_free (name); - break; - } - /* create the stream */ - stream = g_new0 (GstRTSPMediaStream, 1); - stream->payloader = pay; + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + /* create the stream */ + stream = g_new0 (GstRTSPMediaStream, 1); + stream->payloader = elem; - g_message ("found stream %d with payloader %p", i, pay); + g_message ("found stream %d with payloader %p", i, elem); - pad = gst_element_get_static_pad (pay, "src"); + pad = gst_element_get_static_pad (elem, "src"); - /* ghost the pad of the payloader to the element */ - stream->srcpad = gst_ghost_pad_new (name, pad); - gst_element_add_pad (media->element, stream->srcpad); - gst_object_unref (pay); + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_element_add_pad (media->element, stream->srcpad); + gst_object_unref (elem); + + /* add stream now */ + g_array_append_val (media->streams, stream); + have_elem = TRUE; + } g_free (name); - /* add stream now */ - g_array_append_val (media->streams, stream); + name = g_strdup_printf ("dynpay%d", i); + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + /* a stream that will dynamically create pads to provide RTP packets */ + + g_message ("found dynamic element %d, %p", i, elem); + + media->dynamic = g_list_prepend (media->dynamic, elem); + + have_elem = TRUE; + } + g_free (name); } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0e5fec6..b5e0c59 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -134,6 +134,9 @@ gst_rtsp_media_finalize (GObject * obj) } g_array_free (media->streams, TRUE); + g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL); + g_list_free (media->dynamic); + if (media->source) { g_source_destroy (media->source); g_source_unref (media->source); @@ -761,7 +764,6 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) GstPad *pad, *teepad, *selpad; GstPadLinkReturn ret; gint i; - GstElement *tee; /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 * for sending RTP/RTCP. The sender and receiver ports are shared between the @@ -826,42 +828,42 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) goto link_failed; /* make tee for RTP and link to stream */ - tee = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + stream->tee[0] = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]); - pad = gst_element_get_static_pad (tee, "sink"); + pad = gst_element_get_static_pad (stream->tee[0], "sink"); gst_pad_link (stream->send_rtp_src, pad); gst_object_unref (pad); /* link RTP sink, we're pretty sure this will work. */ - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); pad = gst_element_get_static_pad (stream->appsink[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); /* make tee for RTCP */ - tee = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + stream->tee[1] = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]); - pad = gst_element_get_static_pad (tee, "sink"); + pad = gst_element_get_static_pad (stream->tee[1], "sink"); gst_pad_link (stream->send_rtcp_src, pad); gst_object_unref (pad); /* link RTCP elements */ - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); pad = gst_element_get_static_pad (stream->appsink[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); @@ -1046,6 +1048,56 @@ bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) return ret; } +static void +pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) +{ + GstRTSPMediaStream *stream; + gchar *name; + gint i; + + i = media->streams->len + 1; + + g_message ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i); + + stream = g_new0 (GstRTSPMediaStream, 1); + stream->payloader = element; + + name = g_strdup_printf ("dynpay%d", i); + + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (stream->srcpad, TRUE); + gst_element_add_pad (media->element, stream->srcpad); + g_free (name); + + /* add stream now */ + g_array_append_val (media->streams, stream); + + setup_stream (stream, i, media); + + for (i = 0; i < 2; i++) { + gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED); + gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED); + gst_element_set_state (stream->tee[i], GST_STATE_PAUSED); + gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); + gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); + } +} + +static void +no_more_pads_cb (GstElement *element, GstRTSPMedia *media) +{ + g_message ("no more pads"); + if (media->fakesink) { + gst_object_ref (media->fakesink); + gst_bin_remove (GST_BIN (media->pipeline), media->fakesink); + gst_element_set_state (media->fakesink, GST_STATE_NULL); + gst_object_unref (media->fakesink); + media->fakesink = NULL; + g_message ("removed fakesink"); + } +} + /** * gst_rtsp_media_prepare: * @obj: a #GstRTSPMedia @@ -1065,6 +1117,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) guint i, n_streams; GstRTSPMediaClass *klass; GstBus *bus; + GList *walk; if (media->prepared) goto was_prepared; @@ -1090,10 +1143,11 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); - /* add stuf to the bin */ + /* add stuff to the bin */ gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); - /* link streams we already have */ + /* link streams we already have, other streams might appear when we have + * dynamic elements */ n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; @@ -1103,6 +1157,16 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) setup_stream (stream, i, media); } + for (walk = media->dynamic; walk; walk = g_list_next (walk)) { + GstElement *elem = walk->data; + + g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); + g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); + + media->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (media->pipeline), media->fakesink); + } + /* first go to PAUSED */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); media->target_state = GST_STATE_PAUSED; @@ -1129,11 +1193,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; - /* and back to PAUSED for live pipelines */ - ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) - goto state_failed; - /* collect stats about the media */ collect_media_stats (media); @@ -1158,7 +1217,7 @@ state_failed: } is_reused: { - g_warning ("can not reused media %p", media); + g_warning ("can not reuse media %p", media); return FALSE; } } @@ -1281,8 +1340,10 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport } case GST_RTSP_LOWER_TRANS_TCP: if (add) { + g_message ("adding TCP %s", trans->destination); stream->transports = g_list_prepend (stream->transports, tr); } else if (remove) { + g_message ("removing TCP %s", trans->destination); stream->transports = g_list_remove (stream->transports, tr); } break; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a7e9a1c..29e9989 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -110,6 +110,7 @@ struct _GstRTSPMediaStream { GstElement *appsrc[2]; GstElement *appsink[2]; + GstElement *tee[2]; GstElement *selector[2]; /* server ports for sending/receiving */ @@ -153,11 +154,13 @@ struct _GstRTSPMedia { GstElement *element; GArray *streams; + GList *dynamic; gboolean prepared; gint active; /* the pipeline for the media */ GstElement *pipeline; + GstElement *fakesink; GSource *source; guint id; -- 2.7.4