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
35 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
36 #define GST_CAT_DEFAULT rtsp_media_debug
38 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
39 GValue * value, GParamSpec * pspec);
40 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
41 const GValue * value, GParamSpec * pspec);
42 static void gst_rtsp_media_factory_finalize (GObject * obj);
44 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
45 const GstRTSPUrl * url);
46 static GstElement *default_get_element (GstRTSPMediaFactory * factory,
47 const GstRTSPUrl * url);
48 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
49 const GstRTSPUrl * url);
50 static void default_configure (GstRTSPMediaFactory * factory,
51 GstRTSPMedia * media);
52 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
53 GstRTSPMedia * media);
55 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
58 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
60 GObjectClass *gobject_class;
62 gobject_class = G_OBJECT_CLASS (klass);
64 gobject_class->get_property = gst_rtsp_media_factory_get_property;
65 gobject_class->set_property = gst_rtsp_media_factory_set_property;
66 gobject_class->finalize = gst_rtsp_media_factory_finalize;
69 * GstRTSPMediaFactory::launch
71 * The gst_parse_launch() line to use for constructing the pipeline in the
72 * default prepare vmethod.
74 * The pipeline description should return a GstBin as the toplevel element
75 * which can be accomplished by enclosing the dscription with brackets '('
78 * The description should return a pipeline with payloaders named pay0, pay1,
79 * etc.. Each of the payloaders will result in a stream.
81 * Support for dynamic payloaders can be accomplished by adding payloaders
82 * named dynpay0, dynpay1, etc..
84 g_object_class_install_property (gobject_class, PROP_LAUNCH,
85 g_param_spec_string ("launch", "Launch",
86 "A launch description of the pipeline", DEFAULT_LAUNCH,
87 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
89 g_object_class_install_property (gobject_class, PROP_SHARED,
90 g_param_spec_boolean ("shared", "Shared",
91 "If media from this factory is shared", DEFAULT_SHARED,
92 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
94 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
95 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
96 "Send EOS down the pipeline before shutting down",
97 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
99 klass->gen_key = default_gen_key;
100 klass->get_element = default_get_element;
101 klass->construct = default_construct;
102 klass->configure = default_configure;
103 klass->create_pipeline = default_create_pipeline;
105 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
106 "GstRTSPMediaFactory");
110 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
112 factory->launch = g_strdup (DEFAULT_LAUNCH);
113 factory->shared = DEFAULT_SHARED;
114 factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
116 factory->lock = g_mutex_new ();
117 factory->medias_lock = g_mutex_new ();
118 factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
119 g_free, g_object_unref);
123 gst_rtsp_media_factory_finalize (GObject * obj)
125 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
127 g_hash_table_unref (factory->medias);
128 g_mutex_free (factory->medias_lock);
129 g_free (factory->launch);
130 g_mutex_free (factory->lock);
132 g_object_unref (factory->auth);
134 G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
138 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
139 GValue * value, GParamSpec * pspec)
141 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
145 g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
148 g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
150 case PROP_EOS_SHUTDOWN:
151 g_value_set_boolean (value,
152 gst_rtsp_media_factory_is_eos_shutdown (factory));
155 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
160 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
161 const GValue * value, GParamSpec * pspec)
163 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
167 gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
170 gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
172 case PROP_EOS_SHUTDOWN:
173 gst_rtsp_media_factory_set_eos_shutdown (factory,
174 g_value_get_boolean (value));
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
182 * gst_rtsp_media_factory_new:
184 * Create a new #GstRTSPMediaFactory instance.
186 * Returns: a new #GstRTSPMediaFactory object.
188 GstRTSPMediaFactory *
189 gst_rtsp_media_factory_new (void)
191 GstRTSPMediaFactory *result;
193 result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
199 * gst_rtsp_media_factory_set_launch:
200 * @factory: a #GstRTSPMediaFactory
201 * @launch: the launch description
204 * The gst_parse_launch() line to use for constructing the pipeline in the
205 * default prepare vmethod.
207 * The pipeline description should return a GstBin as the toplevel element
208 * which can be accomplished by enclosing the dscription with brackets '('
211 * The description should return a pipeline with payloaders named pay0, pay1,
212 * etc.. Each of the payloaders will result in a stream.
215 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
216 const gchar * launch)
218 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
219 g_return_if_fail (launch != NULL);
221 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
222 g_free (factory->launch);
223 factory->launch = g_strdup (launch);
224 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
228 * gst_rtsp_media_factory_get_launch:
229 * @factory: a #GstRTSPMediaFactory
231 * Get the gst_parse_launch() pipeline description that will be used in the
232 * default prepare vmethod.
234 * Returns: the configured launch description. g_free() after usage.
237 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
241 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
243 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
244 result = g_strdup (factory->launch);
245 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
251 * gst_rtsp_media_factory_set_shared:
252 * @factory: a #GstRTSPMediaFactory
253 * @shared: the new value
255 * Configure if media created from this factory can be shared between clients.
258 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
261 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
263 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
264 factory->shared = shared;
265 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
269 * gst_rtsp_media_factory_is_shared:
270 * @factory: a #GstRTSPMediaFactory
272 * Get if media created from this factory can be shared between clients.
274 * Returns: %TRUE if the media will be shared between clients.
277 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
281 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
283 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
284 result = factory->shared;
285 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
291 * gst_rtsp_media_factory_set_eos_shutdown:
292 * @factory: a #GstRTSPMediaFactory
293 * @eos_shutdown: the new value
295 * Configure if media created from this factory will have an EOS sent to the
296 * pipeline before shutdown.
299 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
300 gboolean eos_shutdown)
302 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
304 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
305 factory->eos_shutdown = eos_shutdown;
306 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
310 * gst_rtsp_media_factory_is_eos_shutdown:
311 * @factory: a #GstRTSPMediaFactory
313 * Get if media created from this factory will have an EOS event sent to the
314 * pipeline before shutdown.
316 * Returns: %TRUE if the media will receive EOS before shutdown.
319 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
323 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
325 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
326 result = factory->eos_shutdown;
327 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
333 * gst_rtsp_media_factory_set_auth:
334 * @factory: a #GstRTSPMediaFactory
335 * @auth: a #GstRTSPAuth
337 * configure @auth to be used as the authentication manager of @factory.
340 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
345 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
352 factory->auth = auth;
354 g_object_unref (old);
359 * gst_rtsp_media_factory_get_auth:
360 * @factory: a #GstRTSPMediaFactory
362 * Get the #GstRTSPAuth used as the authentication manager of @factory.
364 * Returns: the #GstRTSPAuth of @factory. g_object_unref() after
368 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
372 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
374 if ((result = factory->auth))
375 g_object_ref (result);
381 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
383 return (media1 == media2);
387 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
389 g_mutex_lock (factory->medias_lock);
390 g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
391 g_mutex_unlock (factory->medias_lock);
395 * gst_rtsp_media_factory_construct:
396 * @factory: a #GstRTSPMediaFactory
399 * Prepare the media object and create its streams. Implementations
400 * should create the needed gstreamer elements and add them to the result
401 * object. No state changes should be performed on them yet.
403 * One or more GstRTSPMediaStream objects should be added to the result with
404 * the srcpad member set to a source pad that produces buffer of type
407 * Returns: a new #GstRTSPMedia if the media could be prepared.
410 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
411 const GstRTSPUrl * url)
415 GstRTSPMediaFactoryClass *klass;
417 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
419 /* convert the url to a key for the hashtable. NULL return or a NULL function
420 * will not cache anything for this factory. */
422 key = klass->gen_key (factory, url);
426 g_mutex_lock (factory->medias_lock);
428 /* we have a key, see if we find a cached media */
429 media = g_hash_table_lookup (factory->medias, key);
431 g_object_ref (media);
436 /* nothing cached found, try to create one */
437 if (klass->construct)
438 media = klass->construct (factory, url);
443 /* configure the media */
444 if (klass->configure)
445 klass->configure (factory, media);
447 /* check if we can cache this media */
448 if (gst_rtsp_media_is_shared (media)) {
449 /* insert in the hashtable, takes ownership of the key */
450 g_object_ref (media);
451 g_hash_table_insert (factory->medias, key, media);
454 if (!gst_rtsp_media_is_reusable (media)) {
455 /* when not reusable, connect to the unprepare signal to remove the item
456 * from our cache when it gets unprepared */
457 g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
462 g_mutex_unlock (factory->medias_lock);
467 GST_INFO ("constructed media %p for url %s", media, url->abspath);
473 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
476 const gchar *pre_query;
479 pre_query = url->query ? "?" : "";
480 query = url->query ? url->query : "";
483 g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
489 default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
492 GError *error = NULL;
494 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
495 /* we need a parse syntax */
496 if (factory->launch == NULL)
499 /* parse the user provided launch line */
500 element = gst_parse_launch (factory->launch, &error);
504 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
507 /* a recoverable error was encountered */
508 GST_WARNING ("recoverable parsing error: %s", error->message);
509 g_error_free (error);
516 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
517 g_critical ("no launch line specified");
522 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
523 g_critical ("could not parse launch syntax (%s): %s", factory->launch,
524 (error ? error->message : "unknown reason"));
526 g_error_free (error);
531 /* try to find all the payloader elements, they should be named 'pay%d'. for
532 * each of the payloaders we will create a stream and collect the source pad. */
534 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
535 const GstRTSPUrl * url, GstRTSPMedia * media)
537 GstElement *element, *elem;
540 GstRTSPMediaStream *stream;
543 element = media->element;
546 for (i = 0; have_elem; i++) {
551 name = g_strdup_printf ("pay%d", i);
552 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
553 /* create the stream */
554 stream = g_new0 (GstRTSPMediaStream, 1);
555 stream->payloader = elem;
557 GST_INFO ("found stream %d with payloader %p", i, elem);
559 pad = gst_element_get_static_pad (elem, "src");
561 /* ghost the pad of the payloader to the element */
562 stream->srcpad = gst_ghost_pad_new (name, pad);
563 gst_pad_set_active (stream->srcpad, TRUE);
564 gst_element_add_pad (media->element, stream->srcpad);
565 gst_object_unref (elem);
568 g_array_append_val (media->streams, stream);
573 name = g_strdup_printf ("dynpay%d", i);
574 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
575 /* a stream that will dynamically create pads to provide RTP packets */
577 GST_INFO ("found dynamic element %d, %p", i, elem);
579 media->dynamic = g_list_prepend (media->dynamic, elem);
587 static GstRTSPMedia *
588 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
592 GstRTSPMediaFactoryClass *klass;
594 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
596 if (!klass->create_pipeline)
599 if (klass->get_element)
600 element = klass->get_element (factory, url);
606 /* create a new empty media */
607 media = gst_rtsp_media_new ();
608 media->element = element;
610 media->pipeline = klass->create_pipeline (factory, media);
611 if (media->pipeline == NULL)
614 gst_rtsp_media_factory_collect_streams (factory, url, media);
621 g_critical ("no create_pipeline function");
626 g_critical ("could not create element");
631 g_critical ("can't create pipeline");
632 g_object_unref (media);
638 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
640 GstElement *pipeline;
642 if (media->element == NULL)
645 pipeline = gst_pipeline_new ("media-pipeline");
646 gst_bin_add (GST_BIN_CAST (pipeline), media->element);
653 g_critical ("no element");
659 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
661 gboolean shared, eos_shutdown;
664 /* configure the sharedness */
665 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
666 shared = factory->shared;
667 eos_shutdown = factory->eos_shutdown;
668 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
670 gst_rtsp_media_set_shared (media, shared);
671 gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
673 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
674 gst_rtsp_media_set_auth (media, auth);
675 g_object_unref (auth);