Cleaned up the docs a bit.
[platform/upstream/gstreamer.git] / gst / gstpipeline.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstpipeline.c: Overall pipeline management element
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
25
26 #include "gstpipeline.h"
27 #include "gstthread.h"
28 #include "gstutils.h"
29 #include "gsttype.h"
30 #include "gstautoplug.h"
31
32
33 GstElementDetails gst_pipeline_details = {
34   "Pipeline object",
35   "Bin",
36   "Complete pipeline object",
37   VERSION,
38   "Erik Walthinsen <omega@cse.ogi.edu>",
39   "(C) 1999",
40 };
41
42 /* Pipeline signals and args */
43 enum {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum {
49   ARG_0,
50   /* FILL ME */
51 };
52
53
54 static void                     gst_pipeline_class_init         (GstPipelineClass *klass);
55 static void                     gst_pipeline_init               (GstPipeline *pipeline);
56
57 static GstElementStateReturn    gst_pipeline_change_state       (GstElement *element);
58
59 static void                     gst_pipeline_prepare            (GstPipeline *pipeline);
60
61 static void                     gst_pipeline_have_type          (GstElement *sink, GstElement *sink2, gpointer data);
62 static void                     gst_pipeline_pads_autoplug      (GstElement *src, GstElement *sink);
63
64 static GstBinClass *parent_class = NULL;
65 //static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
66
67 GtkType
68 gst_pipeline_get_type (void) {
69   static GtkType pipeline_type = 0;
70
71   if (!pipeline_type) {
72     static const GtkTypeInfo pipeline_info = {
73       "GstPipeline",
74       sizeof(GstPipeline),
75       sizeof(GstPipelineClass),
76       (GtkClassInitFunc)gst_pipeline_class_init,
77       (GtkObjectInitFunc)gst_pipeline_init,
78       (GtkArgSetFunc)NULL,
79       (GtkArgGetFunc)NULL,
80       (GtkClassInitFunc)NULL,
81     };
82     pipeline_type = gtk_type_unique (gst_bin_get_type (), &pipeline_info);
83   }
84   return pipeline_type;
85 }
86
87 static void
88 gst_pipeline_class_init (GstPipelineClass *klass) 
89 {
90   GstElementClass *gstelement_class;
91
92   gstelement_class = (GstElementClass*)klass;
93
94   parent_class = gtk_type_class(gst_bin_get_type());
95
96   gstelement_class->change_state = gst_pipeline_change_state;
97 }
98
99 static void 
100 gst_pipeline_init (GstPipeline *pipeline) 
101 {
102   // we're a manager by default
103   GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
104
105   pipeline->src = NULL;
106   pipeline->sinks = NULL;
107 }
108
109
110 /**
111  * gst_pipeline_new:
112  * @name: name of new pipeline
113  *
114  * Create a new pipeline with the given name.
115  *
116  * Returns: newly created GstPipeline
117  */
118 GstElement*
119 gst_pipeline_new (guchar *name) 
120 {
121   return gst_elementfactory_make ("pipeline", name);
122 }
123
124 static void 
125 gst_pipeline_prepare (GstPipeline *pipeline) 
126 {
127   GST_DEBUG (0,"GstPipeline: preparing pipeline \"%s\" for playing\n", 
128                   gst_element_get_name(GST_ELEMENT(pipeline)));
129 }
130
131 static void 
132 gst_pipeline_have_type (GstElement *sink, GstElement *sink2, gpointer data) 
133 {
134   GST_DEBUG (0,"GstPipeline: pipeline have type %p\n", (gboolean *)data);
135
136   *(gboolean *)data = TRUE;
137 }
138
139 static GstCaps* 
140 gst_pipeline_typefind (GstPipeline *pipeline, GstElement *element) 
141 {
142   gboolean found = FALSE;
143   GstElement *typefind;
144   GstCaps *caps = NULL;
145
146   GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n", 
147                   gst_element_get_name(element), &found);
148
149   typefind = gst_elementfactory_make ("typefind", "typefind");
150   g_return_val_if_fail (typefind != NULL, FALSE);
151
152   gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
153                       GTK_SIGNAL_FUNC (gst_pipeline_have_type), &found);
154
155   gst_pad_connect (gst_element_get_pad (element, "src"),
156                    gst_element_get_pad (typefind, "sink"));
157
158   gst_bin_add (GST_BIN (pipeline), typefind);
159
160   //gst_bin_create_plan (GST_BIN (pipeline));
161   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY);
162   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
163
164   // keep pushing buffers... the have_type signal handler will set the found flag
165   while (!found) {
166     gst_bin_iterate (GST_BIN (pipeline));
167   }
168
169   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
170
171   if (found) {
172     caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
173     
174     gst_pad_set_caps_list (gst_element_get_pad (element, "src"), g_list_prepend (NULL, caps));
175   }
176
177   gst_pad_disconnect (gst_element_get_pad (element, "src"),
178                       gst_element_get_pad (typefind, "sink"));
179   gst_bin_remove (GST_BIN (pipeline), typefind);
180   gst_object_unref (GST_OBJECT (typefind));
181
182   return caps;
183 }
184
185 static gboolean 
186 gst_pipeline_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink) 
187 {
188   GList *sinkpads;
189   gboolean connected = FALSE;
190
191   GST_DEBUG (0,"gstpipeline: autoplug pad connect function for \"%s\" to \"%s\"\n", 
192                   gst_element_get_name(src), gst_element_get_name(sink));
193
194   sinkpads = gst_element_get_pad_list(sink);
195   while (sinkpads) {
196     GstPad *sinkpad = (GstPad *)sinkpads->data;
197
198     // if we have a match, connect the pads
199     if (sinkpad->direction == GST_PAD_SINK && 
200         !GST_PAD_CONNECTED(sinkpad)) 
201     {
202       if (gst_caps_list_check_compatibility (pad->caps, sinkpad->caps)) {
203         gst_pad_connect(pad, sinkpad);
204         GST_DEBUG (0,"gstpipeline: autoconnect pad \"%s\" in element %s <-> ", pad->name, 
205                        gst_element_get_name(src));
206         GST_DEBUG (0,"pad \"%s\" in element %s\n", sinkpad->name,  
207                       gst_element_get_name(sink));
208         connected = TRUE;
209         break;
210       }
211       else {
212         GST_DEBUG (0,"pads incompatible %s, %s\n", gst_pad_get_name (pad), gst_pad_get_name (sinkpad));
213       }
214     }
215     sinkpads = g_list_next(sinkpads);
216   }
217
218   if (!connected) {
219     GST_DEBUG (0,"gstpipeline: no path to sinks for type\n");
220   }
221   return connected;
222 }
223
224 static void 
225 gst_pipeline_pads_autoplug (GstElement *src, GstElement *sink) 
226 {
227   GList *srcpads;
228   gboolean connected = FALSE;
229
230   srcpads = gst_element_get_pad_list(src);
231
232   while (srcpads && !connected) {
233     GstPad *srcpad = (GstPad *)srcpads->data;
234
235     if (srcpad->direction == GST_PAD_SRC) 
236       connected = gst_pipeline_pads_autoplug_func (src, srcpad, sink);
237
238     srcpads = g_list_next(srcpads);
239   }
240   
241   if (!connected) {
242     GST_DEBUG (0,"gstpipeline: delaying pad connections for \"%s\" to \"%s\"\n",
243                     gst_element_get_name(src), gst_element_get_name(sink));
244     gtk_signal_connect(GTK_OBJECT(src),"new_pad",
245                  GTK_SIGNAL_FUNC(gst_pipeline_pads_autoplug_func), sink);
246   }
247 }
248
249 /**
250  * gst_pipeline_add_src:
251  * @pipeline: the pipeline to add the src to
252  * @src: the src to add to the pipeline
253  *
254  * Adds a src element to the pipeline. This element
255  * will be used as a src for autoplugging. If you add more
256  * than one src element, the previously added element will
257  * be removed.
258  */
259 void 
260 gst_pipeline_add_src (GstPipeline *pipeline, GstElement *src) 
261 {
262   g_return_if_fail (pipeline != NULL);
263   g_return_if_fail (GST_IS_PIPELINE (pipeline));
264   g_return_if_fail (src != NULL);
265   g_return_if_fail (GST_IS_ELEMENT (src));
266
267   if (pipeline->src) {
268     printf("gstpipeline: *WARNING* removing previously added element \"%s\"\n",
269                           gst_element_get_name(pipeline->src));
270     gst_bin_remove(GST_BIN(pipeline), pipeline->src);
271   }
272   pipeline->src = src;
273   gst_bin_add(GST_BIN(pipeline), src);
274 }
275
276 /**
277  * gst_pipeline_add_sink:
278  * @pipeline: the pipeline to add the sink to
279  * @sink: the sink to add to the pipeline
280  *
281  * Adds a sink element to the pipeline. This element
282  * will be used as a sink for autoplugging.
283  */
284 void 
285 gst_pipeline_add_sink (GstPipeline *pipeline, GstElement *sink) 
286 {
287   g_return_if_fail (pipeline != NULL);
288   g_return_if_fail (GST_IS_PIPELINE (pipeline));
289   g_return_if_fail (sink != NULL);
290   g_return_if_fail (GST_IS_ELEMENT (sink));
291
292   pipeline->sinks = g_list_prepend (pipeline->sinks, sink);
293   //gst_bin_add(GST_BIN(pipeline), sink);
294 }
295
296 /**
297  * gst_pipeline_autoplug:
298  * @pipeline: the pipeline to autoplug
299  *
300  * Constructs a complete pipeline by automatically
301  * detecting the plugins needed.
302  *
303  * Returns: a gboolean indicating success or failure.
304  */
305 gboolean 
306 gst_pipeline_autoplug (GstPipeline *pipeline) 
307 {
308   GList *elements;
309   GstElement *element, *srcelement = NULL, *sinkelement= NULL;
310   GList **factories;
311   GList **base_factories;
312   GstElementFactory *factory;
313   GstCaps *src_caps = 0;
314   guint i, numsinks;
315   gboolean use_thread = FALSE, have_common = FALSE;
316   GList *sinkstart;
317
318   g_return_val_if_fail(pipeline != NULL, FALSE);
319   g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
320
321   GST_DEBUG (0,"GstPipeline: autopluging pipeline \"%s\"\n", 
322                   gst_element_get_name(GST_ELEMENT(pipeline)));
323
324
325   // fase 1, run typedetect on the source if needed... 
326   if (!pipeline->src) {
327     GST_DEBUG (0,"GstPipeline: no source detected, can't autoplug pipeline \"%s\"\n", 
328                 gst_element_get_name(GST_ELEMENT(pipeline)));
329     return FALSE;
330   }
331
332   GST_DEBUG (0,"GstPipeline: source \"%s\" has no MIME type, running typefind...\n", 
333         gst_element_get_name(pipeline->src));
334
335   src_caps = gst_pipeline_typefind(pipeline, pipeline->src);
336
337   if (src_caps) {
338     GST_DEBUG (0,"GstPipeline: source \"%s\" type found %d\n", gst_element_get_name(pipeline->src), 
339           src_caps->id);
340   }
341   else {
342     GST_DEBUG (0,"GstPipeline: source \"%s\" has no type\n", gst_element_get_name(pipeline->src));
343     return FALSE;
344   }
345
346   srcelement = pipeline->src;
347
348   elements = pipeline->sinks;
349
350   sinkstart = g_list_copy (elements);
351
352   numsinks = g_list_length(elements);
353   factories = g_new0(GList *, numsinks);
354   base_factories = g_new0(GList *, numsinks);
355
356   i = 0;
357   // fase 2, loop over all the sinks..
358   while (elements) {
359     GstPad *pad;
360
361     element = GST_ELEMENT(elements->data);
362
363     pad = (GstPad *)gst_element_get_pad_list (element)->data;
364
365     base_factories[i] = factories[i] = gst_autoplug_caps_list (g_list_append(NULL,src_caps), pad->caps);
366     // if we have a succesfull connection, proceed
367     if (factories[i] != NULL) {
368       i++;
369     }
370     else {
371       sinkstart = g_list_remove (sinkstart, element);
372     }
373
374     elements = g_list_next(elements);
375   }
376   
377   while (factories[0]) {
378     // fase 3: add common elements 
379     factory = (GstElementFactory *)(factories[0]->data);
380
381     // check to other paths for mathing elements (factories)
382     for (i=1; i<numsinks; i++) {
383       if (!factories[i] || (factory != (GstElementFactory *)(factories[i]->data))) {
384         goto differ;
385       }
386       factories[i] = g_list_next(factories[i]);
387     }
388     factory = (GstElementFactory *)(factories[0]->data);
389
390     GST_DEBUG (0,"common factory \"%s\"\n", factory->name);
391
392     element = gst_elementfactory_create(factory, factory->name);
393     gst_bin_add(GST_BIN(pipeline), element);
394
395     gst_pipeline_pads_autoplug(srcelement, element);
396
397     srcelement = element;
398
399     factories[0] = g_list_next(factories[0]);
400
401     have_common = TRUE;
402   }
403
404 differ:
405   // loop over all the sink elements
406   elements = sinkstart;
407
408   i = 0;
409   while (elements) {
410     GstElement *thesrcelement = srcelement;
411     GstElement *thebin = GST_ELEMENT(pipeline);
412
413     if (g_list_length(base_factories[i]) == 0) goto next;
414
415     sinkelement = (GstElement *)elements->data;
416
417     use_thread = have_common;
418
419     while (factories[i] || sinkelement) {
420       // fase 4: add other elements...
421        
422       if (factories[i]) {
423         factory = (GstElementFactory *)(factories[i]->data);
424         GST_DEBUG (0,"factory \"%s\"\n", factory->name);
425         element = gst_elementfactory_create(factory, factory->name);
426         factories[i] = g_list_next(factories[i]);
427       }
428       // we have arived to the final sink element
429       else {
430         element = sinkelement;
431         sinkelement = NULL;
432       }
433
434       // this element suggests the use of a thread, so we set one up...
435       if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) {
436         GstElement *queue;
437         GList *sinkpads;
438         GstPad *srcpad, *sinkpad;
439
440         use_thread = FALSE;
441
442         GST_DEBUG (0,"sugest new thread for \"%s\" %08x\n", element->name, GST_FLAGS(element));
443
444         // create a new queue and add to the previous bin
445         queue = gst_elementfactory_make("queue", g_strconcat("queue_", gst_element_get_name(element), NULL));
446         GST_DEBUG (0,"adding element \"%s\"\n", element->name);
447         gst_bin_add(GST_BIN(thebin), queue);
448
449         // this will be the new bin for all following elements
450         thebin = gst_elementfactory_make("thread", g_strconcat("thread_", gst_element_get_name(element), NULL));
451
452         srcpad = gst_element_get_pad(queue, "src");
453
454         sinkpads = gst_element_get_pad_list(element);
455         while (sinkpads) {
456           sinkpad = (GstPad *)sinkpads->data;
457
458           // FIXME connect matching pads, not just the first one...
459           if (sinkpad->direction == GST_PAD_SINK && 
460               !GST_PAD_CONNECTED(sinkpad)) {
461             GList *caps = gst_pad_get_caps_list (sinkpad);
462
463             // the queue has the type of the elements it connects
464             gst_pad_set_caps_list (srcpad, caps);
465             gst_pad_set_caps_list (gst_element_get_pad(queue, "sink"), caps);
466             break;
467           }
468           sinkpads = g_list_next(sinkpads);
469         }
470         gst_pipeline_pads_autoplug(thesrcelement, queue);
471
472         GST_DEBUG (0,"adding element %s\n", gst_element_get_name (element));
473         gst_bin_add(GST_BIN(thebin), element);
474         GST_DEBUG (0,"adding element %s\n", gst_element_get_name (thebin));
475         gst_bin_add(GST_BIN(pipeline), thebin);
476         thesrcelement = queue;
477       }
478       // no thread needed, easy case
479       else {
480         GST_DEBUG (0,"adding element %s\n", gst_element_get_name (element));
481         gst_bin_add(GST_BIN(thebin), element);
482       }
483       gst_pipeline_pads_autoplug(thesrcelement, element);
484
485       // this element is now the new source element
486       thesrcelement = element;
487     }
488 next:
489     elements = g_list_next(elements);
490     i++;
491   }
492   return TRUE;
493   
494   GST_DEBUG (0,"GstPipeline: unable to autoplug pipeline \"%s\"\n", 
495                   gst_element_get_name(GST_ELEMENT(pipeline)));
496   return FALSE;
497 }
498
499 static GstElementStateReturn 
500 gst_pipeline_change_state (GstElement *element) 
501 {
502   GstPipeline *pipeline;
503
504   g_return_val_if_fail (GST_IS_PIPELINE (element), FALSE);
505   
506   pipeline = GST_PIPELINE (element);
507
508   switch (GST_STATE_TRANSITION (pipeline)) {
509     case GST_STATE_NULL_TO_READY:
510       // we need to set up internal state
511       gst_pipeline_prepare (pipeline);
512       break;
513     default:
514       break;
515   }
516     
517   if (GST_ELEMENT_CLASS (parent_class)->change_state)
518     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
519   
520   return GST_STATE_SUCCESS;
521 }
522
523
524 /**
525  * gst_pipeline_iterate:
526  * @pipeline: #GstPipeline to iterate
527  *
528  * Cause the pipeline's contents to be run through one full 'iteration'.
529  */
530 void 
531 gst_pipeline_iterate (GstPipeline *pipeline) 
532 {
533   g_return_if_fail (pipeline != NULL);
534   g_return_if_fail (GST_IS_PIPELINE(pipeline));
535 }