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