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