2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 #include <gst/app/gstappsrc.h>
24 #include <gst/app/gstappsink.h>
26 #include "rtsp-media.h"
28 #define DEFAULT_SHARED FALSE
29 #define DEFAULT_REUSABLE FALSE
30 #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
31 //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
32 #define DEFAULT_EOS_SHUTDOWN FALSE
33 #define DEFAULT_BUFFER_SIZE 0x80000
34 #define DEFAULT_MULTICAST_GROUP "224.2.0.1"
37 /* define to dump received RTCP packets */
61 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
62 #define GST_CAT_DEFAULT rtsp_media_debug
64 static void gst_rtsp_media_get_property (GObject * object, guint propid,
65 GValue * value, GParamSpec * pspec);
66 static void gst_rtsp_media_set_property (GObject * object, guint propid,
67 const GValue * value, GParamSpec * pspec);
68 static void gst_rtsp_media_finalize (GObject * obj);
70 static gpointer do_loop (GstRTSPMediaClass * klass);
71 static gboolean default_handle_message (GstRTSPMedia * media,
72 GstMessage * message);
73 static void finish_unprepare (GstRTSPMedia * media);
74 static gboolean default_unprepare (GstRTSPMedia * media);
75 static void unlock_streams (GstRTSPMedia * media);
77 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
79 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
82 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
84 GObjectClass *gobject_class;
86 gobject_class = G_OBJECT_CLASS (klass);
88 gobject_class->get_property = gst_rtsp_media_get_property;
89 gobject_class->set_property = gst_rtsp_media_set_property;
90 gobject_class->finalize = gst_rtsp_media_finalize;
92 g_object_class_install_property (gobject_class, PROP_SHARED,
93 g_param_spec_boolean ("shared", "Shared",
94 "If this media pipeline can be shared", DEFAULT_SHARED,
95 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
97 g_object_class_install_property (gobject_class, PROP_REUSABLE,
98 g_param_spec_boolean ("reusable", "Reusable",
99 "If this media pipeline can be reused after an unprepare",
100 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102 g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
103 g_param_spec_flags ("protocols", "Protocols",
104 "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
105 DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
108 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
109 "Send an EOS event to the pipeline before unpreparing",
110 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
113 g_param_spec_uint ("buffer-size", "Buffer Size",
114 "The kernel UDP buffer size to use", 0, G_MAXUINT,
115 DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117 g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
118 g_param_spec_string ("multicast-group", "Multicast Group",
119 "The Multicast group to send media to",
120 DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
122 g_object_class_install_property (gobject_class, PROP_MTU,
123 g_param_spec_uint ("mtu", "MTU",
124 "The MTU for the payloaders (0 = default)",
125 0, G_MAXUINT, DEFAULT_MTU,
126 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
128 gst_rtsp_media_signals[SIGNAL_PREPARED] =
129 g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
130 G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
131 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
133 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
134 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
135 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
136 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
138 gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
139 g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
140 G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
141 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
143 klass->context = g_main_context_new ();
144 klass->loop = g_main_loop_new (klass->context, TRUE);
146 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
148 klass->thread = g_thread_new ("Bus Thread", (GThreadFunc) do_loop, klass);
150 klass->handle_message = default_handle_message;
151 klass->unprepare = default_unprepare;
155 gst_rtsp_media_init (GstRTSPMedia * media)
157 media->streams = g_ptr_array_new_with_free_func (g_object_unref);
158 g_mutex_init (&media->lock);
159 g_cond_init (&media->cond);
161 media->shared = DEFAULT_SHARED;
162 media->reusable = DEFAULT_REUSABLE;
163 media->protocols = DEFAULT_PROTOCOLS;
164 media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
165 media->buffer_size = DEFAULT_BUFFER_SIZE;
166 media->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP);
170 gst_rtsp_media_finalize (GObject * obj)
174 media = GST_RTSP_MEDIA (obj);
176 GST_INFO ("finalize media %p", media);
178 gst_rtsp_media_unprepare (media);
180 g_ptr_array_unref (media->streams);
182 g_list_free_full (media->dynamic, gst_object_unref);
185 g_source_destroy (media->source);
186 g_source_unref (media->source);
188 g_free (media->multicast_group);
189 g_mutex_clear (&media->lock);
190 g_cond_clear (&media->cond);
192 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
196 gst_rtsp_media_get_property (GObject * object, guint propid,
197 GValue * value, GParamSpec * pspec)
199 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
203 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
206 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
209 g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
211 case PROP_EOS_SHUTDOWN:
212 g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
214 case PROP_BUFFER_SIZE:
215 g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
217 case PROP_MULTICAST_GROUP:
218 g_value_take_string (value, gst_rtsp_media_get_multicast_group (media));
221 g_value_set_uint (value, gst_rtsp_media_get_mtu (media));
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
229 gst_rtsp_media_set_property (GObject * object, guint propid,
230 const GValue * value, GParamSpec * pspec)
232 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
236 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
239 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
242 gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
244 case PROP_EOS_SHUTDOWN:
245 gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
247 case PROP_BUFFER_SIZE:
248 gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
250 case PROP_MULTICAST_GROUP:
251 gst_rtsp_media_set_multicast_group (media, g_value_get_string (value));
254 gst_rtsp_media_set_mtu (media, g_value_get_uint (value));
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
262 do_loop (GstRTSPMediaClass * klass)
264 GST_INFO ("enter mainloop");
265 g_main_loop_run (klass->loop);
266 GST_INFO ("exit mainloop");
272 collect_media_stats (GstRTSPMedia * media)
274 gint64 position, duration;
276 media->range.unit = GST_RTSP_RANGE_NPT;
278 if (media->is_live) {
279 media->range.min.type = GST_RTSP_TIME_NOW;
280 media->range.min.seconds = -1;
281 media->range.max.type = GST_RTSP_TIME_END;
282 media->range.max.seconds = -1;
284 /* get the position */
285 if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME,
287 GST_INFO ("position query failed");
291 /* get the duration */
292 if (!gst_element_query_duration (media->pipeline, GST_FORMAT_TIME,
294 GST_INFO ("duration query failed");
298 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
299 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
301 if (position == -1) {
302 media->range.min.type = GST_RTSP_TIME_NOW;
303 media->range.min.seconds = -1;
305 media->range.min.type = GST_RTSP_TIME_SECONDS;
306 media->range.min.seconds = ((gdouble) position) / GST_SECOND;
308 if (duration == -1) {
309 media->range.max.type = GST_RTSP_TIME_END;
310 media->range.max.seconds = -1;
312 media->range.max.type = GST_RTSP_TIME_SECONDS;
313 media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
319 * gst_rtsp_media_new:
321 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
322 * element to produce RTP data for one or more related (audio/video/..)
325 * Returns: a new #GstRTSPMedia object.
328 gst_rtsp_media_new (void)
330 GstRTSPMedia *result;
332 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
338 * gst_rtsp_media_set_shared:
339 * @media: a #GstRTSPMedia
340 * @shared: the new value
342 * Set or unset if the pipeline for @media can be shared will multiple clients.
343 * When @shared is %TRUE, client requests for this media will share the media
347 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
349 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
351 media->shared = shared;
355 * gst_rtsp_media_is_shared:
356 * @media: a #GstRTSPMedia
358 * Check if the pipeline for @media can be shared between multiple clients.
360 * Returns: %TRUE if the media can be shared between clients.
363 gst_rtsp_media_is_shared (GstRTSPMedia * media)
365 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
367 return media->shared;
371 * gst_rtsp_media_set_reusable:
372 * @media: a #GstRTSPMedia
373 * @reusable: the new value
375 * Set or unset if the pipeline for @media can be reused after the pipeline has
379 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
381 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
383 media->reusable = reusable;
387 * gst_rtsp_media_is_reusable:
388 * @media: a #GstRTSPMedia
390 * Check if the pipeline for @media can be reused after an unprepare.
392 * Returns: %TRUE if the media can be reused
395 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
397 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
399 return media->reusable;
403 * gst_rtsp_media_set_protocols:
404 * @media: a #GstRTSPMedia
405 * @protocols: the new flags
407 * Configure the allowed lower transport for @media.
410 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
412 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
414 media->protocols = protocols;
418 * gst_rtsp_media_get_protocols:
419 * @media: a #GstRTSPMedia
421 * Get the allowed protocols of @media.
423 * Returns: a #GstRTSPLowerTrans
426 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
428 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
429 GST_RTSP_LOWER_TRANS_UNKNOWN);
431 return media->protocols;
435 * gst_rtsp_media_set_eos_shutdown:
436 * @media: a #GstRTSPMedia
437 * @eos_shutdown: the new value
439 * Set or unset if an EOS event will be sent to the pipeline for @media before
443 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
445 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
447 media->eos_shutdown = eos_shutdown;
451 * gst_rtsp_media_is_eos_shutdown:
452 * @media: a #GstRTSPMedia
454 * Check if the pipeline for @media will send an EOS down the pipeline before
457 * Returns: %TRUE if the media will send EOS before unpreparing.
460 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
462 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
464 return media->eos_shutdown;
468 * gst_rtsp_media_set_buffer_size:
469 * @media: a #GstRTSPMedia
470 * @size: the new value
472 * Set the kernel UDP buffer size.
475 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
477 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
479 media->buffer_size = size;
483 * gst_rtsp_media_get_buffer_size:
484 * @media: a #GstRTSPMedia
486 * Get the kernel UDP buffer size.
488 * Returns: the kernel UDP buffer size.
491 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
493 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
495 return media->buffer_size;
499 * gst_rtsp_media_set_multicast_group:
500 * @media: a #GstRTSPMedia
501 * @mc: the new multicast group
503 * Set the multicast group that media from @media will be streamed to.
506 gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc)
508 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
510 g_mutex_lock (&media->lock);
511 g_free (media->multicast_group);
512 media->multicast_group = g_strdup (mc);
513 g_mutex_unlock (&media->lock);
517 * gst_rtsp_media_get_multicast_group:
518 * @media: a #GstRTSPMedia
520 * Get the multicast group that media from @media will be streamed to.
522 * Returns: the multicast group
525 gst_rtsp_media_get_multicast_group (GstRTSPMedia * media)
529 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
531 g_mutex_lock (&media->lock);
532 result = g_strdup (media->multicast_group);
533 g_mutex_unlock (&media->lock);
539 * gst_rtsp_media_set_auth:
540 * @media: a #GstRTSPMedia
541 * @auth: a #GstRTSPAuth
543 * configure @auth to be used as the authentication manager of @media.
546 gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
550 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
559 g_object_unref (old);
564 * gst_rtsp_media_get_auth:
565 * @media: a #GstRTSPMedia
567 * Get the #GstRTSPAuth used as the authentication manager of @media.
569 * Returns: (transfer full): the #GstRTSPAuth of @media. g_object_unref() after
573 gst_rtsp_media_get_auth (GstRTSPMedia * media)
577 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
579 if ((result = media->auth))
580 g_object_ref (result);
586 * gst_rtsp_media_set_mtu:
587 * @media: a #GstRTSPMedia
590 * Set maximum size of one RTP packet on the payloaders.
591 * The @mtu will be set on all streams.
594 gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu)
598 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
601 for (i = 0; i < media->streams->len; i++) {
602 GstRTSPStream *stream;
604 GST_INFO ("Setting mtu %u for stream %d", mtu, i);
606 stream = g_ptr_array_index (media->streams, i);
607 gst_rtsp_stream_set_mtu (stream, mtu);
612 * gst_rtsp_media_get_mtu:
613 * @media: a #GstRTSPMedia
615 * Get the configured MTU.
618 gst_rtsp_media_get_mtu (GstRTSPMedia * media)
620 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
626 * gst_rtsp_media_collect_streams:
627 * @media: a #GstRTSPMedia
629 * Find all payloader elements, they should be named pay%d in the
630 * element of @media, and create #GstRTSPStreams for them.
632 * Collect all dynamic elements, named dynpay%d, and add them to
633 * the list of dynamic elements.
636 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
638 GstElement *element, *elem;
643 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
645 element = media->element;
648 for (i = 0; have_elem; i++) {
653 name = g_strdup_printf ("pay%d", i);
654 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
655 GST_INFO ("found stream %d with payloader %p", i, elem);
657 /* take the pad of the payloader */
658 pad = gst_element_get_static_pad (elem, "src");
659 /* create the stream */
660 gst_rtsp_media_create_stream (media, elem, pad);
661 g_object_unref (pad);
663 gst_object_unref (elem);
669 name = g_strdup_printf ("dynpay%d", i);
670 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
671 /* a stream that will dynamically create pads to provide RTP packets */
673 GST_INFO ("found dynamic element %d, %p", i, elem);
675 media->dynamic = g_list_prepend (media->dynamic, elem);
684 * gst_rtsp_media_create_stream:
685 * @media: a #GstRTSPMedia
686 * @payloader: a #GstElement
687 * @srcpad: a source #GstPad
689 * Create a new stream in @media that provides RTP data on @srcpad.
690 * @srcpad should be a pad of an element inside @media->element.
692 * Returns: a new #GstRTSPStream that remains valid for as long
696 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
699 GstRTSPStream *stream;
704 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
705 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
706 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
707 g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
709 idx = media->streams->len;
711 name = g_strdup_printf ("src_%u", idx);
712 srcpad = gst_ghost_pad_new (name, pad);
713 gst_pad_set_active (srcpad, TRUE);
714 gst_element_add_pad (media->element, srcpad);
717 stream = gst_rtsp_stream_new (idx, payloader, srcpad);
719 gst_rtsp_stream_set_mtu (stream, media->mtu);
721 g_ptr_array_add (media->streams, stream);
727 * gst_rtsp_media_n_streams:
728 * @media: a #GstRTSPMedia
730 * Get the number of streams in this media.
732 * Returns: The number of streams.
735 gst_rtsp_media_n_streams (GstRTSPMedia * media)
737 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
739 return media->streams->len;
743 * gst_rtsp_media_get_stream:
744 * @media: a #GstRTSPMedia
745 * @idx: the stream index
747 * Retrieve the stream with index @idx from @media.
749 * Returns: the #GstRTSPStream at index @idx or %NULL when a stream with
750 * that index did not exist.
753 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
757 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
759 if (idx < media->streams->len)
760 res = g_ptr_array_index (media->streams, idx);
768 * gst_rtsp_media_get_range_string:
769 * @media: a #GstRTSPMedia
770 * @play: for the PLAY request
772 * Get the current range as a string.
774 * Returns: The range as a string, g_free() after usage.
777 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
780 GstRTSPTimeRange range;
783 range = media->range;
785 if (!play && media->n_active > 0) {
786 range.min.type = GST_RTSP_TIME_NOW;
787 range.min.seconds = -1;
790 result = gst_rtsp_range_to_string (&range);
796 * gst_rtsp_media_seek:
797 * @media: a #GstRTSPMedia
798 * @range: a #GstRTSPTimeRange
800 * Seek the pipeline to @range.
802 * Returns: %TRUE on success.
805 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
810 GstSeekType start_type, stop_type;
812 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
813 g_return_val_if_fail (range != NULL, FALSE);
815 if (!media->seekable) {
816 GST_INFO ("pipeline is not seekable");
820 if (range->unit != GST_RTSP_RANGE_NPT)
823 /* depends on the current playing state of the pipeline. We might need to
824 * queue this until we get EOS. */
825 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
827 start_type = stop_type = GST_SEEK_TYPE_NONE;
829 switch (range->min.type) {
830 case GST_RTSP_TIME_NOW:
833 case GST_RTSP_TIME_SECONDS:
834 /* only seek when something changed */
835 if (media->range.min.seconds == range->min.seconds) {
838 start = range->min.seconds * GST_SECOND;
839 start_type = GST_SEEK_TYPE_SET;
842 case GST_RTSP_TIME_END:
846 switch (range->max.type) {
847 case GST_RTSP_TIME_SECONDS:
848 /* only seek when something changed */
849 if (media->range.max.seconds == range->max.seconds) {
852 stop = range->max.seconds * GST_SECOND;
853 stop_type = GST_SEEK_TYPE_SET;
856 case GST_RTSP_TIME_END:
858 stop_type = GST_SEEK_TYPE_SET;
860 case GST_RTSP_TIME_NOW:
865 if (start != -1 || stop != -1) {
866 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
867 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
869 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
870 flags, start_type, start, stop_type, stop);
872 /* and block for the seek to complete */
873 GST_INFO ("done seeking %d", res);
874 gst_element_get_state (media->pipeline, NULL, NULL, -1);
875 GST_INFO ("prerolled again");
877 collect_media_stats (media);
879 GST_INFO ("no seek needed");
888 GST_WARNING ("seek unit %d not supported", range->unit);
893 GST_WARNING ("weird range type %d not supported", range->min.type);
899 unlock_streams (GstRTSPMedia * media)
903 /* unlock the udp src elements */
904 for (i = 0; i < media->streams->len; i++) {
905 GstRTSPStream *stream;
907 stream = g_ptr_array_index (media->streams, i);
909 gst_element_set_locked_state (stream->udpsrc[0], FALSE);
910 gst_element_set_locked_state (stream->udpsrc[1], FALSE);
915 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
917 g_mutex_lock (&media->lock);
918 /* never overwrite the error status */
919 if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
920 media->status = status;
921 GST_DEBUG ("setting new status to %d", status);
922 g_cond_broadcast (&media->cond);
923 g_mutex_unlock (&media->lock);
926 static GstRTSPMediaStatus
927 gst_rtsp_media_get_status (GstRTSPMedia * media)
929 GstRTSPMediaStatus result;
932 g_mutex_lock (&media->lock);
933 end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
934 /* while we are preparing, wait */
935 while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
936 GST_DEBUG ("waiting for status change");
937 if (!g_cond_wait_until (&media->cond, &media->lock, end_time)) {
938 GST_DEBUG ("timeout, assuming error status");
939 media->status = GST_RTSP_MEDIA_STATUS_ERROR;
942 /* could be success or error */
943 result = media->status;
944 GST_DEBUG ("got status %d", result);
945 g_mutex_unlock (&media->lock);
951 default_handle_message (GstRTSPMedia * media, GstMessage * message)
955 type = GST_MESSAGE_TYPE (message);
958 case GST_MESSAGE_STATE_CHANGED:
960 case GST_MESSAGE_BUFFERING:
964 gst_message_parse_buffering (message, &percent);
966 /* no state management needed for live pipelines */
970 if (percent == 100) {
971 /* a 100% message means buffering is done */
972 media->buffering = FALSE;
973 /* if the desired state is playing, go back */
974 if (media->target_state == GST_STATE_PLAYING) {
975 GST_INFO ("Buffering done, setting pipeline to PLAYING");
976 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
978 GST_INFO ("Buffering done");
982 if (media->buffering == FALSE) {
983 if (media->target_state == GST_STATE_PLAYING) {
984 /* we were not buffering but PLAYING, PAUSE the pipeline. */
985 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
986 gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
988 GST_INFO ("Buffering ...");
991 media->buffering = TRUE;
995 case GST_MESSAGE_LATENCY:
997 gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
1000 case GST_MESSAGE_ERROR:
1005 gst_message_parse_error (message, &gerror, &debug);
1006 GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1007 g_error_free (gerror);
1010 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1013 case GST_MESSAGE_WARNING:
1018 gst_message_parse_warning (message, &gerror, &debug);
1019 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1020 g_error_free (gerror);
1024 case GST_MESSAGE_ELEMENT:
1026 case GST_MESSAGE_STREAM_STATUS:
1028 case GST_MESSAGE_ASYNC_DONE:
1029 if (!media->adding) {
1030 /* when we are dynamically adding pads, the addition of the udpsrc will
1031 * temporarily produce ASYNC_DONE messages. We have to ignore them and
1032 * wait for the final ASYNC_DONE after everything prerolled */
1033 GST_INFO ("%p: got ASYNC_DONE", media);
1034 collect_media_stats (media);
1036 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1038 GST_INFO ("%p: ignoring ASYNC_DONE", media);
1041 case GST_MESSAGE_EOS:
1042 GST_INFO ("%p: got EOS", media);
1043 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1044 GST_DEBUG ("shutting down after EOS");
1045 finish_unprepare (media);
1046 g_object_unref (media);
1050 GST_INFO ("%p: got message type %s", media,
1051 gst_message_type_get_name (type));
1058 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1060 GstRTSPMediaClass *klass;
1063 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1065 if (klass->handle_message)
1066 ret = klass->handle_message (media, message);
1073 /* called from streaming threads */
1075 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1077 GstRTSPStream *stream;
1080 stream = gst_rtsp_media_create_stream (media, element, pad);
1081 GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad),
1084 media->adding = TRUE;
1086 gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin);
1088 for (i = 0; i < 2; i++) {
1089 gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED);
1090 gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED);
1091 gst_element_set_state (stream->appqueue[i], GST_STATE_PAUSED);
1092 gst_element_set_state (stream->tee[i], GST_STATE_PAUSED);
1093 gst_element_set_state (stream->selector[i], GST_STATE_PAUSED);
1094 gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED);
1097 media->adding = FALSE;
1101 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1103 GST_INFO ("no more pads");
1104 if (media->fakesink) {
1105 gst_object_ref (media->fakesink);
1106 gst_bin_remove (GST_BIN (media->pipeline), media->fakesink);
1107 gst_element_set_state (media->fakesink, GST_STATE_NULL);
1108 gst_object_unref (media->fakesink);
1109 media->fakesink = NULL;
1110 GST_INFO ("removed fakesink");
1115 * gst_rtsp_media_prepare:
1116 * @media: a #GstRTSPMedia
1118 * Prepare @media for streaming. This function will create the pipeline and
1119 * other objects to manage the streaming.
1121 * It will preroll the pipeline and collect vital information about the streams
1122 * such as the duration.
1124 * Returns: %TRUE on success.
1127 gst_rtsp_media_prepare (GstRTSPMedia * media)
1129 GstStateChangeReturn ret;
1130 GstRTSPMediaStatus status;
1132 GstRTSPMediaClass *klass;
1136 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1139 if (!media->reusable && media->reused)
1142 media->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1143 if (media->rtpbin == NULL)
1146 GST_INFO ("preparing media %p", media);
1148 /* reset some variables */
1149 media->is_live = FALSE;
1150 media->seekable = FALSE;
1151 media->buffering = FALSE;
1152 /* we're preparing now */
1153 media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1155 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
1157 /* add the pipeline bus to our custom mainloop */
1158 media->source = gst_bus_create_watch (bus);
1159 gst_object_unref (bus);
1161 g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL);
1163 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1164 media->id = g_source_attach (media->source, klass->context);
1166 /* add stuff to the bin */
1167 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
1169 /* link streams we already have, other streams might appear when we have
1170 * dynamic elements */
1171 for (i = 0; i < media->streams->len; i++) {
1172 GstRTSPStream *stream;
1174 stream = g_ptr_array_index (media->streams, i);
1176 gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin);
1179 for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
1180 GstElement *elem = walk->data;
1182 GST_INFO ("adding callbacks for dynamic element %p", elem);
1184 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1185 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1187 /* we add a fakesink here in order to make the state change async. We remove
1188 * the fakesink again in the no-more-pads callback. */
1189 media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1190 gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
1193 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1194 /* first go to PAUSED */
1195 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1196 media->target_state = GST_STATE_PAUSED;
1199 case GST_STATE_CHANGE_SUCCESS:
1200 GST_INFO ("SUCCESS state change for media %p", media);
1201 media->seekable = TRUE;
1203 case GST_STATE_CHANGE_ASYNC:
1204 GST_INFO ("ASYNC state change for media %p", media);
1205 media->seekable = TRUE;
1207 case GST_STATE_CHANGE_NO_PREROLL:
1208 /* we need to go to PLAYING */
1209 GST_INFO ("NO_PREROLL state change: live media %p", media);
1210 /* FIXME we disable seeking for live streams for now. We should perform a
1211 * seeking query in preroll instead and do a seeking query. */
1212 media->seekable = FALSE;
1213 media->is_live = TRUE;
1214 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1215 if (ret == GST_STATE_CHANGE_FAILURE)
1218 case GST_STATE_CHANGE_FAILURE:
1222 /* now wait for all pads to be prerolled */
1223 status = gst_rtsp_media_get_status (media);
1224 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1227 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1229 GST_INFO ("object %p is prerolled", media);
1241 GST_WARNING ("can not reuse media %p", media);
1246 GST_WARNING ("no rtpbin element");
1247 g_warning ("failed to create element 'rtpbin', check your installation");
1252 GST_WARNING ("failed to preroll pipeline");
1253 gst_rtsp_media_unprepare (media);
1259 * gst_rtsp_media_unprepare:
1260 * @media: a #GstRTSPMedia
1262 * Unprepare @media. After this call, the media should be prepared again before
1263 * it can be used again. If the media is set to be non-reusable, a new instance
1266 * Returns: %TRUE on success.
1269 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1273 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1276 GST_INFO ("unprepare media %p", media);
1277 media->target_state = GST_STATE_NULL;
1280 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1281 GstRTSPMediaClass *klass;
1283 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1284 if (klass->unprepare)
1285 success = klass->unprepare (media);
1287 finish_unprepare (media);
1290 media->reused = TRUE;
1292 /* when the media is not reusable, this will effectively unref the media and
1294 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1300 finish_unprepare (GstRTSPMedia * media)
1304 GST_DEBUG ("shutting down");
1306 unlock_streams (media);
1307 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1309 for (i = 0; i < media->streams->len; i++) {
1310 GstRTSPStream *stream;
1312 GST_INFO ("Removing elements of stream %d from pipeline", i);
1314 stream = g_ptr_array_index (media->streams, i);
1316 gst_rtsp_stream_leave_bin (stream, GST_BIN (media->pipeline),
1319 g_ptr_array_set_size (media->streams, 0);
1321 gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
1323 gst_object_unref (media->pipeline);
1324 media->pipeline = NULL;
1326 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1330 default_unprepare (GstRTSPMedia * media)
1332 if (media->eos_shutdown) {
1333 GST_DEBUG ("sending EOS for shutdown");
1334 /* ref so that we don't disappear */
1335 g_object_ref (media);
1336 gst_element_send_event (media->pipeline, gst_event_new_eos ());
1337 /* we need to go to playing again for the EOS to propagate, normally in this
1338 * state, nothing is receiving data from us anymore so this is ok. */
1339 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1340 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1342 finish_unprepare (media);
1348 * gst_rtsp_media_set_state:
1349 * @media: a #GstRTSPMedia
1350 * @state: the target state of the media
1351 * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers
1353 * Set the state of @media to @state and for the transports in @transports.
1355 * Returns: %TRUE on success.
1358 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1359 GPtrArray * transports)
1362 gboolean add, remove, do_state;
1365 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1366 g_return_val_if_fail (transports != NULL, FALSE);
1368 /* NULL and READY are the same */
1369 if (state == GST_STATE_READY)
1370 state = GST_STATE_NULL;
1372 add = remove = FALSE;
1374 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1378 case GST_STATE_NULL:
1379 /* unlock the streams so that they follow the state changes from now on */
1380 unlock_streams (media);
1382 case GST_STATE_PAUSED:
1383 /* we're going from PLAYING to PAUSED, READY or NULL, remove */
1384 if (media->target_state == GST_STATE_PLAYING)
1387 case GST_STATE_PLAYING:
1388 /* we're going to PLAYING, add */
1394 old_active = media->n_active;
1396 for (i = 0; i < transports->len; i++) {
1397 GstRTSPStreamTransport *trans;
1399 /* we need a non-NULL entry in the array */
1400 trans = g_ptr_array_index (transports, i);
1404 /* we need a transport */
1405 if (!trans->transport)
1409 if (gst_rtsp_stream_add_transport (trans->stream, trans))
1411 } else if (remove) {
1412 if (gst_rtsp_stream_remove_transport (trans->stream, trans))
1417 /* we just added the first media, do the playing state change */
1418 if (old_active == 0 && add)
1420 /* if we have no more active media, do the downward state changes */
1421 else if (media->n_active == 0)
1426 GST_INFO ("state %d active %d media %p do_state %d", state, media->n_active,
1429 if (media->target_state != state) {
1431 if (state == GST_STATE_NULL) {
1432 gst_rtsp_media_unprepare (media);
1434 GST_INFO ("state %s media %p", gst_element_state_get_name (state),
1436 media->target_state = state;
1437 gst_element_set_state (media->pipeline, state);
1440 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
1444 /* remember where we are */
1445 if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
1446 old_active != media->n_active))
1447 collect_media_stats (media);