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