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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, 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
35 /* define to dump received RTCP packets */
58 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
59 #define GST_CAT_DEFAULT rtsp_media_debug
61 static void gst_rtsp_media_get_property (GObject * object, guint propid,
62 GValue * value, GParamSpec * pspec);
63 static void gst_rtsp_media_set_property (GObject * object, guint propid,
64 const GValue * value, GParamSpec * pspec);
65 static void gst_rtsp_media_finalize (GObject * obj);
67 static gpointer do_loop (GstRTSPMediaClass * klass);
68 static gboolean default_handle_message (GstRTSPMedia * media,
69 GstMessage * message);
70 static void finish_unprepare (GstRTSPMedia * media);
71 static gboolean default_unprepare (GstRTSPMedia * media);
73 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
75 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
78 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
80 GObjectClass *gobject_class;
82 gobject_class = G_OBJECT_CLASS (klass);
84 gobject_class->get_property = gst_rtsp_media_get_property;
85 gobject_class->set_property = gst_rtsp_media_set_property;
86 gobject_class->finalize = gst_rtsp_media_finalize;
88 g_object_class_install_property (gobject_class, PROP_SHARED,
89 g_param_spec_boolean ("shared", "Shared",
90 "If this media pipeline can be shared", DEFAULT_SHARED,
91 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
93 g_object_class_install_property (gobject_class, PROP_REUSABLE,
94 g_param_spec_boolean ("reusable", "Reusable",
95 "If this media pipeline can be reused after an unprepare",
96 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
98 g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
99 g_param_spec_flags ("protocols", "Protocols",
100 "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
101 DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
103 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
104 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
105 "Send an EOS event to the pipeline before unpreparing",
106 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
108 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
109 g_param_spec_uint ("buffer-size", "Buffer Size",
110 "The kernel UDP buffer size to use", 0, G_MAXUINT,
111 DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
113 gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
114 g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
115 G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
116 g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM);
118 gst_rtsp_media_signals[SIGNAL_PREPARED] =
119 g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
120 G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
121 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
123 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
124 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
125 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
126 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
128 gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
129 g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
130 G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
131 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
133 klass->context = g_main_context_new ();
134 klass->loop = g_main_loop_new (klass->context, TRUE);
136 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
138 klass->thread = g_thread_new ("Bus Thread", (GThreadFunc) do_loop, klass);
140 klass->handle_message = default_handle_message;
141 klass->unprepare = default_unprepare;
145 gst_rtsp_media_init (GstRTSPMedia * media)
147 media->streams = g_ptr_array_new_with_free_func (g_object_unref);
148 g_mutex_init (&media->lock);
149 g_cond_init (&media->cond);
150 g_rec_mutex_init (&media->state_lock);
152 media->shared = DEFAULT_SHARED;
153 media->reusable = DEFAULT_REUSABLE;
154 media->protocols = DEFAULT_PROTOCOLS;
155 media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
156 media->buffer_size = DEFAULT_BUFFER_SIZE;
160 gst_rtsp_media_finalize (GObject * obj)
164 media = GST_RTSP_MEDIA (obj);
166 GST_INFO ("finalize media %p", media);
168 gst_rtsp_media_unprepare (media);
170 g_ptr_array_unref (media->streams);
172 g_list_free_full (media->dynamic, gst_object_unref);
175 g_object_unref (media->auth);
177 g_object_unref (media->pool);
178 g_mutex_clear (&media->lock);
179 g_cond_clear (&media->cond);
180 g_rec_mutex_clear (&media->state_lock);
182 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
186 gst_rtsp_media_get_property (GObject * object, guint propid,
187 GValue * value, GParamSpec * pspec)
189 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
193 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
196 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
199 g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
201 case PROP_EOS_SHUTDOWN:
202 g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
204 case PROP_BUFFER_SIZE:
205 g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
213 gst_rtsp_media_set_property (GObject * object, guint propid,
214 const GValue * value, GParamSpec * pspec)
216 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
220 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
223 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
226 gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
228 case PROP_EOS_SHUTDOWN:
229 gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
231 case PROP_BUFFER_SIZE:
232 gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
235 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
240 do_loop (GstRTSPMediaClass * klass)
242 GST_INFO ("enter mainloop");
243 g_main_loop_run (klass->loop);
244 GST_INFO ("exit mainloop");
249 /* must be called with state lock */
251 collect_media_stats (GstRTSPMedia * media)
253 gint64 position, duration;
255 media->range.unit = GST_RTSP_RANGE_NPT;
257 GST_INFO ("collect media stats");
259 if (media->is_live) {
260 media->range.min.type = GST_RTSP_TIME_NOW;
261 media->range.min.seconds = -1;
262 media->range.max.type = GST_RTSP_TIME_END;
263 media->range.max.seconds = -1;
265 /* get the position */
266 if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME,
268 GST_INFO ("position query failed");
272 /* get the duration */
273 if (!gst_element_query_duration (media->pipeline, GST_FORMAT_TIME,
275 GST_INFO ("duration query failed");
279 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
280 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
282 if (position == -1) {
283 media->range.min.type = GST_RTSP_TIME_NOW;
284 media->range.min.seconds = -1;
286 media->range.min.type = GST_RTSP_TIME_SECONDS;
287 media->range.min.seconds = ((gdouble) position) / GST_SECOND;
289 if (duration == -1) {
290 media->range.max.type = GST_RTSP_TIME_END;
291 media->range.max.seconds = -1;
293 media->range.max.type = GST_RTSP_TIME_SECONDS;
294 media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
300 * gst_rtsp_media_new:
302 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
303 * element to produce RTP data for one or more related (audio/video/..)
306 * Returns: a new #GstRTSPMedia object.
309 gst_rtsp_media_new (void)
311 GstRTSPMedia *result;
313 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
319 * gst_rtsp_media_set_shared:
320 * @media: a #GstRTSPMedia
321 * @shared: the new value
323 * Set or unset if the pipeline for @media can be shared will multiple clients.
324 * When @shared is %TRUE, client requests for this media will share the media
328 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
330 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
332 g_mutex_lock (&media->lock);
333 media->shared = shared;
334 g_mutex_unlock (&media->lock);
338 * gst_rtsp_media_is_shared:
339 * @media: a #GstRTSPMedia
341 * Check if the pipeline for @media can be shared between multiple clients.
343 * Returns: %TRUE if the media can be shared between clients.
346 gst_rtsp_media_is_shared (GstRTSPMedia * media)
350 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
352 g_mutex_lock (&media->lock);
354 g_mutex_unlock (&media->lock);
360 * gst_rtsp_media_set_reusable:
361 * @media: a #GstRTSPMedia
362 * @reusable: the new value
364 * Set or unset if the pipeline for @media can be reused after the pipeline has
368 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
370 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
372 g_mutex_lock (&media->lock);
373 media->reusable = reusable;
374 g_mutex_unlock (&media->lock);
378 * gst_rtsp_media_is_reusable:
379 * @media: a #GstRTSPMedia
381 * Check if the pipeline for @media can be reused after an unprepare.
383 * Returns: %TRUE if the media can be reused
386 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
390 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
392 g_mutex_lock (&media->lock);
393 res = media->reusable;
394 g_mutex_unlock (&media->lock);
400 * gst_rtsp_media_set_protocols:
401 * @media: a #GstRTSPMedia
402 * @protocols: the new flags
404 * Configure the allowed lower transport for @media.
407 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
409 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
411 g_mutex_lock (&media->lock);
412 media->protocols = protocols;
413 g_mutex_unlock (&media->lock);
417 * gst_rtsp_media_get_protocols:
418 * @media: a #GstRTSPMedia
420 * Get the allowed protocols of @media.
422 * Returns: a #GstRTSPLowerTrans
425 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
427 GstRTSPLowerTrans res;
429 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
430 GST_RTSP_LOWER_TRANS_UNKNOWN);
432 g_mutex_lock (&media->lock);
433 res = media->protocols;
434 g_mutex_unlock (&media->lock);
440 * gst_rtsp_media_set_eos_shutdown:
441 * @media: a #GstRTSPMedia
442 * @eos_shutdown: the new value
444 * Set or unset if an EOS event will be sent to the pipeline for @media before
448 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
450 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
452 g_mutex_lock (&media->lock);
453 media->eos_shutdown = eos_shutdown;
454 g_mutex_unlock (&media->lock);
458 * gst_rtsp_media_is_eos_shutdown:
459 * @media: a #GstRTSPMedia
461 * Check if the pipeline for @media will send an EOS down the pipeline before
464 * Returns: %TRUE if the media will send EOS before unpreparing.
467 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
471 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
473 g_mutex_lock (&media->lock);
474 res = media->eos_shutdown;
475 g_mutex_unlock (&media->lock);
481 * gst_rtsp_media_set_buffer_size:
482 * @media: a #GstRTSPMedia
483 * @size: the new value
485 * Set the kernel UDP buffer size.
488 gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
490 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
492 GST_LOG_OBJECT (media, "set buffer size %u", size);
494 g_mutex_lock (&media->lock);
495 media->buffer_size = size;
496 g_mutex_unlock (&media->lock);
500 * gst_rtsp_media_get_buffer_size:
501 * @media: a #GstRTSPMedia
503 * Get the kernel UDP buffer size.
505 * Returns: the kernel UDP buffer size.
508 gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
512 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
514 g_mutex_unlock (&media->lock);
515 res = media->buffer_size;
516 g_mutex_unlock (&media->lock);
522 * gst_rtsp_media_set_auth:
523 * @media: a #GstRTSPMedia
524 * @auth: a #GstRTSPAuth
526 * configure @auth to be used as the authentication manager of @media.
529 gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
533 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
535 GST_LOG_OBJECT (media, "set auth %p", auth);
537 g_mutex_lock (&media->lock);
538 if ((old = media->auth) != auth)
539 media->auth = auth ? g_object_ref (auth) : NULL;
542 g_mutex_unlock (&media->lock);
545 g_object_unref (old);
549 * gst_rtsp_media_get_auth:
550 * @media: a #GstRTSPMedia
552 * Get the #GstRTSPAuth used as the authentication manager of @media.
554 * Returns: (transfer full): the #GstRTSPAuth of @media. g_object_unref() after
558 gst_rtsp_media_get_auth (GstRTSPMedia * media)
562 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
564 g_mutex_lock (&media->lock);
565 if ((result = media->auth))
566 g_object_ref (result);
567 g_mutex_unlock (&media->lock);
573 * gst_rtsp_media_set_address_pool:
574 * @media: a #GstRTSPMedia
575 * @pool: a #GstRTSPAddressPool
577 * configure @pool to be used as the address pool of @media.
580 gst_rtsp_media_set_address_pool (GstRTSPMedia * media,
581 GstRTSPAddressPool * pool)
583 GstRTSPAddressPool *old;
585 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
587 GST_LOG_OBJECT (media, "set address pool %p", pool);
589 g_mutex_lock (&media->lock);
590 if ((old = media->pool) != pool)
591 media->pool = pool ? g_object_ref (pool) : NULL;
594 g_ptr_array_foreach (media->streams, (GFunc) gst_rtsp_stream_set_address_pool,
596 g_mutex_unlock (&media->lock);
599 g_object_unref (old);
603 * gst_rtsp_media_get_address_pool:
604 * @media: a #GstRTSPMedia
606 * Get the #GstRTSPAddressPool used as the address pool of @media.
608 * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after
612 gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
614 GstRTSPAddressPool *result;
616 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
618 g_mutex_lock (&media->lock);
619 if ((result = media->pool))
620 g_object_ref (result);
621 g_mutex_unlock (&media->lock);
627 * gst_rtsp_media_collect_streams:
628 * @media: a #GstRTSPMedia
630 * Find all payloader elements, they should be named pay%d in the
631 * element of @media, and create #GstRTSPStreams for them.
633 * Collect all dynamic elements, named dynpay%d, and add them to
634 * the list of dynamic elements.
637 gst_rtsp_media_collect_streams (GstRTSPMedia * media)
639 GstElement *element, *elem;
644 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
646 element = media->element;
649 for (i = 0; have_elem; i++) {
654 name = g_strdup_printf ("pay%d", i);
655 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
656 GST_INFO ("found stream %d with payloader %p", i, elem);
658 /* take the pad of the payloader */
659 pad = gst_element_get_static_pad (elem, "src");
660 /* create the stream */
661 gst_rtsp_media_create_stream (media, elem, pad);
662 g_object_unref (pad);
664 gst_object_unref (elem);
670 name = g_strdup_printf ("dynpay%d", i);
671 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
672 /* a stream that will dynamically create pads to provide RTP packets */
674 GST_INFO ("found dynamic element %d, %p", i, elem);
676 g_mutex_lock (&media->lock);
677 media->dynamic = g_list_prepend (media->dynamic, elem);
678 g_mutex_unlock (&media->lock);
687 * gst_rtsp_media_create_stream:
688 * @media: a #GstRTSPMedia
689 * @payloader: a #GstElement
690 * @srcpad: a source #GstPad
692 * Create a new stream in @media that provides RTP data on @srcpad.
693 * @srcpad should be a pad of an element inside @media->element.
695 * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long
699 gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
702 GstRTSPStream *stream;
707 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
708 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
709 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
710 g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
712 g_mutex_lock (&media->lock);
713 idx = media->streams->len;
715 name = g_strdup_printf ("src_%u", idx);
716 srcpad = gst_ghost_pad_new (name, pad);
717 gst_pad_set_active (srcpad, TRUE);
718 gst_element_add_pad (media->element, srcpad);
721 stream = gst_rtsp_stream_new (idx, payloader, srcpad);
723 gst_rtsp_stream_set_address_pool (stream, media->pool);
725 g_ptr_array_add (media->streams, stream);
726 g_mutex_unlock (&media->lock);
728 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream,
735 * gst_rtsp_media_n_streams:
736 * @media: a #GstRTSPMedia
738 * Get the number of streams in this media.
740 * Returns: The number of streams.
743 gst_rtsp_media_n_streams (GstRTSPMedia * media)
747 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
749 g_mutex_lock (&media->lock);
750 res = media->streams->len;
751 g_mutex_unlock (&media->lock);
757 * gst_rtsp_media_get_stream:
758 * @media: a #GstRTSPMedia
759 * @idx: the stream index
761 * Retrieve the stream with index @idx from @media.
763 * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with
764 * that index did not exist.
767 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
771 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
773 g_mutex_lock (&media->lock);
774 if (idx < media->streams->len)
775 res = g_ptr_array_index (media->streams, idx);
778 g_mutex_unlock (&media->lock);
784 * gst_rtsp_media_get_range_string:
785 * @media: a #GstRTSPMedia
786 * @play: for the PLAY request
788 * Get the current range as a string.
790 * Returns: The range as a string, g_free() after usage.
793 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
796 GstRTSPTimeRange range;
798 g_mutex_lock (&media->lock);
800 range = media->range;
802 if (!play && media->n_active > 0) {
803 range.min.type = GST_RTSP_TIME_NOW;
804 range.min.seconds = -1;
806 g_mutex_unlock (&media->lock);
808 result = gst_rtsp_range_to_string (&range);
814 * gst_rtsp_media_seek:
815 * @media: a #GstRTSPMedia
816 * @range: a #GstRTSPTimeRange
818 * Seek the pipeline to @range.
820 * Returns: %TRUE on success.
823 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
828 GstSeekType start_type, stop_type;
830 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
831 g_return_val_if_fail (range != NULL, FALSE);
833 g_rec_mutex_lock (&media->state_lock);
834 if (!media->seekable)
837 if (range->unit != GST_RTSP_RANGE_NPT)
840 /* depends on the current playing state of the pipeline. We might need to
841 * queue this until we get EOS. */
842 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
844 start_type = stop_type = GST_SEEK_TYPE_NONE;
846 switch (range->min.type) {
847 case GST_RTSP_TIME_NOW:
850 case GST_RTSP_TIME_SECONDS:
851 /* only seek when something changed */
852 if (media->range.min.seconds == range->min.seconds) {
855 start = range->min.seconds * GST_SECOND;
856 start_type = GST_SEEK_TYPE_SET;
859 case GST_RTSP_TIME_END:
863 switch (range->max.type) {
864 case GST_RTSP_TIME_SECONDS:
865 /* only seek when something changed */
866 if (media->range.max.seconds == range->max.seconds) {
869 stop = range->max.seconds * GST_SECOND;
870 stop_type = GST_SEEK_TYPE_SET;
873 case GST_RTSP_TIME_END:
875 stop_type = GST_SEEK_TYPE_SET;
877 case GST_RTSP_TIME_NOW:
882 if (start != -1 || stop != -1) {
883 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
884 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
886 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
887 flags, start_type, start, stop_type, stop);
889 /* and block for the seek to complete */
890 GST_INFO ("done seeking %d", res);
891 gst_element_get_state (media->pipeline, NULL, NULL, -1);
892 GST_INFO ("prerolled again");
894 collect_media_stats (media);
896 GST_INFO ("no seek needed");
899 g_rec_mutex_unlock (&media->state_lock);
906 g_rec_mutex_unlock (&media->state_lock);
907 GST_INFO ("pipeline is not seekable");
912 g_rec_mutex_unlock (&media->state_lock);
913 GST_WARNING ("seek unit %d not supported", range->unit);
918 g_rec_mutex_unlock (&media->state_lock);
919 GST_WARNING ("weird range type %d not supported", range->min.type);
925 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
927 g_mutex_lock (&media->lock);
928 /* never overwrite the error status */
929 if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
930 media->status = status;
931 GST_DEBUG ("setting new status to %d", status);
932 g_cond_broadcast (&media->cond);
933 g_mutex_unlock (&media->lock);
936 static GstRTSPMediaStatus
937 gst_rtsp_media_get_status (GstRTSPMedia * media)
939 GstRTSPMediaStatus result;
942 g_mutex_lock (&media->lock);
943 end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND;
944 /* while we are preparing, wait */
945 while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
946 GST_DEBUG ("waiting for status change");
947 if (!g_cond_wait_until (&media->cond, &media->lock, end_time)) {
948 GST_DEBUG ("timeout, assuming error status");
949 media->status = GST_RTSP_MEDIA_STATUS_ERROR;
952 /* could be success or error */
953 result = media->status;
954 GST_DEBUG ("got status %d", result);
955 g_mutex_unlock (&media->lock);
960 /* called with state-lock */
962 default_handle_message (GstRTSPMedia * media, GstMessage * message)
966 type = GST_MESSAGE_TYPE (message);
969 case GST_MESSAGE_STATE_CHANGED:
971 case GST_MESSAGE_BUFFERING:
975 gst_message_parse_buffering (message, &percent);
977 /* no state management needed for live pipelines */
981 if (percent == 100) {
982 /* a 100% message means buffering is done */
983 media->buffering = FALSE;
984 /* if the desired state is playing, go back */
985 if (media->target_state == GST_STATE_PLAYING) {
986 GST_INFO ("Buffering done, setting pipeline to PLAYING");
987 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
989 GST_INFO ("Buffering done");
993 if (media->buffering == FALSE) {
994 if (media->target_state == GST_STATE_PLAYING) {
995 /* we were not buffering but PLAYING, PAUSE the pipeline. */
996 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
997 gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
999 GST_INFO ("Buffering ...");
1002 media->buffering = TRUE;
1006 case GST_MESSAGE_LATENCY:
1008 gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
1011 case GST_MESSAGE_ERROR:
1016 gst_message_parse_error (message, &gerror, &debug);
1017 GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1018 g_error_free (gerror);
1021 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1024 case GST_MESSAGE_WARNING:
1029 gst_message_parse_warning (message, &gerror, &debug);
1030 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1031 g_error_free (gerror);
1035 case GST_MESSAGE_ELEMENT:
1037 case GST_MESSAGE_STREAM_STATUS:
1039 case GST_MESSAGE_ASYNC_DONE:
1040 if (!media->adding) {
1041 /* when we are dynamically adding pads, the addition of the udpsrc will
1042 * temporarily produce ASYNC_DONE messages. We have to ignore them and
1043 * wait for the final ASYNC_DONE after everything prerolled */
1044 GST_INFO ("%p: got ASYNC_DONE", media);
1045 collect_media_stats (media);
1047 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1049 GST_INFO ("%p: ignoring ASYNC_DONE", media);
1052 case GST_MESSAGE_EOS:
1053 GST_INFO ("%p: got EOS", media);
1055 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) {
1056 GST_DEBUG ("shutting down after EOS");
1057 finish_unprepare (media);
1058 g_object_unref (media);
1062 GST_INFO ("%p: got message type %s", media,
1063 gst_message_type_get_name (type));
1070 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1072 GstRTSPMediaClass *klass;
1075 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1077 g_rec_mutex_lock (&media->state_lock);
1078 if (klass->handle_message)
1079 ret = klass->handle_message (media, message);
1082 g_rec_mutex_unlock (&media->state_lock);
1088 watch_destroyed (GstRTSPMedia * media)
1090 GST_DEBUG_OBJECT (media, "source destroyed");
1091 gst_object_unref (media);
1094 /* called from streaming threads */
1096 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1098 GstRTSPStream *stream;
1100 /* FIXME, element is likely not a payloader, find the payloader here */
1101 stream = gst_rtsp_media_create_stream (media, element, pad);
1103 GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad),
1106 g_rec_mutex_lock (&media->state_lock);
1107 /* we will be adding elements below that will cause ASYNC_DONE to be
1108 * posted in the bus. We want to ignore those messages until the
1109 * pipeline really prerolled. */
1110 media->adding = TRUE;
1112 /* join the element in the PAUSED state because this callback is
1113 * called from the streaming thread and it is PAUSED */
1114 gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline),
1115 media->rtpbin, GST_STATE_PAUSED);
1117 media->adding = FALSE;
1118 g_rec_mutex_unlock (&media->state_lock);
1122 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1124 GstElement *fakesink;
1126 g_mutex_lock (&media->lock);
1127 GST_INFO ("no more pads");
1128 if ((fakesink = media->fakesink)) {
1129 gst_object_ref (fakesink);
1130 media->fakesink = NULL;
1131 g_mutex_unlock (&media->lock);
1133 gst_bin_remove (GST_BIN (media->pipeline), fakesink);
1134 gst_element_set_state (fakesink, GST_STATE_NULL);
1135 gst_object_unref (fakesink);
1136 GST_INFO ("removed fakesink");
1141 * gst_rtsp_media_prepare:
1142 * @media: a #GstRTSPMedia
1144 * Prepare @media for streaming. This function will create the pipeline and
1145 * other objects to manage the streaming.
1147 * It will preroll the pipeline and collect vital information about the streams
1148 * such as the duration.
1150 * Returns: %TRUE on success.
1153 gst_rtsp_media_prepare (GstRTSPMedia * media)
1155 GstStateChangeReturn ret;
1156 GstRTSPMediaStatus status;
1158 GstRTSPMediaClass *klass;
1162 g_rec_mutex_lock (&media->state_lock);
1163 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1166 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARING)
1169 if (media->status != GST_RTSP_MEDIA_STATUS_UNPREPARED)
1170 goto not_unprepared;
1172 if (!media->reusable && media->reused)
1175 media->rtpbin = gst_element_factory_make ("rtpbin", NULL);
1176 if (media->rtpbin == NULL)
1179 GST_INFO ("preparing media %p", media);
1181 /* reset some variables */
1182 media->is_live = FALSE;
1183 media->seekable = FALSE;
1184 media->buffering = FALSE;
1185 /* we're preparing now */
1186 media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1188 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
1190 /* add the pipeline bus to our custom mainloop */
1191 media->source = gst_bus_create_watch (bus);
1192 gst_object_unref (bus);
1194 g_source_set_callback (media->source, (GSourceFunc) bus_message,
1195 gst_object_ref (media), (GDestroyNotify) watch_destroyed);
1197 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1198 media->id = g_source_attach (media->source, klass->context);
1200 /* add stuff to the bin */
1201 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
1203 /* link streams we already have, other streams might appear when we have
1204 * dynamic elements */
1205 for (i = 0; i < media->streams->len; i++) {
1206 GstRTSPStream *stream;
1208 stream = g_ptr_array_index (media->streams, i);
1210 gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline),
1211 media->rtpbin, GST_STATE_NULL);
1214 for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
1215 GstElement *elem = walk->data;
1217 GST_INFO ("adding callbacks for dynamic element %p", elem);
1219 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1220 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1222 /* we add a fakesink here in order to make the state change async. We remove
1223 * the fakesink again in the no-more-pads callback. */
1224 media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1225 gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
1228 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1229 /* first go to PAUSED */
1230 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1231 media->target_state = GST_STATE_PAUSED;
1234 case GST_STATE_CHANGE_SUCCESS:
1235 GST_INFO ("SUCCESS state change for media %p", media);
1236 media->seekable = TRUE;
1238 case GST_STATE_CHANGE_ASYNC:
1239 GST_INFO ("ASYNC state change for media %p", media);
1240 media->seekable = TRUE;
1242 case GST_STATE_CHANGE_NO_PREROLL:
1243 /* we need to go to PLAYING */
1244 GST_INFO ("NO_PREROLL state change: live media %p", media);
1245 /* FIXME we disable seeking for live streams for now. We should perform a
1246 * seeking query in preroll instead */
1247 media->seekable = FALSE;
1248 media->is_live = TRUE;
1249 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1250 if (ret == GST_STATE_CHANGE_FAILURE)
1253 case GST_STATE_CHANGE_FAILURE:
1257 g_rec_mutex_unlock (&media->state_lock);
1259 /* now wait for all pads to be prerolled, FIXME, we should somehow be
1260 * able to do this async so that we don't block the server thread. */
1261 status = gst_rtsp_media_get_status (media);
1262 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1265 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1267 GST_INFO ("object %p is prerolled", media);
1274 GST_LOG ("media %p was prepared", media);
1275 g_rec_mutex_unlock (&media->state_lock);
1281 GST_WARNING ("media %p was not unprepared", media);
1282 g_rec_mutex_unlock (&media->state_lock);
1287 g_rec_mutex_unlock (&media->state_lock);
1288 GST_WARNING ("can not reuse media %p", media);
1293 g_rec_mutex_unlock (&media->state_lock);
1294 GST_WARNING ("no rtpbin element");
1295 g_warning ("failed to create element 'rtpbin', check your installation");
1300 GST_WARNING ("failed to preroll pipeline");
1301 gst_rtsp_media_unprepare (media);
1302 g_rec_mutex_unlock (&media->state_lock);
1307 /* must be called with state-lock */
1309 finish_unprepare (GstRTSPMedia * media)
1313 GST_DEBUG ("shutting down");
1315 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1317 for (i = 0; i < media->streams->len; i++) {
1318 GstRTSPStream *stream;
1320 GST_INFO ("Removing elements of stream %d from pipeline", i);
1322 stream = g_ptr_array_index (media->streams, i);
1324 gst_rtsp_stream_leave_bin (stream, GST_BIN (media->pipeline),
1327 g_ptr_array_set_size (media->streams, 0);
1329 gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
1330 media->rtpbin = NULL;
1332 gst_object_unref (media->pipeline);
1333 media->pipeline = NULL;
1335 media->reused = TRUE;
1336 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1338 if (media->source) {
1339 g_source_destroy (media->source);
1340 g_source_unref (media->source);
1341 media->source = NULL;
1344 /* when the media is not reusable, this will effectively unref the media and
1346 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1349 /* called with state-lock */
1351 default_unprepare (GstRTSPMedia * media)
1353 if (media->eos_shutdown) {
1354 GST_DEBUG ("sending EOS for shutdown");
1355 /* ref so that we don't disappear */
1356 g_object_ref (media);
1357 gst_element_send_event (media->pipeline, gst_event_new_eos ());
1358 /* we need to go to playing again for the EOS to propagate, normally in this
1359 * state, nothing is receiving data from us anymore so this is ok. */
1360 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1361 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARING;
1363 finish_unprepare (media);
1369 * gst_rtsp_media_unprepare:
1370 * @media: a #GstRTSPMedia
1372 * Unprepare @media. After this call, the media should be prepared again before
1373 * it can be used again. If the media is set to be non-reusable, a new instance
1376 * Returns: %TRUE on success.
1379 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1383 g_rec_mutex_lock (&media->state_lock);
1384 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1385 goto was_unprepared;
1387 GST_INFO ("unprepare media %p", media);
1388 media->target_state = GST_STATE_NULL;
1391 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
1392 GstRTSPMediaClass *klass;
1394 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1395 if (klass->unprepare)
1396 success = klass->unprepare (media);
1398 finish_unprepare (media);
1400 g_rec_mutex_unlock (&media->state_lock);
1406 g_rec_mutex_unlock (&media->state_lock);
1407 GST_INFO ("media %p was already unprepared", media);
1413 * gst_rtsp_media_set_state:
1414 * @media: a #GstRTSPMedia
1415 * @state: the target state of the media
1416 * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers
1418 * Set the state of @media to @state and for the transports in @transports.
1420 * Returns: %TRUE on success.
1423 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1424 GPtrArray * transports)
1427 gboolean add, remove, do_state;
1430 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1431 g_return_val_if_fail (transports != NULL, FALSE);
1433 g_rec_mutex_lock (&media->state_lock);
1435 /* NULL and READY are the same */
1436 if (state == GST_STATE_READY)
1437 state = GST_STATE_NULL;
1439 add = remove = FALSE;
1441 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1445 case GST_STATE_NULL:
1446 case GST_STATE_PAUSED:
1447 /* we're going from PLAYING to PAUSED, READY or NULL, remove */
1448 if (media->target_state == GST_STATE_PLAYING)
1451 case GST_STATE_PLAYING:
1452 /* we're going to PLAYING, add */
1458 old_active = media->n_active;
1460 for (i = 0; i < transports->len; i++) {
1461 GstRTSPStreamTransport *trans;
1463 /* we need a non-NULL entry in the array */
1464 trans = g_ptr_array_index (transports, i);
1468 /* we need a transport */
1469 if (!trans->transport)
1473 if (gst_rtsp_stream_add_transport (trans->stream, trans))
1475 } else if (remove) {
1476 if (gst_rtsp_stream_remove_transport (trans->stream, trans))
1481 /* we just added the first media, do the playing state change */
1482 if (old_active == 0 && add)
1484 /* if we have no more active media, do the downward state changes */
1485 else if (media->n_active == 0)
1490 GST_INFO ("state %d active %d media %p do_state %d", state, media->n_active,
1493 if (media->target_state != state) {
1495 if (state == GST_STATE_NULL) {
1496 gst_rtsp_media_unprepare (media);
1498 GST_INFO ("state %s media %p", gst_element_state_get_name (state),
1500 media->target_state = state;
1501 gst_element_set_state (media->pipeline, state);
1504 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
1508 /* remember where we are */
1509 if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED ||
1510 old_active != media->n_active))
1511 collect_media_stats (media);
1513 g_rec_mutex_unlock (&media->state_lock);