factory-uri: add some debug
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-media-factory.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
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.
8  *
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.
13  *
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "rtsp-media-factory.h"
21
22 #define DEFAULT_LAUNCH          NULL
23 #define DEFAULT_SHARED          FALSE
24 #define DEFAULT_EOS_SHUTDOWN    FALSE
25 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
26 #define DEFAULT_BUFFER_SIZE     0x80000
27
28 enum
29 {
30   PROP_0,
31   PROP_LAUNCH,
32   PROP_SHARED,
33   PROP_EOS_SHUTDOWN,
34   PROP_PROTOCOLS,
35   PROP_BUFFER_SIZE,
36   PROP_LAST
37 };
38
39 enum
40 {
41   SIGNAL_MEDIA_CONSTRUCTED,
42   SIGNAL_MEDIA_CONFIGURE,
43   SIGNAL_LAST
44 };
45
46 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
47 #define GST_CAT_DEFAULT rtsp_media_debug
48
49 static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
50
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);
56
57 static gchar *default_gen_key (GstRTSPMediaFactory * factory,
58     const GstRTSPUrl * url);
59 static GstElement *default_create_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);
67
68 G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
69
70 static void
71 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
72 {
73   GObjectClass *gobject_class;
74
75   gobject_class = G_OBJECT_CLASS (klass);
76
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;
80
81   /**
82    * GstRTSPMediaFactory::launch:
83    *
84    * The gst_parse_launch() line to use for constructing the pipeline in the
85    * default prepare vmethod.
86    *
87    * The pipeline description should return a GstBin as the toplevel element
88    * which can be accomplished by enclosing the dscription with brackets '('
89    * ')'.
90    *
91    * The description should return a pipeline with payloaders named pay0, pay1,
92    * etc.. Each of the payloaders will result in a stream.
93    *
94    * Support for dynamic payloaders can be accomplished by adding payloaders
95    * named dynpay0, dynpay1, etc..
96    */
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));
101
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));
106
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));
111
112   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
113       g_param_spec_flags ("protocols", "Protocols",
114           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
115           DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
116
117   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
118       g_param_spec_uint ("buffer-size", "Buffer Size",
119           "The kernel UDP buffer size to use", 0, G_MAXUINT,
120           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121
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);
127
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);
133
134   klass->gen_key = default_gen_key;
135   klass->create_element = default_create_element;
136   klass->construct = default_construct;
137   klass->configure = default_configure;
138   klass->create_pipeline = default_create_pipeline;
139
140   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
141       "GstRTSPMediaFactory");
142 }
143
144 static void
145 gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
146 {
147   factory->launch = g_strdup (DEFAULT_LAUNCH);
148   factory->shared = DEFAULT_SHARED;
149   factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
150   factory->protocols = DEFAULT_PROTOCOLS;
151   factory->buffer_size = DEFAULT_BUFFER_SIZE;
152
153   g_mutex_init (&factory->lock);
154   g_mutex_init (&factory->medias_lock);
155   factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
156       g_free, g_object_unref);
157 }
158
159 static void
160 gst_rtsp_media_factory_finalize (GObject * obj)
161 {
162   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
163
164   g_hash_table_unref (factory->medias);
165   g_mutex_clear (&factory->medias_lock);
166   g_free (factory->launch);
167   g_mutex_clear (&factory->lock);
168   if (factory->auth)
169     g_object_unref (factory->auth);
170   if (factory->pool)
171     g_object_unref (factory->pool);
172
173   G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
174 }
175
176 static void
177 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
178     GValue * value, GParamSpec * pspec)
179 {
180   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
181
182   switch (propid) {
183     case PROP_LAUNCH:
184       g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
185       break;
186     case PROP_SHARED:
187       g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
188       break;
189     case PROP_EOS_SHUTDOWN:
190       g_value_set_boolean (value,
191           gst_rtsp_media_factory_is_eos_shutdown (factory));
192       break;
193     case PROP_PROTOCOLS:
194       g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory));
195       break;
196     case PROP_BUFFER_SIZE:
197       g_value_set_uint (value,
198           gst_rtsp_media_factory_get_buffer_size (factory));
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
202   }
203 }
204
205 static void
206 gst_rtsp_media_factory_set_property (GObject * object, guint propid,
207     const GValue * value, GParamSpec * pspec)
208 {
209   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
210
211   switch (propid) {
212     case PROP_LAUNCH:
213       gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
214       break;
215     case PROP_SHARED:
216       gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
217       break;
218     case PROP_EOS_SHUTDOWN:
219       gst_rtsp_media_factory_set_eos_shutdown (factory,
220           g_value_get_boolean (value));
221       break;
222     case PROP_PROTOCOLS:
223       gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value));
224       break;
225     case PROP_BUFFER_SIZE:
226       gst_rtsp_media_factory_set_buffer_size (factory,
227           g_value_get_uint (value));
228       break;
229     default:
230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
231   }
232 }
233
234 /**
235  * gst_rtsp_media_factory_new:
236  *
237  * Create a new #GstRTSPMediaFactory instance.
238  *
239  * Returns: a new #GstRTSPMediaFactory object.
240  */
241 GstRTSPMediaFactory *
242 gst_rtsp_media_factory_new (void)
243 {
244   GstRTSPMediaFactory *result;
245
246   result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
247
248   return result;
249 }
250
251 /**
252  * gst_rtsp_media_factory_set_launch:
253  * @factory: a #GstRTSPMediaFactory
254  * @launch: the launch description
255  *
256  *
257  * The gst_parse_launch() line to use for constructing the pipeline in the
258  * default prepare vmethod.
259  *
260  * The pipeline description should return a GstBin as the toplevel element
261  * which can be accomplished by enclosing the dscription with brackets '('
262  * ')'.
263  *
264  * The description should return a pipeline with payloaders named pay0, pay1,
265  * etc.. Each of the payloaders will result in a stream.
266  */
267 void
268 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
269     const gchar * launch)
270 {
271   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
272   g_return_if_fail (launch != NULL);
273
274   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
275   g_free (factory->launch);
276   factory->launch = g_strdup (launch);
277   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
278 }
279
280 /**
281  * gst_rtsp_media_factory_get_launch:
282  * @factory: a #GstRTSPMediaFactory
283  *
284  * Get the gst_parse_launch() pipeline description that will be used in the
285  * default prepare vmethod.
286  *
287  * Returns: the configured launch description. g_free() after usage.
288  */
289 gchar *
290 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
291 {
292   gchar *result;
293
294   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
295
296   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
297   result = g_strdup (factory->launch);
298   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
299
300   return result;
301 }
302
303 /**
304  * gst_rtsp_media_factory_set_shared:
305  * @factory: a #GstRTSPMediaFactory
306  * @shared: the new value
307  *
308  * Configure if media created from this factory can be shared between clients.
309  */
310 void
311 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
312     gboolean shared)
313 {
314   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
315
316   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
317   factory->shared = shared;
318   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
319 }
320
321 /**
322  * gst_rtsp_media_factory_is_shared:
323  * @factory: a #GstRTSPMediaFactory
324  *
325  * Get if media created from this factory can be shared between clients.
326  *
327  * Returns: %TRUE if the media will be shared between clients.
328  */
329 gboolean
330 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
331 {
332   gboolean result;
333
334   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
335
336   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
337   result = factory->shared;
338   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
339
340   return result;
341 }
342
343 /**
344  * gst_rtsp_media_factory_set_eos_shutdown:
345  * @factory: a #GstRTSPMediaFactory
346  * @eos_shutdown: the new value
347  *
348  * Configure if media created from this factory will have an EOS sent to the
349  * pipeline before shutdown.
350  */
351 void
352 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
353     gboolean eos_shutdown)
354 {
355   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
356
357   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
358   factory->eos_shutdown = eos_shutdown;
359   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
360 }
361
362 /**
363  * gst_rtsp_media_factory_is_eos_shutdown:
364  * @factory: a #GstRTSPMediaFactory
365  *
366  * Get if media created from this factory will have an EOS event sent to the
367  * pipeline before shutdown.
368  *
369  * Returns: %TRUE if the media will receive EOS before shutdown.
370  */
371 gboolean
372 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
373 {
374   gboolean result;
375
376   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
377
378   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
379   result = factory->eos_shutdown;
380   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
381
382   return result;
383 }
384
385 /**
386  * gst_rtsp_media_factory_set_buffer_size:
387  * @factory: a #GstRTSPMedia
388  * @size: the new value
389  *
390  * Set the kernel UDP buffer size.
391  */
392 void
393 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
394     guint size)
395 {
396   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
397
398   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
399   factory->buffer_size = size;
400   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
401 }
402
403 /**
404  * gst_rtsp_media_factory_get_buffer_size:
405  * @factory: a #GstRTSPMedia
406  *
407  * Get the kernel UDP buffer size.
408  *
409  * Returns: the kernel UDP buffer size.
410  */
411 guint
412 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
413 {
414   guint result;
415
416   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
417
418   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
419   result = factory->buffer_size;
420   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
421
422   return result;
423 }
424
425 /**
426  * gst_rtsp_media_factory_set_address_pool:
427  * @factory: a #GstRTSPMediaFactory
428  * @pool: a #GstRTSPAddressPool
429  *
430  * configure @pool to be used as the address pool of @factory.
431  */
432 void
433 gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory,
434     GstRTSPAddressPool * pool)
435 {
436   GstRTSPAddressPool *old;
437
438   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
439
440   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
441   if ((old = factory->pool) != pool)
442     factory->pool = pool ? g_object_ref (pool) : NULL;
443   else
444     old = NULL;
445   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
446
447   if (old)
448     g_object_unref (old);
449 }
450
451 /**
452  * gst_rtsp_media_factory_get_address_pool:
453  * @factory: a #GstRTSPMediaFactory
454  *
455  * Get the #GstRTSPAddressPool used as the address pool of @factory.
456  *
457  * Returns: (transfer full): the #GstRTSPAddressPool of @factory. g_object_unref() after
458  * usage.
459  */
460 GstRTSPAddressPool *
461 gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory)
462 {
463   GstRTSPAddressPool *result;
464
465   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
466
467   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
468   if ((result = factory->pool))
469     g_object_ref (result);
470   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
471
472   return result;
473 }
474
475 /**
476  * gst_rtsp_media_factory_set_auth:
477  * @factory: a #GstRTSPMediaFactory
478  * @auth: a #GstRTSPAuth
479  *
480  * configure @auth to be used as the authentication manager of @factory.
481  */
482 void
483 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
484     GstRTSPAuth * auth)
485 {
486   GstRTSPAuth *old;
487
488   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
489
490   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
491   if ((old = factory->auth) != auth)
492     factory->auth = auth ? g_object_ref (auth) : NULL;
493   else
494     old = NULL;
495   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
496
497   if (old)
498     g_object_unref (old);
499 }
500
501 /**
502  * gst_rtsp_media_factory_get_auth:
503  * @factory: a #GstRTSPMediaFactory
504  *
505  * Get the #GstRTSPAuth used as the authentication manager of @factory.
506  *
507  * Returns: (transfer full): the #GstRTSPAuth of @factory. g_object_unref() after
508  * usage.
509  */
510 GstRTSPAuth *
511 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
512 {
513   GstRTSPAuth *result;
514
515   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
516
517   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
518   if ((result = factory->auth))
519     g_object_ref (result);
520   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
521
522   return result;
523 }
524
525 /**
526  * gst_rtsp_media_factory_set_protocols:
527  * @factory: a #GstRTSPMediaFactory
528  * @protocols: the new flags
529  *
530  * Configure the allowed lower transport for @factory.
531  */
532 void
533 gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory,
534     GstRTSPLowerTrans protocols)
535 {
536   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
537
538   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
539   factory->protocols = protocols;
540   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
541 }
542
543 /**
544  * gst_rtsp_media_factory_get_protocols:
545  * @factory: a #GstRTSPMediaFactory
546  *
547  * Get the allowed protocols of @factory.
548  *
549  * Returns: a #GstRTSPLowerTrans
550  */
551 GstRTSPLowerTrans
552 gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
553 {
554   GstRTSPLowerTrans res;
555
556   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
557       GST_RTSP_LOWER_TRANS_UNKNOWN);
558
559   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
560   res = factory->protocols;
561   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
562
563   return res;
564 }
565
566 static gboolean
567 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
568 {
569   return (media1 == media2);
570 }
571
572 static void
573 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
574 {
575   g_mutex_lock (&factory->medias_lock);
576   g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
577   g_mutex_unlock (&factory->medias_lock);
578 }
579
580 /**
581  * gst_rtsp_media_factory_construct:
582  * @factory: a #GstRTSPMediaFactory
583  * @url: the url used
584  *
585  * Construct the media object and create its streams. Implementations
586  * should create the needed gstreamer elements and add them to the result
587  * object. No state changes should be performed on them yet.
588  *
589  * One or more GstRTSPStream objects should be created from the result
590  * with gst_rtsp_media_create_stream ().
591  *
592  * After the media is constructed, it can be configured and then prepared
593  * with gst_rtsp_media_prepare ().
594  *
595  * Returns: (transfer full): a new #GstRTSPMedia if the media could be prepared.
596  */
597 GstRTSPMedia *
598 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
599     const GstRTSPUrl * url)
600 {
601   gchar *key;
602   GstRTSPMedia *media;
603   GstRTSPMediaFactoryClass *klass;
604
605   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
606   g_return_val_if_fail (url != NULL, NULL);
607
608   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
609
610   /* convert the url to a key for the hashtable. NULL return or a NULL function
611    * will not cache anything for this factory. */
612   if (klass->gen_key)
613     key = klass->gen_key (factory, url);
614   else
615     key = NULL;
616
617   g_mutex_lock (&factory->medias_lock);
618   if (key) {
619     /* we have a key, see if we find a cached media */
620     media = g_hash_table_lookup (factory->medias, key);
621     if (media)
622       g_object_ref (media);
623   } else
624     media = NULL;
625
626   if (media == NULL) {
627     /* nothing cached found, try to create one */
628     if (klass->construct) {
629       media = klass->construct (factory, url);
630       if (media)
631         g_signal_emit (factory,
632             gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
633             NULL);
634     } else
635       media = NULL;
636
637     if (media) {
638       /* configure the media */
639       if (klass->configure)
640         klass->configure (factory, media);
641
642       g_signal_emit (factory,
643           gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
644           NULL);
645
646       /* check if we can cache this media */
647       if (gst_rtsp_media_is_shared (media)) {
648         /* insert in the hashtable, takes ownership of the key */
649         g_object_ref (media);
650         g_hash_table_insert (factory->medias, key, media);
651         key = NULL;
652       }
653       if (!gst_rtsp_media_is_reusable (media)) {
654         /* when not reusable, connect to the unprepare signal to remove the item
655          * from our cache when it gets unprepared */
656         g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
657             factory);
658       }
659     }
660   }
661   g_mutex_unlock (&factory->medias_lock);
662
663   if (key)
664     g_free (key);
665
666   GST_INFO ("constructed media %p for url %s", media, url->abspath);
667
668   return media;
669 }
670
671 static gchar *
672 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
673 {
674   gchar *result;
675   const gchar *pre_query;
676   const gchar *query;
677
678   pre_query = url->query ? "?" : "";
679   query = url->query ? url->query : "";
680
681   result =
682       g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
683
684   return result;
685 }
686
687 static GstElement *
688 default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
689 {
690   GstElement *element;
691   GError *error = NULL;
692
693   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
694   /* we need a parse syntax */
695   if (factory->launch == NULL)
696     goto no_launch;
697
698   /* parse the user provided launch line */
699   element = gst_parse_launch (factory->launch, &error);
700   if (element == NULL)
701     goto parse_error;
702
703   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
704
705   if (error != NULL) {
706     /* a recoverable error was encountered */
707     GST_WARNING ("recoverable parsing error: %s", error->message);
708     g_error_free (error);
709   }
710   return element;
711
712   /* ERRORS */
713 no_launch:
714   {
715     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
716     g_critical ("no launch line specified");
717     return NULL;
718   }
719 parse_error:
720   {
721     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
722     g_critical ("could not parse launch syntax (%s): %s", factory->launch,
723         (error ? error->message : "unknown reason"));
724     if (error)
725       g_error_free (error);
726     return NULL;
727   }
728 }
729
730 static GstRTSPMedia *
731 default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
732 {
733   GstRTSPMedia *media;
734   GstElement *element;
735   GstRTSPMediaFactoryClass *klass;
736
737   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
738
739   if (!klass->create_pipeline)
740     goto no_create;
741
742   element = gst_rtsp_media_factory_create_element (factory, url);
743   if (element == NULL)
744     goto no_element;
745
746   /* create a new empty media */
747   media = gst_rtsp_media_new ();
748   media->element = element;
749
750   gst_rtsp_media_collect_streams (media);
751
752   media->pipeline = klass->create_pipeline (factory, media);
753   if (media->pipeline == NULL)
754     goto no_pipeline;
755
756   return media;
757
758   /* ERRORS */
759 no_create:
760   {
761     g_critical ("no create_pipeline function");
762     return NULL;
763   }
764 no_element:
765   {
766     g_critical ("could not create element");
767     return NULL;
768   }
769 no_pipeline:
770   {
771     g_critical ("can't create pipeline");
772     g_object_unref (media);
773     return NULL;
774   }
775 }
776
777 static GstElement *
778 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
779 {
780   GstElement *pipeline;
781
782   if (media->element == NULL)
783     goto no_element;
784
785   pipeline = gst_pipeline_new ("media-pipeline");
786   gst_bin_add (GST_BIN_CAST (pipeline), media->element);
787
788   return pipeline;
789
790   /* ERRORS */
791 no_element:
792   {
793     g_critical ("no element");
794     return NULL;
795   }
796 }
797
798 static void
799 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
800 {
801   gboolean shared, eos_shutdown;
802   guint size;
803   GstRTSPAuth *auth;
804   GstRTSPLowerTrans protocols;
805   GstRTSPAddressPool *pool;
806
807   /* configure the sharedness */
808   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
809   shared = factory->shared;
810   eos_shutdown = factory->eos_shutdown;
811   size = factory->buffer_size;
812   protocols = factory->protocols;
813   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
814
815   gst_rtsp_media_set_shared (media, shared);
816   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
817   gst_rtsp_media_set_buffer_size (media, size);
818   gst_rtsp_media_set_protocols (media, protocols);
819
820   if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
821     gst_rtsp_media_set_auth (media, auth);
822     g_object_unref (auth);
823   }
824   if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) {
825     gst_rtsp_media_set_address_pool (media, pool);
826     g_object_unref (pool);
827   }
828 }
829
830 /**
831  * gst_rtsp_media_factory_create_element:
832  * @factory: a #GstRTSPMediaFactory
833  * @url: the url used
834  *
835  * Construct and return a #GstElement that is a #GstBin containing
836  * the elements to use for streaming the media.
837  *
838  * The bin should contain payloaders pay%d for each stream. The default
839  * implementation of this function returns the bin created from the
840  * launch parameter.
841  *
842  * Returns: (transfer floating) a new #GstElement.
843  */
844 GstElement *
845 gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory,
846     const GstRTSPUrl * url)
847 {
848   GstRTSPMediaFactoryClass *klass;
849   GstElement *result;
850
851   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
852
853   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
854
855   if (klass->create_element)
856     result = klass->create_element (factory, url);
857   else
858     result = NULL;
859
860   return result;
861 }