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