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
33 GST_DEBUG_CATEGORY (rtsp_media_debug);
34 #define GST_CAT_DEFAULT rtsp_media_debug
36 static void gst_rtsp_media_factory_get_property (GObject *object, guint propid,
37 GValue *value, GParamSpec *pspec);
38 static void gst_rtsp_media_factory_set_property (GObject *object, guint propid,
39 const GValue *value, GParamSpec *pspec);
40 static void gst_rtsp_media_factory_finalize (GObject * obj);
42 static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
43 static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
44 static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
45 static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
46 static GstElement* default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
48 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
51 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
53 GObjectClass *gobject_class;
55 gobject_class = G_OBJECT_CLASS (klass);
57 gobject_class->get_property = gst_rtsp_media_factory_get_property;
58 gobject_class->set_property = gst_rtsp_media_factory_set_property;
59 gobject_class->finalize = gst_rtsp_media_factory_finalize;
62 * GstRTSPMediaFactory::launch
64 * The gst_parse_launch() line to use for constructing the pipeline in the
65 * default prepare vmethod.
67 * The pipeline description should return a GstBin as the toplevel element
68 * which can be accomplished by enclosing the dscription with brackets '('
71 * The description should return a pipeline with payloaders named pay0, pay1,
72 * etc.. Each of the payloaders will result in a stream.
74 g_object_class_install_property (gobject_class, PROP_LAUNCH,
75 g_param_spec_string ("launch", "Launch", "A launch description of the pipeline",
76 DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
78 g_object_class_install_property (gobject_class, PROP_SHARED,
79 g_param_spec_boolean ("shared", "Shared", "If media from this factory is shared",
80 DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
82 klass->gen_key = default_gen_key;
83 klass->get_element = default_get_element;
84 klass->construct = default_construct;
85 klass->configure = default_configure;
86 klass->create_pipeline = default_create_pipeline;
88 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
92 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
94 factory->launch = g_strdup (DEFAULT_LAUNCH);
95 factory->shared = DEFAULT_SHARED;
97 factory->lock = g_mutex_new ();
98 factory->medias_lock = g_mutex_new ();
99 factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
100 g_free, g_object_unref);
104 gst_rtsp_media_factory_finalize (GObject * obj)
106 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
108 g_hash_table_unref (factory->medias);
109 g_mutex_free (factory->medias_lock);
110 g_free (factory->launch);
111 g_mutex_free (factory->lock);
113 G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
117 gst_rtsp_media_factory_get_property (GObject *object, guint propid,
118 GValue *value, GParamSpec *pspec)
120 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
124 g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
127 g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
130 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
135 gst_rtsp_media_factory_set_property (GObject *object, guint propid,
136 const GValue *value, GParamSpec *pspec)
138 GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
142 gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
145 gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
153 * gst_rtsp_media_factory_new:
155 * Create a new #GstRTSPMediaFactory instance.
157 * Returns: a new #GstRTSPMediaFactory object.
159 GstRTSPMediaFactory *
160 gst_rtsp_media_factory_new (void)
162 GstRTSPMediaFactory *result;
164 result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
170 * gst_rtsp_media_factory_set_launch:
171 * @factory: a #GstRTSPMediaFactory
172 * @launch: the launch description
175 * The gst_parse_launch() line to use for constructing the pipeline in the
176 * default prepare vmethod.
178 * The pipeline description should return a GstBin as the toplevel element
179 * which can be accomplished by enclosing the dscription with brackets '('
182 * The description should return a pipeline with payloaders named pay0, pay1,
183 * etc.. Each of the payloaders will result in a stream.
186 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch)
188 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
189 g_return_if_fail (launch != NULL);
191 g_mutex_lock (factory->lock);
192 g_free (factory->launch);
193 factory->launch = g_strdup (launch);
194 g_mutex_unlock (factory->lock);
198 * gst_rtsp_media_factory_get_launch:
199 * @factory: a #GstRTSPMediaFactory
201 * Get the gst_parse_launch() pipeline description that will be used in the
202 * default prepare vmethod.
204 * Returns: the configured launch description. g_free() after usage.
207 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory)
211 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
213 g_mutex_lock (factory->lock);
214 result = g_strdup (factory->launch);
215 g_mutex_unlock (factory->lock);
221 * gst_rtsp_media_factory_set_shared:
222 * @factory: a #GstRTSPMediaFactory
223 * @shared: the new value
225 * Configure if media created from this factory can be shared between clients.
228 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory,
231 g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
233 g_mutex_lock (factory->lock);
234 factory->shared = shared;
235 g_mutex_unlock (factory->lock);
239 * gst_rtsp_media_factory_is_shared:
240 * @factory: a #GstRTSPMediaFactory
242 * Get if media created from this factory can be shared between clients.
244 * Returns: %TRUE if the media will be shared between clients.
247 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory)
251 g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
253 g_mutex_lock (factory->lock);
254 result = factory->shared;
255 g_mutex_unlock (factory->lock);
261 compare_media (gpointer key, GstRTSPMedia *media1, GstRTSPMedia *media2)
263 return (media1 == media2);
267 media_unprepared (GstRTSPMedia *media, GstRTSPMediaFactory *factory)
269 g_mutex_lock (factory->medias_lock);
270 g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media,
272 g_mutex_unlock (factory->medias_lock);
276 * gst_rtsp_media_factory_construct:
277 * @factory: a #GstRTSPMediaFactory
280 * Prepare the media object and create its streams. Implementations
281 * should create the needed gstreamer elements and add them to the result
282 * object. No state changes should be performed on them yet.
284 * One or more GstRTSPMediaStream objects should be added to the result with
285 * the srcpad member set to a source pad that produces buffer of type
288 * Returns: a new #GstRTSPMedia if the media could be prepared.
291 gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
295 GstRTSPMediaFactoryClass *klass;
297 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
299 /* convert the url to a key for the hashtable. NULL return or a NULL function
300 * will not cache anything for this factory. */
302 key = klass->gen_key (factory, url);
306 g_mutex_lock (factory->medias_lock);
308 /* we have a key, see if we find a cached media */
309 media = g_hash_table_lookup (factory->medias, key);
311 g_object_ref (media);
317 /* nothing cached found, try to create one */
318 if (klass->construct)
319 media = klass->construct (factory, url);
324 /* configure the media */
325 if (klass->configure)
326 klass->configure (factory, media);
328 /* check if we can cache this media */
329 if (gst_rtsp_media_is_shared (media)) {
330 /* insert in the hashtable, takes ownership of the key */
331 g_object_ref (media);
332 g_hash_table_insert (factory->medias, key, media);
335 if (!gst_rtsp_media_is_reusable (media)) {
336 /* when not reusable, connect to the unprepare signal to remove the item
337 * from our cache when it gets unprepared */
338 g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
343 g_mutex_unlock (factory->medias_lock);
348 GST_INFO ("constructed media %p for url %s", media, url->abspath);
354 default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
358 result = gst_rtsp_url_get_request_uri ((GstRTSPUrl *)url);
364 default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
367 GError *error = NULL;
369 g_mutex_lock (factory->lock);
370 /* we need a parse syntax */
371 if (factory->launch == NULL)
374 /* parse the user provided launch line */
375 element = gst_parse_launch (factory->launch, &error);
379 g_mutex_unlock (factory->lock);
382 /* a recoverable error was encountered */
383 GST_WARNING ("recoverable parsing error: %s", error->message);
384 g_error_free (error);
391 g_mutex_unlock (factory->lock);
392 g_critical ("no launch line specified");
397 g_mutex_unlock (factory->lock);
398 g_critical ("could not parse launch syntax (%s): %s", factory->launch,
399 (error ? error->message : "unknown reason"));
401 g_error_free (error);
406 /* try to find all the payloader elements, they should be named 'pay%d'. for
407 * each of the payloaders we will create a stream and collect the source pad. */
409 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url,
412 GstElement *element, *elem;
415 GstRTSPMediaStream *stream;
418 element = media->element;
421 for (i = 0; have_elem ; i++) {
426 name = g_strdup_printf ("pay%d", i);
427 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
428 /* create the stream */
429 stream = g_new0 (GstRTSPMediaStream, 1);
430 stream->payloader = elem;
432 GST_INFO ("found stream %d with payloader %p", i, elem);
434 pad = gst_element_get_static_pad (elem, "src");
436 /* ghost the pad of the payloader to the element */
437 stream->srcpad = gst_ghost_pad_new (name, pad);
438 gst_pad_set_active (stream->srcpad, TRUE);
439 gst_element_add_pad (media->element, stream->srcpad);
440 gst_object_unref (elem);
443 g_array_append_val (media->streams, stream);
448 name = g_strdup_printf ("dynpay%d", i);
449 if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
450 /* a stream that will dynamically create pads to provide RTP packets */
452 GST_INFO ("found dynamic element %d, %p", i, elem);
454 media->dynamic = g_list_prepend (media->dynamic, elem);
462 static GstRTSPMedia *
463 default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
467 GstRTSPMediaFactoryClass *klass;
469 klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
471 if (klass->get_element)
472 element = klass->get_element (factory, url);
478 /* create a new empty media */
479 media = gst_rtsp_media_new ();
480 media->element = element;
482 if (!klass->create_pipeline)
485 media->pipeline = klass->create_pipeline (factory, media);
487 gst_rtsp_media_factory_collect_streams (factory, url, media);
494 g_critical ("could not create element");
499 g_critical ("could not create pipeline");
505 default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media) {
506 GstElement *pipeline;
508 pipeline = gst_pipeline_new ("media-pipeline");
509 gst_bin_add (GST_BIN_CAST (pipeline), media->element);
515 default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media)
519 /* configure the sharedness */
520 g_mutex_lock (factory->lock);
521 shared = factory->shared;
522 g_mutex_unlock (factory->lock);
524 gst_rtsp_media_set_shared (media, shared);