media-factory: add media-configure signal
[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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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_BUFFER_SIZE     0x80000
26 #define DEFAULT_MULTICAST_GROUP "224.2.0.1"
27
28 enum
29 {
30   PROP_0,
31   PROP_LAUNCH,
32   PROP_SHARED,
33   PROP_EOS_SHUTDOWN,
34   PROP_BUFFER_SIZE,
35   PROP_MULTICAST_GROUP,
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_get_element (GstRTSPMediaFactory * factory,
60     const GstRTSPUrl * url);
61 static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory,
62     const GstRTSPUrl * url);
63 static void default_configure (GstRTSPMediaFactory * factory,
64     GstRTSPMedia * media);
65 static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
66     GstRTSPMedia * media);
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_BUFFER_SIZE,
113       g_param_spec_uint ("buffer-size", "Buffer Size",
114           "The kernel UDP buffer size to use", 0, G_MAXUINT,
115           DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
116
117   g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
118       g_param_spec_string ("multicast-group", "Multicast Group",
119           "The Multicast group to send media to",
120           DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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->get_element = default_get_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->buffer_size = DEFAULT_BUFFER_SIZE;
151   factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP);
152
153   factory->lock = g_mutex_new ();
154   factory->medias_lock = g_mutex_new ();
155   factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
156       g_free, g_object_unref);
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_free (factory->medias_lock);
166   g_free (factory->launch);
167   g_free (factory->multicast_group);
168   g_mutex_free (factory->lock);
169   if (factory->auth)
170     g_object_unref (factory->auth);
171
172   G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
173 }
174
175 static void
176 gst_rtsp_media_factory_get_property (GObject * object, guint propid,
177     GValue * value, GParamSpec * pspec)
178 {
179   GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
180
181   switch (propid) {
182     case PROP_LAUNCH:
183       g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
184       break;
185     case PROP_SHARED:
186       g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
187       break;
188     case PROP_EOS_SHUTDOWN:
189       g_value_set_boolean (value,
190           gst_rtsp_media_factory_is_eos_shutdown (factory));
191       break;
192     case PROP_BUFFER_SIZE:
193       g_value_set_uint (value,
194           gst_rtsp_media_factory_get_buffer_size (factory));
195       break;
196     case PROP_MULTICAST_GROUP:
197       g_value_take_string (value,
198           gst_rtsp_media_factory_get_multicast_group (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_BUFFER_SIZE:
223       gst_rtsp_media_factory_set_buffer_size (factory,
224           g_value_get_uint (value));
225       break;
226     case PROP_MULTICAST_GROUP:
227       gst_rtsp_media_factory_set_multicast_group (factory,
228           g_value_get_string (value));
229       break;
230     default:
231       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
232   }
233 }
234
235 /**
236  * gst_rtsp_media_factory_new:
237  *
238  * Create a new #GstRTSPMediaFactory instance.
239  *
240  * Returns: a new #GstRTSPMediaFactory object.
241  */
242 GstRTSPMediaFactory *
243 gst_rtsp_media_factory_new (void)
244 {
245   GstRTSPMediaFactory *result;
246
247   result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
248
249   return result;
250 }
251
252 /**
253  * gst_rtsp_media_factory_set_launch:
254  * @factory: a #GstRTSPMediaFactory
255  * @launch: the launch description
256  *
257  *
258  * The gst_parse_launch() line to use for constructing the pipeline in the
259  * default prepare vmethod.
260  *
261  * The pipeline description should return a GstBin as the toplevel element
262  * which can be accomplished by enclosing the dscription with brackets '('
263  * ')'.
264  *
265  * The description should return a pipeline with payloaders named pay0, pay1,
266  * etc.. Each of the payloaders will result in a stream.
267  */
268 void
269 gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
270     const gchar * launch)
271 {
272   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
273   g_return_if_fail (launch != NULL);
274
275   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
276   g_free (factory->launch);
277   factory->launch = g_strdup (launch);
278   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
279 }
280
281 /**
282  * gst_rtsp_media_factory_get_launch:
283  * @factory: a #GstRTSPMediaFactory
284  *
285  * Get the gst_parse_launch() pipeline description that will be used in the
286  * default prepare vmethod.
287  *
288  * Returns: the configured launch description. g_free() after usage.
289  */
290 gchar *
291 gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
292 {
293   gchar *result;
294
295   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
296
297   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
298   result = g_strdup (factory->launch);
299   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
300
301   return result;
302 }
303
304 /**
305  * gst_rtsp_media_factory_set_shared:
306  * @factory: a #GstRTSPMediaFactory
307  * @shared: the new value
308  *
309  * Configure if media created from this factory can be shared between clients.
310  */
311 void
312 gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory,
313     gboolean shared)
314 {
315   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
316
317   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
318   factory->shared = shared;
319   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
320 }
321
322 /**
323  * gst_rtsp_media_factory_is_shared:
324  * @factory: a #GstRTSPMediaFactory
325  *
326  * Get if media created from this factory can be shared between clients.
327  *
328  * Returns: %TRUE if the media will be shared between clients.
329  */
330 gboolean
331 gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory)
332 {
333   gboolean result;
334
335   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
336
337   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
338   result = factory->shared;
339   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
340
341   return result;
342 }
343
344 /**
345  * gst_rtsp_media_factory_set_eos_shutdown:
346  * @factory: a #GstRTSPMediaFactory
347  * @eos_shutdown: the new value
348  *
349  * Configure if media created from this factory will have an EOS sent to the
350  * pipeline before shutdown.
351  */
352 void
353 gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
354     gboolean eos_shutdown)
355 {
356   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
357
358   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
359   factory->eos_shutdown = eos_shutdown;
360   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
361 }
362
363 /**
364  * gst_rtsp_media_factory_is_eos_shutdown:
365  * @factory: a #GstRTSPMediaFactory
366  *
367  * Get if media created from this factory will have an EOS event sent to the
368  * pipeline before shutdown.
369  *
370  * Returns: %TRUE if the media will receive EOS before shutdown.
371  */
372 gboolean
373 gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
374 {
375   gboolean result;
376
377   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
378
379   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
380   result = factory->eos_shutdown;
381   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
382
383   return result;
384 }
385
386 /**
387  * gst_rtsp_media_factory_set_buffer_size:
388  * @factory: a #GstRTSPMedia
389  * @size: the new value
390  *
391  * Set the kernel UDP buffer size.
392  */
393 void
394 gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
395     guint size)
396 {
397   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
398
399   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
400   factory->buffer_size = size;
401   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
402 }
403
404 /**
405  * gst_rtsp_media_factory_get_buffer_size:
406  * @factory: a #GstRTSPMedia
407  *
408  * Get the kernel UDP buffer size.
409  *
410  * Returns: the kernel UDP buffer size.
411  */
412 guint
413 gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
414 {
415   guint result;
416
417   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
418
419   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
420   result = factory->buffer_size;
421   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
422
423   return result;
424 }
425
426 /**
427  * gst_rtsp_media_factory_set_multicast_group:
428  * @factory: a #GstRTSPMedia
429  * @mc: the new multicast group
430  *
431  * Set the multicast group that media from @factory will be streamed to.
432  */
433 void
434 gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory,
435     const gchar * mc)
436 {
437   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
438
439   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
440   g_free (factory->multicast_group);
441   factory->multicast_group = g_strdup (mc);
442   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
443 }
444
445 /**
446  * gst_rtsp_media_factory_get_multicast_group:
447  * @factory: a #GstRTSPMedia
448  *
449  * Get the multicast group that media from @factory will be streamed to.
450  *
451  * Returns: the multicast group
452  */
453 gchar *
454 gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory)
455 {
456   gchar *result;
457
458   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
459
460   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
461   result = g_strdup (factory->multicast_group);
462   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
463
464   return result;
465 }
466
467 /**
468  * gst_rtsp_media_factory_set_auth:
469  * @factory: a #GstRTSPMediaFactory
470  * @auth: a #GstRTSPAuth
471  *
472  * configure @auth to be used as the authentication manager of @factory.
473  */
474 void
475 gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
476     GstRTSPAuth * auth)
477 {
478   GstRTSPAuth *old;
479
480   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
481
482   old = factory->auth;
483
484   if (old != auth) {
485     if (auth)
486       g_object_ref (auth);
487     factory->auth = auth;
488     if (old)
489       g_object_unref (old);
490   }
491 }
492
493 /**
494  * gst_rtsp_media_factory_get_auth:
495  * @factory: a #GstRTSPMediaFactory
496  *
497  * Get the #GstRTSPAuth used as the authentication manager of @factory.
498  *
499  * Returns: the #GstRTSPAuth of @factory. g_object_unref() after
500  * usage.
501  */
502 GstRTSPAuth *
503 gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
504 {
505   GstRTSPAuth *result;
506
507   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
508
509   if ((result = factory->auth))
510     g_object_ref (result);
511
512   return result;
513 }
514
515 static gboolean
516 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
517 {
518   return (media1 == media2);
519 }
520
521 static void
522 media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
523 {
524   g_mutex_lock (factory->medias_lock);
525   g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
526   g_mutex_unlock (factory->medias_lock);
527 }
528
529 /**
530  * gst_rtsp_media_factory_construct:
531  * @factory: a #GstRTSPMediaFactory
532  * @url: the url used
533  *
534  * Prepare the media object and create its streams. Implementations
535  * should create the needed gstreamer elements and add them to the result
536  * object. No state changes should be performed on them yet.
537  *
538  * One or more GstRTSPMediaStream objects should be added to the result with
539  * the srcpad member set to a source pad that produces buffer of type 
540  * application/x-rtp.
541  *
542  * Returns: a new #GstRTSPMedia if the media could be prepared.
543  */
544 GstRTSPMedia *
545 gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
546     const GstRTSPUrl * url)
547 {
548   gchar *key;
549   GstRTSPMedia *media;
550   GstRTSPMediaFactoryClass *klass;
551
552   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
553
554   /* convert the url to a key for the hashtable. NULL return or a NULL function
555    * will not cache anything for this factory. */
556   if (klass->gen_key)
557     key = klass->gen_key (factory, url);
558   else
559     key = NULL;
560
561   g_mutex_lock (factory->medias_lock);
562   if (key) {
563     /* we have a key, see if we find a cached media */
564     media = g_hash_table_lookup (factory->medias, key);
565     if (media)
566       g_object_ref (media);
567   } else
568     media = NULL;
569
570   if (media == NULL) {
571     /* nothing cached found, try to create one */
572     if (klass->construct) {
573       media = klass->construct (factory, url);
574       if (media)
575         g_signal_emit (factory,
576             gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
577             NULL);
578     } else
579       media = NULL;
580
581     if (media) {
582       /* configure the media */
583       if (klass->configure)
584         klass->configure (factory, media);
585
586       g_signal_emit (factory,
587           gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
588           NULL);
589
590       /* check if we can cache this media */
591       if (gst_rtsp_media_is_shared (media)) {
592         /* insert in the hashtable, takes ownership of the key */
593         g_object_ref (media);
594         g_hash_table_insert (factory->medias, key, media);
595         key = NULL;
596       }
597       if (!gst_rtsp_media_is_reusable (media)) {
598         /* when not reusable, connect to the unprepare signal to remove the item
599          * from our cache when it gets unprepared */
600         g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
601             factory);
602       }
603     }
604   }
605   g_mutex_unlock (factory->medias_lock);
606
607   if (key)
608     g_free (key);
609
610   GST_INFO ("constructed media %p for url %s", media, url->abspath);
611
612   return media;
613 }
614
615 static gchar *
616 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
617 {
618   gchar *result;
619   const gchar *pre_query;
620   const gchar *query;
621
622   pre_query = url->query ? "?" : "";
623   query = url->query ? url->query : "";
624
625   result =
626       g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
627
628   return result;
629 }
630
631 static GstElement *
632 default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
633 {
634   GstElement *element;
635   GError *error = NULL;
636
637   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
638   /* we need a parse syntax */
639   if (factory->launch == NULL)
640     goto no_launch;
641
642   /* parse the user provided launch line */
643   element = gst_parse_launch (factory->launch, &error);
644   if (element == NULL)
645     goto parse_error;
646
647   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
648
649   if (error != NULL) {
650     /* a recoverable error was encountered */
651     GST_WARNING ("recoverable parsing error: %s", error->message);
652     g_error_free (error);
653   }
654   return element;
655
656   /* ERRORS */
657 no_launch:
658   {
659     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
660     g_critical ("no launch line specified");
661     return NULL;
662   }
663 parse_error:
664   {
665     GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
666     g_critical ("could not parse launch syntax (%s): %s", factory->launch,
667         (error ? error->message : "unknown reason"));
668     if (error)
669       g_error_free (error);
670     return NULL;
671   }
672 }
673
674 /* try to find all the payloader elements, they should be named 'pay%d'. for
675  * each of the payloaders we will create a stream and collect the source pad. */
676 void
677 gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
678     const GstRTSPUrl * url, GstRTSPMedia * media)
679 {
680   GstElement *element, *elem;
681   GstPad *pad;
682   gint i;
683   GstRTSPMediaStream *stream;
684   gboolean have_elem;
685
686   element = media->element;
687
688   have_elem = TRUE;
689   for (i = 0; have_elem; i++) {
690     gchar *name;
691
692     have_elem = FALSE;
693
694     name = g_strdup_printf ("pay%d", i);
695     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
696       /* create the stream */
697       stream = g_new0 (GstRTSPMediaStream, 1);
698       stream->payloader = elem;
699
700       GST_INFO ("found stream %d with payloader %p", i, elem);
701
702       pad = gst_element_get_static_pad (elem, "src");
703
704       /* ghost the pad of the payloader to the element */
705       stream->srcpad = gst_ghost_pad_new (name, pad);
706       gst_pad_set_active (stream->srcpad, TRUE);
707       gst_element_add_pad (media->element, stream->srcpad);
708       gst_object_unref (elem);
709
710       /* add stream now */
711       g_array_append_val (media->streams, stream);
712       have_elem = TRUE;
713     }
714     g_free (name);
715
716     name = g_strdup_printf ("dynpay%d", i);
717     if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
718       /* a stream that will dynamically create pads to provide RTP packets */
719
720       GST_INFO ("found dynamic element %d, %p", i, elem);
721
722       media->dynamic = g_list_prepend (media->dynamic, elem);
723
724       have_elem = TRUE;
725     }
726     g_free (name);
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   if (klass->get_element)
743     element = klass->get_element (factory, url);
744   else
745     element = NULL;
746   if (element == NULL)
747     goto no_element;
748
749   /* create a new empty media */
750   media = gst_rtsp_media_new ();
751   media->element = element;
752
753   media->pipeline = klass->create_pipeline (factory, media);
754   if (media->pipeline == NULL)
755     goto no_pipeline;
756
757   gst_rtsp_media_factory_collect_streams (factory, url, media);
758
759   return media;
760
761   /* ERRORS */
762 no_create:
763   {
764     g_critical ("no create_pipeline function");
765     return NULL;
766   }
767 no_element:
768   {
769     g_critical ("could not create element");
770     return NULL;
771   }
772 no_pipeline:
773   {
774     g_critical ("can't create pipeline");
775     g_object_unref (media);
776     return NULL;
777   }
778 }
779
780 static GstElement *
781 default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
782 {
783   GstElement *pipeline;
784
785   if (media->element == NULL)
786     goto no_element;
787
788   pipeline = gst_pipeline_new ("media-pipeline");
789   gst_bin_add (GST_BIN_CAST (pipeline), media->element);
790
791   return pipeline;
792
793   /* ERRORS */
794 no_element:
795   {
796     g_critical ("no element");
797     return NULL;
798   }
799 }
800
801 static void
802 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
803 {
804   gboolean shared, eos_shutdown;
805   guint size;
806   GstRTSPAuth *auth;
807   gchar *mc;
808
809   /* configure the sharedness */
810   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
811   shared = factory->shared;
812   eos_shutdown = factory->eos_shutdown;
813   size = factory->buffer_size;
814   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
815
816   gst_rtsp_media_set_shared (media, shared);
817   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
818   gst_rtsp_media_set_buffer_size (media, size);
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 ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) {
825     gst_rtsp_media_set_multicast_group (media, mc);
826     g_free (mc);
827   }
828 }