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
26 #define DEFAULT_MULTICAST_GROUP "224.2.0.1"
41 SIGNAL_MEDIA_CONSTRUCTED,
45 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
46 #define GST_CAT_DEFAULT rtsp_media_debug
48 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
50 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
51 GValue * value, GParamSpec * pspec);
52 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
53 const GValue * value, GParamSpec * pspec);
54 static void gst_rtsp_media_factory_finalize (GObject * obj);
56 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
57 const GstRTSPUrl * url);
58 static GstElement *default_get_element (GstRTSPMediaFactory * factory,
59 const GstRTSPUrl * url);
60 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
61 const GstRTSPUrl * url);
62 static void default_configure (GstRTSPMediaFactory * factory,
63 GstRTSPMedia * media);
64 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
65 GstRTSPMedia * media);
67 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
70 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
72 GObjectClass *gobject_class;
74 gobject_class = G_OBJECT_CLASS (klass);
76 gobject_class->get_property = gst_rtsp_media_factory_get_property;
77 gobject_class->set_property = gst_rtsp_media_factory_set_property;
78 gobject_class->finalize = gst_rtsp_media_factory_finalize;
81 * GstRTSPMediaFactory::launch
83 * The gst_parse_launch() line to use for constructing the pipeline in the
84 * default prepare vmethod.
86 * The pipeline description should return a GstBin as the toplevel element
87 * which can be accomplished by enclosing the dscription with brackets '('
90 * The description should return a pipeline with payloaders named pay0, pay1,
91 * etc.. Each of the payloaders will result in a stream.
93 * Support for dynamic payloaders can be accomplished by adding payloaders
94 * named dynpay0, dynpay1, etc..
96 g_object_class_install_property (gobject_class, PROP_LAUNCH,
97 g_param_spec_string ("launch", "Launch",
98 "A launch description of the pipeline", DEFAULT_LAUNCH,
99 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
101 g_object_class_install_property (gobject_class, PROP_SHARED,
102 g_param_spec_boolean ("shared", "Shared",
103 "If media from this factory is shared", DEFAULT_SHARED,
104 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
106 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
107 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
108 "Send EOS down the pipeline before shutting down",
109 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
111 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
112 g_param_spec_uint ("buffer-size", "Buffer Size",
113 "The kernel UDP buffer size to use", 0, G_MAXUINT,
114 DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
116 g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
117 g_param_spec_string ("multicast-group", "Multicast Group",
118 "The Multicast group to send media to",
119 DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
122 g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
123 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
124 media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
125 G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
127 klass->gen_key = default_gen_key;
128 klass->get_element = default_get_element;
129 klass->construct = default_construct;
130 klass->configure = default_configure;
131 klass->create_pipeline = default_create_pipeline;
133 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
134 "GstRTSPMediaFactory");
138 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
140 factory->launch = g_strdup (DEFAULT_LAUNCH);
141 factory->shared = DEFAULT_SHARED;
142 factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
143 factory->buffer_size = DEFAULT_BUFFER_SIZE;
144 factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP);
146 factory->lock = g_mutex_new ();
147 factory->medias_lock = g_mutex_new ();
148 factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
149 g_free, g_object_unref);
153 gst_rtsp_media_factory_finalize (GObject * obj)
155 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
157 g_hash_table_unref (factory->medias);
158 g_mutex_free (factory->medias_lock);
159 g_free (factory->launch);
160 g_free (factory->multicast_group);
161 g_mutex_free (factory->lock);
163 g_object_unref (factory->auth);
165 G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
169 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
170 GValue * value, GParamSpec * pspec)
172 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
176 g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
179 g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
181 case PROP_EOS_SHUTDOWN:
182 g_value_set_boolean (value,
183 gst_rtsp_media_factory_is_eos_shutdown (factory));
185 case PROP_BUFFER_SIZE:
186 g_value_set_uint (value,
187 gst_rtsp_media_factory_get_buffer_size (factory));
189 case PROP_MULTICAST_GROUP:
190 g_value_take_string (value,
191 gst_rtsp_media_factory_get_multicast_group (factory));
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
199 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
200 const GValue * value, GParamSpec * pspec)
202 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
206 gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
209 gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
211 case PROP_EOS_SHUTDOWN:
212 gst_rtsp_media_factory_set_eos_shutdown (factory,
213 g_value_get_boolean (value));
215 case PROP_BUFFER_SIZE:
216 gst_rtsp_media_factory_set_buffer_size (factory,
217 g_value_get_uint (value));
219 case PROP_MULTICAST_GROUP:
220 gst_rtsp_media_factory_set_multicast_group (factory,
221 g_value_get_string (value));
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
229 * gst_rtsp_media_factory_new:
231 * Create a new #GstRTSPMediaFactory instance.
233 * Returns: a new #GstRTSPMediaFactory object.
235 GstRTSPMediaFactory *
236 gst_rtsp_media_factory_new (void)
238 GstRTSPMediaFactory *result;
240 result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
246 * gst_rtsp_media_factory_set_launch:
247 * @factory: a #GstRTSPMediaFactory
248 * @launch: the launch description
251 * The gst_parse_launch() line to use for constructing the pipeline in the
252 * default prepare vmethod.
254 * The pipeline description should return a GstBin as the toplevel element
255 * which can be accomplished by enclosing the dscription with brackets '('
258 * The description should return a pipeline with payloaders named pay0, pay1,
259 * etc.. Each of the payloaders will result in a stream.
262 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
263 const gchar * launch)
265 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
266 g_return_if_fail (launch != NULL);
268 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
269 g_free (factory->launch);
270 factory->launch = g_strdup (launch);
271 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
275 * gst_rtsp_media_factory_get_launch:
276 * @factory: a #GstRTSPMediaFactory
278 * Get the gst_parse_launch() pipeline description that will be used in the
279 * default prepare vmethod.
281 * Returns: the configured launch description. g_free() after usage.
284 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
288 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
290 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
291 result = g_strdup (factory->launch);
292 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
298 * gst_rtsp_media_factory_set_shared:
299 * @factory: a #GstRTSPMediaFactory
300 * @shared: the new value
302 * Configure if media created from this factory can be shared between clients.
305 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
308 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
310 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
311 factory->shared = shared;
312 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
316 * gst_rtsp_media_factory_is_shared:
317 * @factory: a #GstRTSPMediaFactory
319 * Get if media created from this factory can be shared between clients.
321 * Returns: %TRUE if the media will be shared between clients.
324 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
328 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
330 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
331 result = factory->shared;
332 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
338 * gst_rtsp_media_factory_set_eos_shutdown:
339 * @factory: a #GstRTSPMediaFactory
340 * @eos_shutdown: the new value
342 * Configure if media created from this factory will have an EOS sent to the
343 * pipeline before shutdown.
346 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
347 gboolean eos_shutdown)
349 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
351 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
352 factory->eos_shutdown = eos_shutdown;
353 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
357 * gst_rtsp_media_factory_is_eos_shutdown:
358 * @factory: a #GstRTSPMediaFactory
360 * Get if media created from this factory will have an EOS event sent to the
361 * pipeline before shutdown.
363 * Returns: %TRUE if the media will receive EOS before shutdown.
366 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
370 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
372 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
373 result = factory->eos_shutdown;
374 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
380 * gst_rtsp_media_factory_set_buffer_size:
381 * @factory: a #GstRTSPMedia
382 * @size: the new value
384 * Set the kernel UDP buffer size.
387 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
390 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
392 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
393 factory->buffer_size = size;
394 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
398 * gst_rtsp_media_factory_get_buffer_size:
399 * @factory: a #GstRTSPMedia
401 * Get the kernel UDP buffer size.
403 * Returns: the kernel UDP buffer size.
406 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
410 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
412 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
413 result = factory->buffer_size;
414 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
420 * gst_rtsp_media_factory_set_multicast_group:
421 * @factory: a #GstRTSPMedia
422 * @mc: the new multicast group
424 * Set the multicast group that media from @factory will be streamed to.
427 gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory,
430 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
432 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
433 g_free (factory->multicast_group);
434 factory->multicast_group = g_strdup (mc);
435 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
439 * gst_rtsp_media_factory_get_multicast_group:
440 * @factory: a #GstRTSPMedia
442 * Get the multicast group that media from @factory will be streamed to.
444 * Returns: the multicast group
447 gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory)
451 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
453 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
454 result = g_strdup (factory->multicast_group);
455 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
461 * gst_rtsp_media_factory_set_auth:
462 * @factory: a #GstRTSPMediaFactory
463 * @auth: a #GstRTSPAuth
465 * configure @auth to be used as the authentication manager of @factory.
468 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
473 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
480 factory->auth = auth;
482 g_object_unref (old);
487 * gst_rtsp_media_factory_get_auth:
488 * @factory: a #GstRTSPMediaFactory
490 * Get the #GstRTSPAuth used as the authentication manager of @factory.
492 * Returns: the #GstRTSPAuth of @factory. g_object_unref() after
496 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
500 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
502 if ((result = factory->auth))
503 g_object_ref (result);
509 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
511 return (media1 == media2);
515 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
517 g_mutex_lock (factory->medias_lock);
518 g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
519 g_mutex_unlock (factory->medias_lock);
523 * gst_rtsp_media_factory_construct:
524 * @factory: a #GstRTSPMediaFactory
527 * Prepare the media object and create its streams. Implementations
528 * should create the needed gstreamer elements and add them to the result
529 * object. No state changes should be performed on them yet.
531 * One or more GstRTSPMediaStream objects should be added to the result with
532 * the srcpad member set to a source pad that produces buffer of type
535 * Returns: a new #GstRTSPMedia if the media could be prepared.
538 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
539 const GstRTSPUrl * url)
543 GstRTSPMediaFactoryClass *klass;
545 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
547 /* convert the url to a key for the hashtable. NULL return or a NULL function
548 * will not cache anything for this factory. */
550 key = klass->gen_key (factory, url);
554 g_mutex_lock (factory->medias_lock);
556 /* we have a key, see if we find a cached media */
557 media = g_hash_table_lookup (factory->medias, key);
559 g_object_ref (media);
564 /* nothing cached found, try to create one */
565 if (klass->construct) {
566 media = klass->construct (factory, url);
568 g_signal_emit (factory,
569 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
575 /* configure the media */
576 if (klass->configure)
577 klass->configure (factory, media);
579 /* check if we can cache this media */
580 if (gst_rtsp_media_is_shared (media)) {
581 /* insert in the hashtable, takes ownership of the key */
582 g_object_ref (media);
583 g_hash_table_insert (factory->medias, key, media);
586 if (!gst_rtsp_media_is_reusable (media)) {
587 /* when not reusable, connect to the unprepare signal to remove the item
588 * from our cache when it gets unprepared */
589 g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
594 g_mutex_unlock (factory->medias_lock);
599 GST_INFO ("constructed media %p for url %s", media, url->abspath);
605 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
608 const gchar *pre_query;
611 pre_query = url->query ? "?" : "";
612 query = url->query ? url->query : "";
615 g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
621 default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
624 GError *error = NULL;
626 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
627 /* we need a parse syntax */
628 if (factory->launch == NULL)
631 /* parse the user provided launch line */
632 element = gst_parse_launch (factory->launch, &error);
636 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
639 /* a recoverable error was encountered */
640 GST_WARNING ("recoverable parsing error: %s", error->message);
641 g_error_free (error);
648 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
649 g_critical ("no launch line specified");
654 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
655 g_critical ("could not parse launch syntax (%s): %s", factory->launch,
656 (error ? error->message : "unknown reason"));
658 g_error_free (error);
663 /* try to find all the payloader elements, they should be named 'pay%d'. for
664 * each of the payloaders we will create a stream and collect the source pad. */
666 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
667 const GstRTSPUrl * url, GstRTSPMedia * media)
669 GstElement *element, *elem;
672 GstRTSPMediaStream *stream;
675 element = media->element;
678 for (i = 0; have_elem; i++) {
683 name = g_strdup_printf ("pay%d", i);
684 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
685 /* create the stream */
686 stream = g_new0 (GstRTSPMediaStream, 1);
687 stream->payloader = elem;
689 GST_INFO ("found stream %d with payloader %p", i, elem);
691 pad = gst_element_get_static_pad (elem, "src");
693 /* ghost the pad of the payloader to the element */
694 stream->srcpad = gst_ghost_pad_new (name, pad);
695 gst_pad_set_active (stream->srcpad, TRUE);
696 gst_element_add_pad (media->element, stream->srcpad);
697 gst_object_unref (elem);
700 g_array_append_val (media->streams, stream);
705 name = g_strdup_printf ("dynpay%d", i);
706 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
707 /* a stream that will dynamically create pads to provide RTP packets */
709 GST_INFO ("found dynamic element %d, %p", i, elem);
711 media->dynamic = g_list_prepend (media->dynamic, elem);
719 static GstRTSPMedia *
720 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
724 GstRTSPMediaFactoryClass *klass;
726 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
728 if (!klass->create_pipeline)
731 if (klass->get_element)
732 element = klass->get_element (factory, url);
738 /* create a new empty media */
739 media = gst_rtsp_media_new ();
740 media->element = element;
742 media->pipeline = klass->create_pipeline (factory, media);
743 if (media->pipeline == NULL)
746 gst_rtsp_media_factory_collect_streams (factory, url, media);
753 g_critical ("no create_pipeline function");
758 g_critical ("could not create element");
763 g_critical ("can't create pipeline");
764 g_object_unref (media);
770 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
772 GstElement *pipeline;
774 if (media->element == NULL)
777 pipeline = gst_pipeline_new ("media-pipeline");
778 gst_bin_add (GST_BIN_CAST (pipeline), media->element);
785 g_critical ("no element");
791 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
793 gboolean shared, eos_shutdown;
798 /* configure the sharedness */
799 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
800 shared = factory->shared;
801 eos_shutdown = factory->eos_shutdown;
802 size = factory->buffer_size;
803 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
805 gst_rtsp_media_set_shared (media, shared);
806 gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
807 gst_rtsp_media_set_buffer_size (media, size);
809 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
810 gst_rtsp_media_set_auth (media, auth);
811 g_object_unref (auth);
813 if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) {
814 gst_rtsp_media_set_multicast_group (media, mc);