Fixed a severe timestamp bug in mpeg_play.
[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   GstElementClass *gstelement_class;
86
87   gstelement_class = (GstElementClass*)klass;
88
89   parent_class = gtk_type_class(gst_bin_get_type());
90
91   gstelement_class->change_state = gst_pipeline_change_state;
92   gstelement_class->elementfactory = gst_elementfactory_find("pipeline");
93 }
94
95 static void gst_pipeline_init(GstPipeline *pipeline) {
96   pipeline->src = NULL;
97   pipeline->sinks = NULL;
98 }
99
100
101 /**
102  * gst_pipeline_new:
103  * @name: name of new pipeline
104  *
105  * Create a new pipeline with the given name.
106  *
107  * Returns: newly created GstPipeline
108  */
109 GstElement *gst_pipeline_new(guchar *name) {
110   GstPipeline *pipeline;
111
112   pipeline = gtk_type_new(gst_pipeline_get_type());
113   gst_element_set_name(GST_ELEMENT(pipeline),name);
114   return GST_ELEMENT(pipeline);
115 }
116
117 static void gst_pipeline_prepare(GstPipeline *pipeline) {
118   g_print("GstPipeline: preparing pipeline \"%s\" for playing\n", 
119                   gst_element_get_name(GST_ELEMENT(pipeline)));
120 }
121
122 static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data) {
123   g_print("GstPipeline: pipeline have type %p\n", (gboolean *)data);
124
125   *(gboolean *)data = TRUE;
126 }
127
128 static guint16 gst_pipeline_typefind(GstPipeline *pipeline, GstElement *element) {
129   gboolean found = FALSE;
130   GstElement *typefind;
131   guint16 type_id = 0;
132
133   g_print("GstPipeline: typefind for element \"%s\" %p\n", 
134                   gst_element_get_name(element), &found);
135
136   typefind = gst_elementfactory_make("typefind","typefind");
137   g_return_val_if_fail(typefind != NULL, FALSE);
138
139   gtk_signal_connect(GTK_OBJECT(typefind),"have_type",
140                     GTK_SIGNAL_FUNC(gst_pipeline_have_type), &found);
141
142   gst_pad_connect(gst_element_get_pad(element,"src"),
143                   gst_element_get_pad(typefind,"sink"));
144
145   gst_bin_add(GST_BIN(pipeline), typefind);
146
147   gst_bin_create_plan(GST_BIN(pipeline));
148   gst_element_set_state(GST_ELEMENT(element),GST_STATE_READY);
149   gst_element_set_state(GST_ELEMENT(element),GST_STATE_PLAYING);
150
151   // keep pushing buffers... the have_type signal handler will set the found flag
152   while (!found) {
153     gst_src_push(GST_SRC(element));
154   }
155
156   gst_element_set_state(GST_ELEMENT(element),GST_STATE_NULL);
157
158   if (found) {
159     type_id = gst_util_get_int_arg(GTK_OBJECT(typefind),"type");
160     gst_pad_set_type_id(gst_element_get_pad(element, "src"), type_id);
161   }
162
163   gst_pad_disconnect(gst_element_get_pad(element,"src"),
164                     gst_element_get_pad(typefind,"sink"));
165   gst_bin_remove(GST_BIN(pipeline), typefind);
166   gst_object_unref(GST_OBJECT(typefind));
167
168   return type_id;
169 }
170
171 static void gst_pipeline_pads_autoplug_func(GstElement *src, GstPad *pad, GstElement *sink) {
172   GList *sinkpads;
173   GstPad *sinkpad;
174   gboolean connected = FALSE;
175
176   g_print("gstpipeline: autoplug pad connect function type %d for \"%s\" to \"%s\"\n", pad->type, 
177                   gst_element_get_name(src), gst_element_get_name(sink));
178
179   sinkpads = gst_element_get_pad_list(sink);
180   while (sinkpads) {
181     sinkpad = (GstPad *)sinkpads->data;
182
183     // if we have a match, connect the pads
184     if (sinkpad->type == pad->type && 
185         sinkpad->direction == GST_PAD_SINK && 
186         !GST_PAD_CONNECTED(sinkpad)) 
187     {
188       gst_pad_connect(pad, sinkpad);
189       g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", pad->name, 
190                       pad->type, gst_element_get_name(src));
191       g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, 
192                       gst_element_get_name(sink));
193       connected = TRUE;
194       break;
195     }
196     sinkpads = g_list_next(sinkpads);
197   }
198
199   if (!connected) {
200     g_print("gstpipeline: no path to sinks for type %d\n", pad->type);
201   }
202 }
203
204 static void gst_pipeline_pads_autoplug(GstElement *src, GstElement *sink) {
205   GList *srcpads, *sinkpads;
206   gboolean connected = FALSE;
207
208   srcpads = gst_element_get_pad_list(src);
209
210   while (srcpads) {
211     GstPad *srcpad = (GstPad *)srcpads->data;
212     GstPad *sinkpad;
213
214     if (srcpad->direction == GST_PAD_SRC && !GST_PAD_CONNECTED(srcpad)) {
215
216       sinkpads = gst_element_get_pad_list(sink);
217       // FIXME could O(n) if the types were sorted...
218       while (sinkpads) {
219         sinkpad = (GstPad *)sinkpads->data;
220
221         // if we have a match, connect the pads
222         if (sinkpad->type == srcpad->type && 
223             sinkpad->direction == GST_PAD_SINK && 
224             !GST_PAD_CONNECTED(sinkpad)) {
225           gst_pad_connect(srcpad, sinkpad);
226           g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", 
227                           srcpad->name, srcpad->type, gst_element_get_name(src));
228           g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, 
229                           sinkpad->type, gst_element_get_name(sink));
230           connected = TRUE;
231           goto end;
232         }
233         sinkpads = g_list_next(sinkpads);
234       }
235     }
236     srcpads = g_list_next(srcpads);
237   }
238   
239 end:
240   if (!connected) {
241     g_print("gstpipeline: delaying pad connections for \"%s\" to \"%s\"\n",
242                     gst_element_get_name(src), gst_element_get_name(sink));
243     gtk_signal_connect(GTK_OBJECT(src),"new_pad",
244                  GTK_SIGNAL_FUNC(gst_pipeline_pads_autoplug_func), sink);
245   }
246 }
247
248 /**
249  * gst_pipeline_add_src:
250  * @pipeline: the pipeline to add the src to
251  * @src: the src to add to the pipeline
252  *
253  * Adds a src element to the pipeline. This element
254  * will be used as a src for autoplugging. If you add more
255  * than one src element, the previously added element will
256  * be removed.
257  */
258 void gst_pipeline_add_src(GstPipeline *pipeline, GstElement *src) 
259 {
260   g_return_if_fail(pipeline != NULL);
261   g_return_if_fail(GST_IS_PIPELINE(pipeline));
262   g_return_if_fail(src != NULL);
263   g_return_if_fail(GST_IS_ELEMENT(src));
264
265   if (pipeline->src) {
266     printf("gstpipeline: *WARNING* removing previously added element \"%s\"\n",
267                           gst_element_get_name(pipeline->src));
268     gst_bin_remove(GST_BIN(pipeline), pipeline->src);
269   }
270   pipeline->src = src;
271   gst_bin_add(GST_BIN(pipeline), src);
272 }
273
274 /**
275  * gst_pipeline_add_sink:
276  * @pipeline: the pipeline to add the sink to
277  * @sink: the sink to add to the pipeline
278  *
279  * Adds a sink element to the pipeline. This element
280  * will be used as a sink for autoplugging
281  */
282 void gst_pipeline_add_sink(GstPipeline *pipeline, GstElement *sink) 
283 {
284   g_return_if_fail(pipeline != NULL);
285   g_return_if_fail(GST_IS_PIPELINE(pipeline));
286   g_return_if_fail(sink != NULL);
287   g_return_if_fail(GST_IS_ELEMENT(sink));
288
289   pipeline->sinks = g_list_prepend(pipeline->sinks, sink);
290   //gst_bin_add(GST_BIN(pipeline), sink);
291 }
292
293 /**
294  * gst_pipeline_autoplug:
295  * @pipeline: the pipeline to autoplug
296  *
297  * Constructs a complete pipeline by automatically
298  * detecting the plugins needed.
299  *
300  * Returns: a gboolean indicating success or failure.
301  */
302 gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
303   GList *elements;
304   GstElement *element, *srcelement = NULL, *sinkelement= NULL;
305   GList **factories;
306   GstElementFactory *factory;
307   GList *src_types;
308   guint16 src_type = 0, sink_type = 0;
309   guint i, numsinks;
310   gboolean use_thread = FALSE, have_common = FALSE;
311
312   g_return_val_if_fail(pipeline != NULL, FALSE);
313   g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
314
315   g_print("GstPipeline: autopluging pipeline \"%s\"\n", 
316                   gst_element_get_name(GST_ELEMENT(pipeline)));
317
318
319   // fase 1, run typedetect on the source if needed... 
320   if (!pipeline->src) {
321     g_print("GstPipeline: no source detected, can't autoplug pipeline \"%s\"\n", 
322                 gst_element_get_name(GST_ELEMENT(pipeline)));
323     return FALSE;
324   }
325
326   factory = gst_element_get_factory(pipeline->src);
327
328   src_types = factory->src_types;
329   if (src_types == NULL) {
330     g_print("GstPipeline: source \"%s\" has no MIME type, running typefind...\n", 
331                 gst_element_get_name(pipeline->src));
332
333     src_type = gst_pipeline_typefind(pipeline, pipeline->src);
334
335     if (src_type) {
336       g_print("GstPipeline: source \"%s\" type found %d\n", gst_element_get_name(pipeline->src), 
337                   src_type);
338     }
339     else {
340       g_print("GstPipeline: source \"%s\" has no type\n", gst_element_get_name(pipeline->src));
341       return FALSE;
342     }
343   }
344   else {
345     while (src_types) {
346       // FIXME loop over types and find paths...
347       src_types = g_list_next(src_types);
348     }
349   }
350
351   srcelement = pipeline->src;
352
353   elements = pipeline->sinks;
354
355   numsinks = g_list_length(elements);
356   factories = g_new0(GList *, numsinks);
357
358   i = 0;
359   // fase 2, loop over all the sinks.. 
360   while (elements) {
361     GList *pads;
362     GstPad *pad;
363
364     element = GST_ELEMENT(elements->data);
365
366     pads = gst_element_get_pad_list(element);
367
368     while (pads) {
369       pad = (GstPad *)pads->data;
370
371       if (pad->direction == GST_PAD_SINK) {
372         sink_type = gst_pad_get_type_id(pad);
373         break;
374       }
375
376       pads = g_list_next(pads);
377     }
378
379     factories[i] = gst_type_get_sink_to_src(src_type, sink_type);
380     //factories[i] = g_list_append(factories[i], element);
381     i++;
382
383     elements = g_list_next(elements);
384   }
385
386   while (factories[0]) {
387     // fase 3: add common elements 
388     factory = (GstElementFactory *)(factories[0]->data);
389
390     // check to other paths for mathing elements (factories)
391     for (i=1; i<numsinks; i++) {
392       if (factory != (GstElementFactory *)(factories[i]->data)) {
393         goto differ;
394       }
395       factories[i] = g_list_next(factories[i]);
396     }
397     factory = (GstElementFactory *)(factories[0]->data);
398
399     g_print("GstPipeline: common factory \"%s\"\n", factory->name);
400
401     element = gst_elementfactory_create(factory, factory->name);
402     gst_bin_add(GST_BIN(pipeline), element);
403
404     gst_pipeline_pads_autoplug(srcelement, element);
405
406     srcelement = element;
407
408     factories[0] = g_list_next(factories[0]);
409
410     have_common = TRUE;
411   }
412
413 differ:
414   // loop over all the sink elements
415   elements = pipeline->sinks;
416
417   i = 0;
418   while (elements) {
419     GstElement *thesrcelement = srcelement;
420     GstElement *thebin = GST_ELEMENT(pipeline);
421
422     sinkelement = (GstElement *)elements->data;
423
424     use_thread = have_common;
425
426     while (factories[i] || sinkelement) {
427       // fase 4: add other elements...
428        
429       if (factories[i]) {
430         factory = (GstElementFactory *)(factories[i]->data);
431         g_print("GstPipeline: factory \"%s\"\n", factory->name);
432         element = gst_elementfactory_create(factory, factory->name);
433         factories[i] = g_list_next(factories[i]);
434       }
435       // we have arived to the final sink element
436       else {
437         element = sinkelement;
438         sinkelement = NULL;
439       }
440
441       // this element suggests the use of a thread, so we set one up...
442       if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) {
443         GstElement *queue;
444         GList *sinkpads;
445         GstPad *srcpad, *sinkpad;
446
447         use_thread = FALSE;
448
449         g_print("GstPipeline: sugest new thread for \"%s\" %08x\n", element->name, GST_FLAGS(element));
450
451         // create a new queue and add to the previous bin
452         queue = gst_elementfactory_make("queue", g_strconcat("queue_", gst_element_get_name(element), NULL));
453         gst_bin_add(GST_BIN(thebin), queue);
454
455         // this will be the new bin for all following elements
456         thebin = gst_elementfactory_make("thread", g_strconcat("thread_", gst_element_get_name(element), NULL));
457
458         srcpad = gst_element_get_pad(queue, "src");
459
460         sinkpads = gst_element_get_pad_list(element);
461         while (sinkpads) {
462           sinkpad = (GstPad *)sinkpads->data;
463
464           // FIXME connect matching pads, not just the first one...
465           if (sinkpad->direction == GST_PAD_SINK && 
466               !GST_PAD_CONNECTED(sinkpad)) {
467             // the queue has the types of the element it connects
468             srcpad->type = sinkpad->type;
469             gst_element_get_pad(queue, "sink")->type = sinkpad->type;
470             break;
471           }
472           sinkpads = g_list_next(sinkpads);
473         }
474         gst_pipeline_pads_autoplug(thesrcelement, queue);
475
476         gst_bin_add(GST_BIN(thebin), element);
477         gst_bin_add(GST_BIN(pipeline), thebin);
478         thesrcelement = queue;
479       }
480       // no thread needed, easy case
481       else {
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
490     elements = g_list_next(elements);
491     i++;
492   }
493   return TRUE;
494   
495   g_print("GstPipeline: unable to autoplug pipeline \"%s\"\n", 
496                   gst_element_get_name(GST_ELEMENT(pipeline)));
497   return FALSE;
498 }
499
500 static GstElementStateReturn gst_pipeline_change_state(GstElement *element) {
501   GstPipeline *pipeline;
502
503   g_return_val_if_fail(GST_IS_PIPELINE(element), FALSE);
504   pipeline = GST_PIPELINE(element);
505
506
507   switch (GST_STATE_PENDING(pipeline)) {
508     case GST_STATE_READY:
509       // we need to set up internal state
510       gst_pipeline_prepare(pipeline);
511       break;
512     default:
513       break;
514   }
515     
516   if (GST_ELEMENT_CLASS(parent_class)->change_state)
517     return GST_ELEMENT_CLASS(parent_class)->change_state(element);
518   return GST_STATE_SUCCESS;
519 }
520
521
522 /**
523  * gst_pipeline_iterate:
524  * @pipeline: GstPipeline to iterate
525  *
526  * Cause the pipeline's contents to be run through one full 'iteration'.
527  */
528 void gst_pipeline_iterate(GstPipeline *pipeline) {
529   g_return_if_fail(pipeline != NULL);
530   g_return_if_fail(GST_IS_PIPELINE(pipeline));
531 }