rtsp: add support for dynamic elements

Add support for dynamic elements.
Don't set live pipelines back to paused.
This commit is contained in:
Wim Taymans 2009-05-24 19:34:52 +02:00 committed by Wim Taymans
parent 415e5e674b
commit fab65082da
3 changed files with 117 additions and 40 deletions

View file

@ -402,39 +402,52 @@ static void
collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url,
GstRTSPMedia *media) GstRTSPMedia *media)
{ {
GstElement *element, *pay; GstElement *element, *elem;
GstPad * pad; GstPad * pad;
gint i; gint i;
GstRTSPMediaStream *stream; GstRTSPMediaStream *stream;
gboolean have_elem;
element = media->element; element = media->element;
for (i = 0; ; i++) { have_elem = TRUE;
for (i = 0; have_elem ; i++) {
gchar *name; gchar *name;
have_elem = FALSE;
name = g_strdup_printf ("pay%d", i); name = g_strdup_printf ("pay%d", i);
if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
/* no more payloaders found, we have found all the streams and we can /* create the stream */
* end the loop */ stream = g_new0 (GstRTSPMediaStream, 1);
g_free (name); stream->payloader = elem;
break;
g_message ("found stream %d with payloader %p", i, elem);
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 (elem);
/* add stream now */
g_array_append_val (media->streams, stream);
have_elem = TRUE;
} }
/* create the stream */
stream = g_new0 (GstRTSPMediaStream, 1);
stream->payloader = pay;
g_message ("found stream %d with payloader %p", i, pay);
pad = gst_element_get_static_pad (pay, "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);
g_free (name); g_free (name);
/* add stream now */ name = g_strdup_printf ("dynpay%d", i);
g_array_append_val (media->streams, stream); 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);
} }
} }

View file

@ -134,6 +134,9 @@ gst_rtsp_media_finalize (GObject * obj)
} }
g_array_free (media->streams, TRUE); g_array_free (media->streams, TRUE);
g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL);
g_list_free (media->dynamic);
if (media->source) { if (media->source) {
g_source_destroy (media->source); g_source_destroy (media->source);
g_source_unref (media->source); g_source_unref (media->source);
@ -761,7 +764,6 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media)
GstPad *pad, *teepad, *selpad; GstPad *pad, *teepad, *selpad;
GstPadLinkReturn ret; GstPadLinkReturn ret;
gint i; gint i;
GstElement *tee;
/* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 /* 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 * 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; goto link_failed;
/* make tee for RTP and link to stream */ /* make tee for RTP and link to stream */
tee = gst_element_factory_make ("tee", NULL); stream->tee[0] = gst_element_factory_make ("tee", NULL);
gst_bin_add (GST_BIN_CAST (media->pipeline), tee); 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_pad_link (stream->send_rtp_src, pad);
gst_object_unref (pad); gst_object_unref (pad);
/* link RTP sink, we're pretty sure this will work. */ /* 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"); pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
gst_pad_link (teepad, pad); gst_pad_link (teepad, pad);
gst_object_unref (pad); gst_object_unref (pad);
gst_object_unref (teepad); 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"); pad = gst_element_get_static_pad (stream->appsink[0], "sink");
gst_pad_link (teepad, pad); gst_pad_link (teepad, pad);
gst_object_unref (pad); gst_object_unref (pad);
gst_object_unref (teepad); gst_object_unref (teepad);
/* make tee for RTCP */ /* make tee for RTCP */
tee = gst_element_factory_make ("tee", NULL); stream->tee[1] = gst_element_factory_make ("tee", NULL);
gst_bin_add (GST_BIN_CAST (media->pipeline), tee); 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_pad_link (stream->send_rtcp_src, pad);
gst_object_unref (pad); gst_object_unref (pad);
/* link RTCP elements */ /* 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"); pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
gst_pad_link (teepad, pad); gst_pad_link (teepad, pad);
gst_object_unref (pad); gst_object_unref (pad);
gst_object_unref (teepad); 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"); pad = gst_element_get_static_pad (stream->appsink[1], "sink");
gst_pad_link (teepad, pad); gst_pad_link (teepad, pad);
gst_object_unref (pad); gst_object_unref (pad);
@ -1046,6 +1048,56 @@ bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media)
return ret; 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: * gst_rtsp_media_prepare:
* @obj: a #GstRTSPMedia * @obj: a #GstRTSPMedia
@ -1065,6 +1117,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
guint i, n_streams; guint i, n_streams;
GstRTSPMediaClass *klass; GstRTSPMediaClass *klass;
GstBus *bus; GstBus *bus;
GList *walk;
if (media->prepared) if (media->prepared)
goto was_prepared; goto was_prepared;
@ -1090,10 +1143,11 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); 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); 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); n_streams = gst_rtsp_media_n_streams (media);
for (i = 0; i < n_streams; i++) { for (i = 0; i < n_streams; i++) {
GstRTSPMediaStream *stream; GstRTSPMediaStream *stream;
@ -1103,6 +1157,16 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
setup_stream (stream, i, 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 */ /* first go to PAUSED */
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
media->target_state = 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) if (ret == GST_STATE_CHANGE_FAILURE)
goto state_failed; 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 stats about the media */
collect_media_stats (media); collect_media_stats (media);
@ -1158,7 +1217,7 @@ state_failed:
} }
is_reused: is_reused:
{ {
g_warning ("can not reused media %p", media); g_warning ("can not reuse media %p", media);
return FALSE; return FALSE;
} }
} }
@ -1281,8 +1340,10 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport
} }
case GST_RTSP_LOWER_TRANS_TCP: case GST_RTSP_LOWER_TRANS_TCP:
if (add) { if (add) {
g_message ("adding TCP %s", trans->destination);
stream->transports = g_list_prepend (stream->transports, tr); stream->transports = g_list_prepend (stream->transports, tr);
} else if (remove) { } else if (remove) {
g_message ("removing TCP %s", trans->destination);
stream->transports = g_list_remove (stream->transports, tr); stream->transports = g_list_remove (stream->transports, tr);
} }
break; break;

View file

@ -110,6 +110,7 @@ struct _GstRTSPMediaStream {
GstElement *appsrc[2]; GstElement *appsrc[2];
GstElement *appsink[2]; GstElement *appsink[2];
GstElement *tee[2];
GstElement *selector[2]; GstElement *selector[2];
/* server ports for sending/receiving */ /* server ports for sending/receiving */
@ -153,11 +154,13 @@ struct _GstRTSPMedia {
GstElement *element; GstElement *element;
GArray *streams; GArray *streams;
GList *dynamic;
gboolean prepared; gboolean prepared;
gint active; gint active;
/* the pipeline for the media */ /* the pipeline for the media */
GstElement *pipeline; GstElement *pipeline;
GstElement *fakesink;
GSource *source; GSource *source;
guint id; guint id;