This is a megapatch with the following changes:
[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_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_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_NAME(src), GST_ELEMENT_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 (gst_pad_get_direction(sinkpad)   == GST_PAD_SINK &&
200         !GST_PAD_CONNECTED(sinkpad))
201     {
202       if (gst_caps_list_check_compatibility (gst_pad_get_caps_list(pad), gst_pad_get_caps_list(sinkpad))) {
203         gst_pad_connect(pad, sinkpad);
204         GST_DEBUG (0,"gstpipeline: autoconnect pad \"%s\" in element %s <-> ", GST_PAD_NAME (pad),
205                        GST_ELEMENT_NAME(src));
206         GST_DEBUG (0,"pad \"%s\" in element %s\n", GST_PAD_NAME (sinkpad),
207                       GST_ELEMENT_NAME(sink));
208         connected = TRUE;
209         break;
210       }
211       else {
212         GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_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 (gst_pad_get_direction(srcpad) == 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_NAME(src), GST_ELEMENT_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_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_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_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_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_NAME(pipeline->src), 
339           src_caps->id);
340   }
341   else {
342     GST_DEBUG (0,"GstPipeline: source \"%s\" has no type\n", GST_ELEMENT_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), 
366 gst_pad_get_caps_list(pad));
367     // if we have a succesfull connection, proceed
368     if (factories[i] != NULL) {
369       i++;
370     }
371     else {
372       sinkstart = g_list_remove (sinkstart, element);
373     }
374
375     elements = g_list_next(elements);
376   }
377   
378   while (factories[0]) {
379     // fase 3: add common elements 
380     factory = (GstElementFactory *)(factories[0]->data);
381
382     // check to other paths for mathing elements (factories)
383     for (i=1; i<numsinks; i++) {
384       if (!factories[i] || (factory != (GstElementFactory *)(factories[i]->data))) {
385         goto differ;
386       }
387       factories[i] = g_list_next(factories[i]);
388     }
389     factory = (GstElementFactory *)(factories[0]->data);
390
391     GST_DEBUG (0,"common factory \"%s\"\n", factory->name);
392
393     element = gst_elementfactory_create(factory, factory->name);
394     gst_bin_add(GST_BIN(pipeline), element);
395
396     gst_pipeline_pads_autoplug(srcelement, element);
397
398     srcelement = element;
399
400     factories[0] = g_list_next(factories[0]);
401
402     have_common = TRUE;
403   }
404
405 differ:
406   // loop over all the sink elements
407   elements = sinkstart;
408
409   i = 0;
410   while (elements) {
411     GstElement *thesrcelement = srcelement;
412     GstElement *thebin = GST_ELEMENT(pipeline);
413
414     if (g_list_length(base_factories[i]) == 0) goto next;
415
416     sinkelement = (GstElement *)elements->data;
417
418     use_thread = have_common;
419
420     while (factories[i] || sinkelement) {
421       // fase 4: add other elements...
422        
423       if (factories[i]) {
424         factory = (GstElementFactory *)(factories[i]->data);
425         GST_DEBUG (0,"factory \"%s\"\n", factory->name);
426         element = gst_elementfactory_create(factory, factory->name);
427         factories[i] = g_list_next(factories[i]);
428       }
429       // we have arived to the final sink element
430       else {
431         element = sinkelement;
432         sinkelement = NULL;
433       }
434
435       // this element suggests the use of a thread, so we set one up...
436       if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) {
437         GstElement *queue;
438         GList *sinkpads;
439         GstPad *srcpad, *sinkpad;
440
441         use_thread = FALSE;
442
443         GST_DEBUG (0,"sugest new thread for \"%s\" %08x\n", GST_ELEMENT_NAME (element), GST_FLAGS(element));
444
445         // create a new queue and add to the previous bin
446         queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL));
447         GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element));
448         gst_bin_add(GST_BIN(thebin), queue);
449
450         // this will be the new bin for all following elements
451         thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL));
452
453         srcpad = gst_element_get_pad(queue, "src");
454
455         sinkpads = gst_element_get_pad_list(element);
456         while (sinkpads) {
457           sinkpad = (GstPad *)sinkpads->data;
458
459           // FIXME connect matching pads, not just the first one...
460           if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK && 
461               !GST_PAD_CONNECTED(sinkpad)) {
462             GList *caps = gst_pad_get_caps_list (sinkpad);
463
464             // the queue has the type of the elements it connects
465             gst_pad_set_caps_list (srcpad, caps);
466             gst_pad_set_caps_list (gst_element_get_pad(queue, "sink"), caps);
467             break;
468           }
469           sinkpads = g_list_next(sinkpads);
470         }
471         gst_pipeline_pads_autoplug(thesrcelement, queue);
472
473         GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element));
474         gst_bin_add(GST_BIN(thebin), element);
475         GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (thebin));
476         gst_bin_add(GST_BIN(pipeline), thebin);
477         thesrcelement = queue;
478       }
479       // no thread needed, easy case
480       else {
481         GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element));
482         gst_bin_add(GST_BIN(thebin), element);
483       }
484       gst_pipeline_pads_autoplug(thesrcelement, element);
485
486       // this element is now the new source element
487       thesrcelement = element;
488     }
489 next:
490     elements = g_list_next(elements);
491     i++;
492   }
493   return TRUE;
494   
495   GST_DEBUG (0,"GstPipeline: unable to autoplug pipeline \"%s\"\n", 
496                   GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
497   return FALSE;
498 }
499
500 static GstElementStateReturn 
501 gst_pipeline_change_state (GstElement *element) 
502 {
503   GstPipeline *pipeline;
504
505   g_return_val_if_fail (GST_IS_PIPELINE (element), FALSE);
506   
507   pipeline = GST_PIPELINE (element);
508
509   switch (GST_STATE_TRANSITION (pipeline)) {
510     case GST_STATE_NULL_TO_READY:
511       // we need to set up internal state
512       gst_pipeline_prepare (pipeline);
513       break;
514     default:
515       break;
516   }
517     
518   if (GST_ELEMENT_CLASS (parent_class)->change_state)
519     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
520   
521   return GST_STATE_SUCCESS;
522 }
523
524
525 /**
526  * gst_pipeline_iterate:
527  * @pipeline: #GstPipeline to iterate
528  *
529  * Cause the pipeline's contents to be run through one full 'iteration'.
530  */
531 void 
532 gst_pipeline_iterate (GstPipeline *pipeline) 
533 {
534   g_return_if_fail (pipeline != NULL);
535   g_return_if_fail (GST_IS_PIPELINE(pipeline));
536 }