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,
42 SIGNAL_MEDIA_CONFIGURE,
46 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
47 #define GST_CAT_DEFAULT rtsp_media_debug
49 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
51 static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
52 GValue * value, GParamSpec * pspec);
53 static void gst_rtsp_media_factory_set_property (GObject * object, guint propid,
54 const GValue * value, GParamSpec * pspec);
55 static void gst_rtsp_media_factory_finalize (GObject * obj);
57 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
58 const GstRTSPUrl * url);
59 static GstElement *default_get_element (GstRTSPMediaFactory * factory,
60 const GstRTSPUrl * url);
61 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
62 const GstRTSPUrl * url);
63 static void default_configure (GstRTSPMediaFactory * factory,
64 GstRTSPMedia * media);
65 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
66 GstRTSPMedia * media);
68 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
71 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
73 GObjectClass *gobject_class;
75 gobject_class = G_OBJECT_CLASS (klass);
77 gobject_class->get_property = gst_rtsp_media_factory_get_property;
78 gobject_class->set_property = gst_rtsp_media_factory_set_property;
79 gobject_class->finalize = gst_rtsp_media_factory_finalize;
82 * GstRTSPMediaFactory::launch
84 * The gst_parse_launch() line to use for constructing the pipeline in the
85 * default prepare vmethod.
87 * The pipeline description should return a GstBin as the toplevel element
88 * which can be accomplished by enclosing the dscription with brackets '('
91 * The description should return a pipeline with payloaders named pay0, pay1,
92 * etc.. Each of the payloaders will result in a stream.
94 * Support for dynamic payloaders can be accomplished by adding payloaders
95 * named dynpay0, dynpay1, etc..
97 g_object_class_install_property (gobject_class, PROP_LAUNCH,
98 g_param_spec_string ("launch", "Launch",
99 "A launch description of the pipeline", DEFAULT_LAUNCH,
100 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102 g_object_class_install_property (gobject_class, PROP_SHARED,
103 g_param_spec_boolean ("shared", "Shared",
104 "If media from this factory is shared", DEFAULT_SHARED,
105 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 EOS down the pipeline before shutting down",
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 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
123 g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
124 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
125 media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
126 G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
128 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] =
129 g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass),
130 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
131 media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
132 G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
134 klass->gen_key = default_gen_key;
135 klass->get_element = default_get_element;
136 klass->construct = default_construct;
137 klass->configure = default_configure;
138 klass->create_pipeline = default_create_pipeline;
140 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
141 "GstRTSPMediaFactory");
145 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
147 factory->launch = g_strdup (DEFAULT_LAUNCH);
148 factory->shared = DEFAULT_SHARED;
149 factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
150 factory->buffer_size = DEFAULT_BUFFER_SIZE;
151 factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP);
153 factory->lock = g_mutex_new ();
154 factory->medias_lock = g_mutex_new ();
155 factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
156 g_free, g_object_unref);
160 gst_rtsp_media_factory_finalize (GObject * obj)
162 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
164 g_hash_table_unref (factory->medias);
165 g_mutex_free (factory->medias_lock);
166 g_free (factory->launch);
167 g_free (factory->multicast_group);
168 g_mutex_free (factory->lock);
170 g_object_unref (factory->auth);
172 G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
176 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
177 GValue * value, GParamSpec * pspec)
179 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
183 g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
186 g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
188 case PROP_EOS_SHUTDOWN:
189 g_value_set_boolean (value,
190 gst_rtsp_media_factory_is_eos_shutdown (factory));
192 case PROP_BUFFER_SIZE:
193 g_value_set_uint (value,
194 gst_rtsp_media_factory_get_buffer_size (factory));
196 case PROP_MULTICAST_GROUP:
197 g_value_take_string (value,
198 gst_rtsp_media_factory_get_multicast_group (factory));
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
206 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
207 const GValue * value, GParamSpec * pspec)
209 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
213 gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
216 gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
218 case PROP_EOS_SHUTDOWN:
219 gst_rtsp_media_factory_set_eos_shutdown (factory,
220 g_value_get_boolean (value));
222 case PROP_BUFFER_SIZE:
223 gst_rtsp_media_factory_set_buffer_size (factory,
224 g_value_get_uint (value));
226 case PROP_MULTICAST_GROUP:
227 gst_rtsp_media_factory_set_multicast_group (factory,
228 g_value_get_string (value));
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
236 * gst_rtsp_media_factory_new:
238 * Create a new #GstRTSPMediaFactory instance.
240 * Returns: a new #GstRTSPMediaFactory object.
242 GstRTSPMediaFactory *
243 gst_rtsp_media_factory_new (void)
245 GstRTSPMediaFactory *result;
247 result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
253 * gst_rtsp_media_factory_set_launch:
254 * @factory: a #GstRTSPMediaFactory
255 * @launch: the launch description
258 * The gst_parse_launch() line to use for constructing the pipeline in the
259 * default prepare vmethod.
261 * The pipeline description should return a GstBin as the toplevel element
262 * which can be accomplished by enclosing the dscription with brackets '('
265 * The description should return a pipeline with payloaders named pay0, pay1,
266 * etc.. Each of the payloaders will result in a stream.
269 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
270 const gchar * launch)
272 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
273 g_return_if_fail (launch != NULL);
275 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
276 g_free (factory->launch);
277 factory->launch = g_strdup (launch);
278 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
282 * gst_rtsp_media_factory_get_launch:
283 * @factory: a #GstRTSPMediaFactory
285 * Get the gst_parse_launch() pipeline description that will be used in the
286 * default prepare vmethod.
288 * Returns: the configured launch description. g_free() after usage.
291 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
295 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
297 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
298 result = g_strdup (factory->launch);
299 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
305 * gst_rtsp_media_factory_set_shared:
306 * @factory: a #GstRTSPMediaFactory
307 * @shared: the new value
309 * Configure if media created from this factory can be shared between clients.
312 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
315 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
317 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
318 factory->shared = shared;
319 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
323 * gst_rtsp_media_factory_is_shared:
324 * @factory: a #GstRTSPMediaFactory
326 * Get if media created from this factory can be shared between clients.
328 * Returns: %TRUE if the media will be shared between clients.
331 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
335 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
337 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
338 result = factory->shared;
339 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
345 * gst_rtsp_media_factory_set_eos_shutdown:
346 * @factory: a #GstRTSPMediaFactory
347 * @eos_shutdown: the new value
349 * Configure if media created from this factory will have an EOS sent to the
350 * pipeline before shutdown.
353 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
354 gboolean eos_shutdown)
356 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
358 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
359 factory->eos_shutdown = eos_shutdown;
360 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
364 * gst_rtsp_media_factory_is_eos_shutdown:
365 * @factory: a #GstRTSPMediaFactory
367 * Get if media created from this factory will have an EOS event sent to the
368 * pipeline before shutdown.
370 * Returns: %TRUE if the media will receive EOS before shutdown.
373 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
377 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
379 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
380 result = factory->eos_shutdown;
381 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
387 * gst_rtsp_media_factory_set_buffer_size:
388 * @factory: a #GstRTSPMedia
389 * @size: the new value
391 * Set the kernel UDP buffer size.
394 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
397 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
399 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
400 factory->buffer_size = size;
401 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
405 * gst_rtsp_media_factory_get_buffer_size:
406 * @factory: a #GstRTSPMedia
408 * Get the kernel UDP buffer size.
410 * Returns: the kernel UDP buffer size.
413 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
417 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
419 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
420 result = factory->buffer_size;
421 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
427 * gst_rtsp_media_factory_set_multicast_group:
428 * @factory: a #GstRTSPMedia
429 * @mc: the new multicast group
431 * Set the multicast group that media from @factory will be streamed to.
434 gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory,
437 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
439 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
440 g_free (factory->multicast_group);
441 factory->multicast_group = g_strdup (mc);
442 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
446 * gst_rtsp_media_factory_get_multicast_group:
447 * @factory: a #GstRTSPMedia
449 * Get the multicast group that media from @factory will be streamed to.
451 * Returns: the multicast group
454 gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory)
458 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
460 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
461 result = g_strdup (factory->multicast_group);
462 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
468 * gst_rtsp_media_factory_set_auth:
469 * @factory: a #GstRTSPMediaFactory
470 * @auth: a #GstRTSPAuth
472 * configure @auth to be used as the authentication manager of @factory.
475 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
480 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
487 factory->auth = auth;
489 g_object_unref (old);
494 * gst_rtsp_media_factory_get_auth:
495 * @factory: a #GstRTSPMediaFactory
497 * Get the #GstRTSPAuth used as the authentication manager of @factory.
499 * Returns: the #GstRTSPAuth of @factory. g_object_unref() after
503 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
507 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
509 if ((result = factory->auth))
510 g_object_ref (result);
516 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
518 return (media1 == media2);
522 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
524 g_mutex_lock (factory->medias_lock);
525 g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
526 g_mutex_unlock (factory->medias_lock);
530 * gst_rtsp_media_factory_construct:
531 * @factory: a #GstRTSPMediaFactory
534 * Prepare the media object and create its streams. Implementations
535 * should create the needed gstreamer elements and add them to the result
536 * object. No state changes should be performed on them yet.
538 * One or more GstRTSPMediaStream objects should be added to the result with
539 * the srcpad member set to a source pad that produces buffer of type
542 * Returns: a new #GstRTSPMedia if the media could be prepared.
545 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
546 const GstRTSPUrl * url)
550 GstRTSPMediaFactoryClass *klass;
552 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
554 /* convert the url to a key for the hashtable. NULL return or a NULL function
555 * will not cache anything for this factory. */
557 key = klass->gen_key (factory, url);
561 g_mutex_lock (factory->medias_lock);
563 /* we have a key, see if we find a cached media */
564 media = g_hash_table_lookup (factory->medias, key);
566 g_object_ref (media);
571 /* nothing cached found, try to create one */
572 if (klass->construct) {
573 media = klass->construct (factory, url);
575 g_signal_emit (factory,
576 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
582 /* configure the media */
583 if (klass->configure)
584 klass->configure (factory, media);
586 g_signal_emit (factory,
587 gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
590 /* check if we can cache this media */
591 if (gst_rtsp_media_is_shared (media)) {
592 /* insert in the hashtable, takes ownership of the key */
593 g_object_ref (media);
594 g_hash_table_insert (factory->medias, key, media);
597 if (!gst_rtsp_media_is_reusable (media)) {
598 /* when not reusable, connect to the unprepare signal to remove the item
599 * from our cache when it gets unprepared */
600 g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
605 g_mutex_unlock (factory->medias_lock);
610 GST_INFO ("constructed media %p for url %s", media, url->abspath);
616 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
619 const gchar *pre_query;
622 pre_query = url->query ? "?" : "";
623 query = url->query ? url->query : "";
626 g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
632 default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
635 GError *error = NULL;
637 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
638 /* we need a parse syntax */
639 if (factory->launch == NULL)
642 /* parse the user provided launch line */
643 element = gst_parse_launch (factory->launch, &error);
647 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
650 /* a recoverable error was encountered */
651 GST_WARNING ("recoverable parsing error: %s", error->message);
652 g_error_free (error);
659 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
660 g_critical ("no launch line specified");
665 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
666 g_critical ("could not parse launch syntax (%s): %s", factory->launch,
667 (error ? error->message : "unknown reason"));
669 g_error_free (error);
674 /* try to find all the payloader elements, they should be named 'pay%d'. for
675 * each of the payloaders we will create a stream and collect the source pad. */
677 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
678 const GstRTSPUrl * url, GstRTSPMedia * media)
680 GstElement *element, *elem;
683 GstRTSPMediaStream *stream;
686 element = media->element;
689 for (i = 0; have_elem; i++) {
694 name = g_strdup_printf ("pay%d", i);
695 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
696 /* create the stream */
697 stream = g_new0 (GstRTSPMediaStream, 1);
698 stream->payloader = elem;
700 GST_INFO ("found stream %d with payloader %p", i, elem);
702 pad = gst_element_get_static_pad (elem, "src");
704 /* ghost the pad of the payloader to the element */
705 stream->srcpad = gst_ghost_pad_new (name, pad);
706 gst_pad_set_active (stream->srcpad, TRUE);
707 gst_element_add_pad (media->element, stream->srcpad);
708 gst_object_unref (elem);
711 g_array_append_val (media->streams, stream);
716 name = g_strdup_printf ("dynpay%d", i);
717 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
718 /* a stream that will dynamically create pads to provide RTP packets */
720 GST_INFO ("found dynamic element %d, %p", i, elem);
722 media->dynamic = g_list_prepend (media->dynamic, elem);
730 static GstRTSPMedia *
731 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
735 GstRTSPMediaFactoryClass *klass;
737 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
739 if (!klass->create_pipeline)
742 if (klass->get_element)
743 element = klass->get_element (factory, url);
749 /* create a new empty media */
750 media = gst_rtsp_media_new ();
751 media->element = element;
753 media->pipeline = klass->create_pipeline (factory, media);
754 if (media->pipeline == NULL)
757 gst_rtsp_media_factory_collect_streams (factory, url, media);
764 g_critical ("no create_pipeline function");
769 g_critical ("could not create element");
774 g_critical ("can't create pipeline");
775 g_object_unref (media);
781 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
783 GstElement *pipeline;
785 if (media->element == NULL)
788 pipeline = gst_pipeline_new ("media-pipeline");
789 gst_bin_add (GST_BIN_CAST (pipeline), media->element);
796 g_critical ("no element");
802 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
804 gboolean shared, eos_shutdown;
809 /* configure the sharedness */
810 GST_RTSP_MEDIA_FACTORY_LOCK (factory);
811 shared = factory->shared;
812 eos_shutdown = factory->eos_shutdown;
813 size = factory->buffer_size;
814 GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
816 gst_rtsp_media_set_shared (media, shared);
817 gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
818 gst_rtsp_media_set_buffer_size (media, size);
820 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
821 gst_rtsp_media_set_auth (media, auth);
822 g_object_unref (auth);
824 if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) {
825 gst_rtsp_media_set_multicast_group (media, mc);