Due to popular demand :-), I added a vorbis decoder.
[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/gstsink.h>
22 #include <gst/gstutils.h>
23 #include <gst/gsttype.h>
24
25 #include "config.h"
26
27 GstElementDetails gst_pipeline_details = {
28   "Pipeline object",
29   "Bin",
30   "Complete pipeline object",
31   VERSION,
32   "Erik Walthinsen <omega@cse.ogi.edu>",
33   "(C) 1999",
34 };
35
36
37 /* Pipeline signals and args */
38 enum {
39   /* FILL ME */
40   LAST_SIGNAL
41 };
42
43 enum {
44   ARG_0,
45   /* FILL ME */
46 };
47
48
49 static void gst_pipeline_class_init(GstPipelineClass *klass);
50 static void gst_pipeline_init(GstPipeline *pipeline);
51
52 static GstElementStateReturn gst_pipeline_change_state(GstElement *element);
53
54 static void gst_pipeline_prepare(GstPipeline *pipeline);
55
56 static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data);
57 static void gst_pipeline_pads_autoplug(GstElement *src, GstElement *sink);
58
59 static GstBin *parent_class = NULL;
60 //static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
61
62 GtkType
63 gst_pipeline_get_type(void) {
64   static GtkType pipeline_type = 0;
65
66   if (!pipeline_type) {
67     static const GtkTypeInfo pipeline_info = {
68       "GstPipeline",
69       sizeof(GstPipeline),
70       sizeof(GstPipelineClass),
71       (GtkClassInitFunc)gst_pipeline_class_init,
72       (GtkObjectInitFunc)gst_pipeline_init,
73       (GtkArgSetFunc)NULL,
74       (GtkArgGetFunc)NULL,
75       (GtkClassInitFunc)NULL,
76     };
77     pipeline_type = gtk_type_unique(gst_bin_get_type(),&pipeline_info);
78   }
79   return pipeline_type;
80 }
81
82 static void
83 gst_pipeline_class_init(GstPipelineClass *klass) {
84   GstElementClass *gstelement_class;
85
86   gstelement_class = (GstElementClass*)klass;
87
88   parent_class = gtk_type_class(gst_bin_get_type());
89
90   gstelement_class->change_state = gst_pipeline_change_state;
91 }
92
93 static void gst_pipeline_init(GstPipeline *pipeline) {
94 }
95
96
97 /**
98  * gst_pipeline_new:
99  * @name: name of new pipeline
100  *
101  * Create a new pipeline with the given name.
102  *
103  * Returns: newly created GstPipeline
104  */
105 GstElement *gst_pipeline_new(guchar *name) {
106   GstPipeline *pipeline;
107
108   pipeline = gtk_type_new(gst_pipeline_get_type());
109   gst_element_set_name(GST_ELEMENT(pipeline),name);
110   return GST_ELEMENT(pipeline);
111 }
112
113 static void gst_pipeline_prepare(GstPipeline *pipeline) {
114   g_print("GstPipeline: preparing pipeline \"%s\" for playing\n", gst_element_get_name(GST_ELEMENT(pipeline)));
115 }
116
117 static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data) {
118   g_print("GstPipeline: pipeline have type %p\n", (gboolean *)data);
119
120   *(gboolean *)data = TRUE;
121 }
122
123 static guint16 gst_pipeline_typefind(GstPipeline *pipeline, GstElement *element) {
124   gboolean found = FALSE;
125   GstElement *typefind;
126   guint16 type_id = 0;
127
128   g_print("GstPipeline: typefind for element \"%s\" %p\n", gst_element_get_name(element), &found);
129
130   typefind = gst_elementfactory_make("typefind","typefind");
131   g_return_val_if_fail(typefind != NULL, FALSE);
132
133   gtk_signal_connect(GTK_OBJECT(typefind),"have_type",
134                     GTK_SIGNAL_FUNC(gst_pipeline_have_type), &found);
135
136   gst_pad_connect(gst_element_get_pad(element,"src"),
137                   gst_element_get_pad(typefind,"sink"));
138
139   gst_bin_add(GST_BIN(pipeline), typefind);
140
141   gst_bin_create_plan(GST_BIN(pipeline));
142   gst_element_set_state(GST_ELEMENT(element),GST_STATE_READY);
143   gst_element_set_state(GST_ELEMENT(element),GST_STATE_PLAYING);
144
145   while (!found) {
146     gst_src_push(GST_SRC(element));
147   }
148
149   gst_element_set_state(GST_ELEMENT(element),GST_STATE_NULL);
150
151   if (found) {
152     type_id = gst_util_get_int_arg(GTK_OBJECT(typefind),"type");
153   }
154
155   gst_pad_set_type_id(gst_element_get_pad(element, "src"), type_id);
156
157   gst_pad_disconnect(gst_element_get_pad(element,"src"),
158                     gst_element_get_pad(typefind,"sink"));
159   gst_bin_remove(GST_BIN(pipeline), typefind);
160   gst_object_unref(GST_OBJECT(typefind));
161
162   return type_id;
163 }
164
165 static void gst_pipeline_pads_autoplug_func(GstElement *src, GstPad *pad, GstElement *sink) {
166   GList *sinkpads;
167   GstPad *sinkpad;
168
169   g_print("gstpipeline: autoplug pad connect function type %d\n", pad->type);
170
171   sinkpads = gst_element_get_pad_list(sink);
172   while (sinkpads) {
173     sinkpad = (GstPad *)sinkpads->data;
174
175     // if we have a match, connect the pads
176     if (sinkpad->type == pad->type && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) {
177       gst_pad_connect(pad, sinkpad);
178       g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", pad->name, pad->type, gst_element_get_name(src));
179       g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, gst_element_get_name(sink));
180       break;
181     }
182     sinkpads = g_list_next(sinkpads);
183   }
184 }
185
186 static void gst_pipeline_pads_autoplug(GstElement *src, GstElement *sink) {
187   GList *srcpads, *sinkpads;
188   gboolean connected = FALSE;
189
190   srcpads = gst_element_get_pad_list(src);
191
192   while (srcpads) {
193     GstPad *srcpad = (GstPad *)srcpads->data;
194     GstPad *sinkpad;
195
196     if (srcpad->direction == GST_PAD_SRC && !GST_PAD_CONNECTED(srcpad)) {
197
198       sinkpads = gst_element_get_pad_list(sink);
199       // FIXME could O(n) if the types were sorted...
200       while (sinkpads) {
201         sinkpad = (GstPad *)sinkpads->data;
202
203         // if we have a match, connect the pads
204         if (sinkpad->type == srcpad->type && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) {
205           gst_pad_connect(srcpad, sinkpad);
206           g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", srcpad->name, srcpad->type, gst_element_get_name(src));
207           g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, gst_element_get_name(sink));
208           connected = TRUE;
209           goto end;
210         }
211         sinkpads = g_list_next(sinkpads);
212       }
213     }
214     srcpads = g_list_next(srcpads);
215   }
216   
217 end:
218   if (!connected) {
219     g_print("gstpipeline: delaying pad connections\n");
220     gtk_signal_connect(GTK_OBJECT(src),"new_pad",
221                  GTK_SIGNAL_FUNC(gst_pipeline_pads_autoplug_func), sink);
222   }
223 }
224
225 /**
226  * gst_pipeline_autoplug:
227  * @pipeline: the pipeline to autoplug
228  *
229  * Constructs a complete pipeline by automatically
230  * detecting the plugins needed.
231  *
232  * Returns: a gboolean indicating success or failure.
233  */
234 gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
235   GList *elements;
236   GstElement *element, *srcelement = NULL, *sinkelement= NULL;
237   GList *factories;
238   GstElementFactory *factory;
239   GList *src_types, *sink_types;
240   guint16 src_type = 0, sink_type = 0;
241   gboolean complete = FALSE;
242
243   g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
244
245   g_print("GstPipeline: autopluging pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
246
247   elements = gst_bin_get_list(GST_BIN(pipeline));
248
249   // fase 1, find all the sinks and sources... FIXME need better way to do this...
250   while (elements) {
251     element = GST_ELEMENT(elements->data);
252
253     if (GST_IS_SINK(element)) {
254       g_print("GstPipeline: found sink \"%s\"\n", gst_element_get_name(element));
255
256       if (sink_type) {
257         g_print("GstPipeline: multiple sinks detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
258         return FALSE;
259       }
260       sinkelement = element;
261       factory = gst_element_get_factory(element);
262       
263       sink_types = factory->sink_types;
264       if (sink_types == NULL) {
265         g_print("GstPipeline: sink \"%s\" has no MIME type, can't autoplug \n", gst_element_get_name(element));
266         return FALSE;
267       }
268       else {
269         sink_type = GPOINTER_TO_UINT(sink_types->data);
270         g_print("GstPipeline: sink \"%s\" has MIME type %d \n", gst_element_get_name(element), sink_type);
271       }
272     }
273     else if (GST_IS_SRC(element)) {
274       g_print("GstPipeline: found source \"%s\"\n", gst_element_get_name(element));
275
276       if (src_type) {
277         g_print("GstPipeline: multiple sources detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
278         return FALSE;
279       }
280
281       srcelement = element;
282
283       factory = gst_element_get_factory(element);
284
285       src_types = factory->src_types;
286       if (src_types == NULL) {
287         g_print("GstPipeline: source \"%s\" has no MIME type, running typefind...\n", gst_element_get_name(element));
288
289         src_type = gst_pipeline_typefind(pipeline, element);
290
291         if (src_type) {
292           g_print("GstPipeline: source \"%s\" type found %d\n", gst_element_get_name(element), src_type);
293         }
294         else {
295           g_print("GstPipeline: source \"%s\" has no type\n", gst_element_get_name(element));
296           return FALSE;
297         }
298       }
299       else {
300         while (src_types) {
301           src_types = g_list_next(src_types);
302         }
303       }
304     }
305     else {
306       g_print("GstPipeline: found invalid element \"%s\", not source or sink\n", gst_element_get_name(element));
307     }
308
309     elements = g_list_next(elements);
310   }
311
312   factories = gst_type_get_sink_to_src(src_type, sink_type);
313
314   while (factories) {
315     // fase 2: find elements to form a pad
316        
317     factory = (GstElementFactory *)(factories->data);
318
319     g_print("GstPipeline: factory \"%s\"\n", factory->name);
320
321     element = gst_elementfactory_create(factory, factory->name);
322     gst_bin_add(GST_BIN(pipeline), element);
323
324     gst_pipeline_pads_autoplug(srcelement, element);
325
326     srcelement = element;
327
328     factories = g_list_next(factories);
329
330     complete = TRUE;
331   }
332
333   if (complete) {
334     gst_pipeline_pads_autoplug(srcelement, sinkelement);
335     return TRUE;
336   }
337   
338   g_print("GstPipeline: unable to autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
339   return FALSE;
340 }
341
342 static GstElementStateReturn gst_pipeline_change_state(GstElement *element) {
343   GstPipeline *pipeline;
344
345   g_return_val_if_fail(GST_IS_PIPELINE(element), FALSE);
346   pipeline = GST_PIPELINE(element);
347
348
349   switch (GST_STATE_PENDING(pipeline)) {
350     case GST_STATE_READY:
351       // we need to set up internal state
352       gst_pipeline_prepare(pipeline);
353       break;
354     default:
355       break;
356   }
357     
358   if (GST_ELEMENT_CLASS(parent_class)->change_state)
359     return GST_ELEMENT_CLASS(parent_class)->change_state(element);
360   return GST_STATE_SUCCESS;
361 }
362
363
364 /**
365  * gst_pipeline_iterate:
366  * @pipeline: GstPipeline to iterate
367  *
368  * Cause the pipeline's contents to be run through one full 'iteration'.
369  */
370 void gst_pipeline_iterate(GstPipeline *pipeline) {
371   g_return_if_fail(pipeline != NULL);
372   g_return_if_fail(GST_IS_PIPELINE(pipeline));
373 }