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.
20 #include "rtsp-media-factory.h"
22 #define DEFAULT_LAUNCH NULL
23 #define DEFAULT_SHARED FALSE
24 #define DEFAULT_EOS_SHUTDOWN FALSE
25 #define DEFAULT_BUFFER_SIZE 0x80000
39 SIGNAL_MEDIA_CONSTRUCTED,
43 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
44 #define GST_CAT_DEFAULT rtsp_media_debug
46 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
48 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
49 GValue * value, GParamSpec * pspec);
50 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
51 const GValue * value, GParamSpec * pspec);
52 static void gst_rtsp_media_factory_finalize (GObject * obj);
54 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
55 const GstRTSPUrl * url);
56 static GstElement *default_get_element (GstRTSPMediaFactory * factory,
57 const GstRTSPUrl * url);
58 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
59 const GstRTSPUrl * url);
60 static void default_configure (GstRTSPMediaFactory * factory,
61 GstRTSPMedia * media);
62 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
63 GstRTSPMedia * media);
65 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
68 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
70 GObjectClass *gobject_class;
72 gobject_class = G_OBJECT_CLASS (klass);
74 gobject_class->get_property = gst_rtsp_media_factory_get_property;
75 gobject_class->set_property = gst_rtsp_media_factory_set_property;
76 gobject_class->finalize = gst_rtsp_media_factory_finalize;
79 * GstRTSPMediaFactory::launch
81 * The gst_parse_launch() line to use for constructing the pipeline in the
82 * default prepare vmethod.
84 * The pipeline description should return a GstBin as the toplevel element
85 * which can be accomplished by enclosing the dscription with brackets '('
88 * The description should return a pipeline with payloaders named pay0, pay1,
89 * etc.. Each of the payloaders will result in a stream.
91 * Support for dynamic payloaders can be accomplished by adding payloaders
92 * named dynpay0, dynpay1, etc..
94 g_object_class_install_property (gobject_class, PROP_LAUNCH,
95 g_param_spec_string ("launch", "Launch",
96 "A launch description of the pipeline", DEFAULT_LAUNCH,
97 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
99 g_object_class_install_property (gobject_class, PROP_SHARED,
100 g_param_spec_boolean ("shared", "Shared",
101 "If media from this factory is shared", DEFAULT_SHARED,
102 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
104 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
105 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
106 "Send EOS down the pipeline before shutting down",
107 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
110 g_param_spec_uint ("buffer-size", "Buffer Size",
111 "The kernel UDP buffer size to use", 0, G_MAXUINT,
112 DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
115 g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
116 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
117 media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
118 G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
120 klass->gen_key = default_gen_key;
121 klass->get_element = default_get_element;
122 klass->construct = default_construct;
123 klass->configure = default_configure;
124 klass->create_pipeline = default_create_pipeline;
126 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
127 "GstRTSPMediaFactory");
131 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
133 factory->launch = g_strdup (DEFAULT_LAUNCH);
134 factory->shared = DEFAULT_SHARED;
135 factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
136 factory->buffer_size = DEFAULT_BUFFER_SIZE;
138 factory->lock = g_mutex_new ();
139 factory->medias_lock = g_mutex_new ();
140 factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
141 g_free, g_object_unref);
145 gst_rtsp_media_factory_finalize (GObject * obj)
147 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
149 g_hash_table_unref (factory->medias);
150 g_mutex_free (factory->medias_lock);
151 g_free (factory->launch);
152 g_mutex_free (factory->lock);
154 g_object_unref (factory->auth);
156 G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
160 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
161 GValue * value, GParamSpec * pspec)
163 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
167 g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
170 g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
172 case PROP_EOS_SHUTDOWN:
173 g_value_set_boolean (value,
174 gst_rtsp_media_factory_is_eos_shutdown (factory));
176 case PROP_BUFFER_SIZE:
177 g_value_set_uint (value,
178 gst_rtsp_media_factory_get_buffer_size (factory));
181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
186 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
187 const GValue * value, GParamSpec * pspec)
189 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
193 gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
196 gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
198 case PROP_EOS_SHUTDOWN:
199 gst_rtsp_media_factory_set_eos_shutdown (factory,
200 g_value_get_boolean (value));
202 case PROP_BUFFER_SIZE:
203 gst_rtsp_media_factory_set_buffer_size (factory,
204 g_value_get_uint (value));
207 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
212 * gst_rtsp_media_factory_new:
214 * Create a new #GstRTSPMediaFactory instance.
216 * Returns: a new #GstRTSPMediaFactory object.
218 GstRTSPMediaFactory *
219 gst_rtsp_media_factory_new (void)
221 GstRTSPMediaFactory *result;
223 result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
229 * gst_rtsp_media_factory_set_launch:
230 * @factory: a #GstRTSPMediaFactory
231 * @launch: the launch description
234 * The gst_parse_launch() line to use for constructing the pipeline in the
235 * default prepare vmethod.
237 * The pipeline description should return a GstBin as the toplevel element
238 * which can be accomplished by enclosing the dscription with brackets '('
241 * The description should return a pipeline with payloaders named pay0, pay1,
242 * etc.. Each of the payloaders will result in a stream.
245 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
246 const gchar * launch)
248 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
249 g_return_if_fail (launch != NULL);
251 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
252 g_free (factory->launch);
253 factory->launch = g_strdup (launch);
254 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
258 * gst_rtsp_media_factory_get_launch:
259 * @factory: a #GstRTSPMediaFactory
261 * Get the gst_parse_launch() pipeline description that will be used in the
262 * default prepare vmethod.
264 * Returns: the configured launch description. g_free() after usage.
267 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
271 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
273 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
274 result = g_strdup (factory->launch);
275 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
281 * gst_rtsp_media_factory_set_shared:
282 * @factory: a #GstRTSPMediaFactory
283 * @shared: the new value
285 * Configure if media created from this factory can be shared between clients.
288 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
291 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
293 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
294 factory->shared = shared;
295 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
299 * gst_rtsp_media_factory_is_shared:
300 * @factory: a #GstRTSPMediaFactory
302 * Get if media created from this factory can be shared between clients.
304 * Returns: %TRUE if the media will be shared between clients.
307 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
311 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
313 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
314 result = factory->shared;
315 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
321 * gst_rtsp_media_factory_set_eos_shutdown:
322 * @factory: a #GstRTSPMediaFactory
323 * @eos_shutdown: the new value
325 * Configure if media created from this factory will have an EOS sent to the
326 * pipeline before shutdown.
329 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
330 gboolean eos_shutdown)
332 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
334 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
335 factory->eos_shutdown = eos_shutdown;
336 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
340 * gst_rtsp_media_factory_is_eos_shutdown:
341 * @factory: a #GstRTSPMediaFactory
343 * Get if media created from this factory will have an EOS event sent to the
344 * pipeline before shutdown.
346 * Returns: %TRUE if the media will receive EOS before shutdown.
349 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
353 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
355 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
356 result = factory->eos_shutdown;
357 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
363 * gst_rtsp_media_factory_set_buffer_size:
364 * @factory: a #GstRTSPMedia
365 * @size: the new value
367 * Set the kernel UDP buffer size.
370 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
373 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
375 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
376 factory->buffer_size = size;
377 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
381 * gst_rtsp_media_factory_get_buffer_size:
382 * @factory: a #GstRTSPMedia
384 * Get the kernel UDP buffer size.
386 * Returns: the kernel UDP buffer size.
389 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
393 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
395 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
396 result = factory->buffer_size;
397 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
403 * gst_rtsp_media_factory_set_auth:
404 * @factory: a #GstRTSPMediaFactory
405 * @auth: a #GstRTSPAuth
407 * configure @auth to be used as the authentication manager of @factory.
410 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
415 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
422 factory->auth = auth;
424 g_object_unref (old);
429 * gst_rtsp_media_factory_get_auth:
430 * @factory: a #GstRTSPMediaFactory
432 * Get the #GstRTSPAuth used as the authentication manager of @factory.
434 * Returns: the #GstRTSPAuth of @factory. g_object_unref() after
438 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
442 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
444 if ((result = factory->auth))
445 g_object_ref (result);
451 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
453 return (media1 == media2);
457 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
459 g_mutex_lock (factory->medias_lock);
460 g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
461 g_mutex_unlock (factory->medias_lock);
465 * gst_rtsp_media_factory_construct:
466 * @factory: a #GstRTSPMediaFactory
469 * Prepare the media object and create its streams. Implementations
470 * should create the needed gstreamer elements and add them to the result
471 * object. No state changes should be performed on them yet.
473 * One or more GstRTSPMediaStream objects should be added to the result with
474 * the srcpad member set to a source pad that produces buffer of type
477 * Returns: a new #GstRTSPMedia if the media could be prepared.
480 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
481 const GstRTSPUrl * url)
485 GstRTSPMediaFactoryClass *klass;
487 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
489 /* convert the url to a key for the hashtable. NULL return or a NULL function
490 * will not cache anything for this factory. */
492 key = klass->gen_key (factory, url);
496 g_mutex_lock (factory->medias_lock);
498 /* we have a key, see if we find a cached media */
499 media = g_hash_table_lookup (factory->medias, key);
501 g_object_ref (media);
506 /* nothing cached found, try to create one */
507 if (klass->construct) {
508 media = klass->construct (factory, url);
510 g_signal_emit (factory,
511 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
517 /* configure the media */
518 if (klass->configure)
519 klass->configure (factory, media);
521 /* check if we can cache this media */
522 if (gst_rtsp_media_is_shared (media)) {
523 /* insert in the hashtable, takes ownership of the key */
524 g_object_ref (media);
525 g_hash_table_insert (factory->medias, key, media);
528 if (!gst_rtsp_media_is_reusable (media)) {
529 /* when not reusable, connect to the unprepare signal to remove the item
530 * from our cache when it gets unprepared */
531 g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
536 g_mutex_unlock (factory->medias_lock);
541 GST_INFO ("constructed media %p for url %s", media, url->abspath);
547 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
550 const gchar *pre_query;
553 pre_query = url->query ? "?" : "";
554 query = url->query ? url->query : "";
557 g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
563 default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
566 GError *error = NULL;
568 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
569 /* we need a parse syntax */
570 if (factory->launch == NULL)
573 /* parse the user provided launch line */
574 element = gst_parse_launch (factory->launch, &error);
578 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
581 /* a recoverable error was encountered */
582 GST_WARNING ("recoverable parsing error: %s", error->message);
583 g_error_free (error);
590 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
591 g_critical ("no launch line specified");
596 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
597 g_critical ("could not parse launch syntax (%s): %s", factory->launch,
598 (error ? error->message : "unknown reason"));
600 g_error_free (error);
605 /* try to find all the payloader elements, they should be named 'pay%d'. for
606 * each of the payloaders we will create a stream and collect the source pad. */
608 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
609 const GstRTSPUrl * url, GstRTSPMedia * media)
611 GstElement *element, *elem;
614 GstRTSPMediaStream *stream;
617 element = media->element;
620 for (i = 0; have_elem; i++) {
625 name = g_strdup_printf ("pay%d", i);
626 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
627 /* create the stream */
628 stream = g_new0 (GstRTSPMediaStream, 1);
629 stream->payloader = elem;
631 GST_INFO ("found stream %d with payloader %p", i, elem);
633 pad = gst_element_get_static_pad (elem, "src");
635 /* ghost the pad of the payloader to the element */
636 stream->srcpad = gst_ghost_pad_new (name, pad);
637 gst_pad_set_active (stream->srcpad, TRUE);
638 gst_element_add_pad (media->element, stream->srcpad);
639 gst_object_unref (elem);
642 g_array_append_val (media->streams, stream);
647 name = g_strdup_printf ("dynpay%d", i);
648 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
649 /* a stream that will dynamically create pads to provide RTP packets */
651 GST_INFO ("found dynamic element %d, %p", i, elem);
653 media->dynamic = g_list_prepend (media->dynamic, elem);
661 static GstRTSPMedia *
662 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
666 GstRTSPMediaFactoryClass *klass;
668 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
670 if (!klass->create_pipeline)
673 if (klass->get_element)
674 element = klass->get_element (factory, url);
680 /* create a new empty media */
681 media = gst_rtsp_media_new ();
682 media->element = element;
684 media->pipeline = klass->create_pipeline (factory, media);
685 if (media->pipeline == NULL)
688 gst_rtsp_media_factory_collect_streams (factory, url, media);
695 g_critical ("no create_pipeline function");
700 g_critical ("could not create element");
705 g_critical ("can't create pipeline");
706 g_object_unref (media);
712 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
714 GstElement *pipeline;
716 if (media->element == NULL)
719 pipeline = gst_pipeline_new ("media-pipeline");
720 gst_bin_add (GST_BIN_CAST (pipeline), media->element);
727 g_critical ("no element");
733 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
735 gboolean shared, eos_shutdown;
739 /* configure the sharedness */
740 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
741 shared = factory->shared;
742 eos_shutdown = factory->eos_shutdown;
743 size = factory->buffer_size;
744 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
746 gst_rtsp_media_set_shared (media, shared);
747 gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
748 gst_rtsp_media_set_buffer_size (media, size);
750 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
751 gst_rtsp_media_set_auth (media, auth);
752 g_object_unref (auth);