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