A first (rude) attempt at autoplug.
[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
58 static GstBin *parent_class = NULL;
59 //static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
60
61 GtkType
62 gst_pipeline_get_type(void) {
63   static GtkType pipeline_type = 0;
64
65   if (!pipeline_type) {
66     static const GtkTypeInfo pipeline_info = {
67       "GstPipeline",
68       sizeof(GstPipeline),
69       sizeof(GstPipelineClass),
70       (GtkClassInitFunc)gst_pipeline_class_init,
71       (GtkObjectInitFunc)gst_pipeline_init,
72       (GtkArgSetFunc)NULL,
73       (GtkArgGetFunc)NULL,
74       (GtkClassInitFunc)NULL,
75     };
76     pipeline_type = gtk_type_unique(gst_bin_get_type(),&pipeline_info);
77   }
78   return pipeline_type;
79 }
80
81 static void
82 gst_pipeline_class_init(GstPipelineClass *klass) {
83   GstElementClass *gstelement_class;
84
85   gstelement_class = (GstElementClass*)klass;
86
87   parent_class = gtk_type_class(gst_bin_get_type());
88
89   gstelement_class->change_state = gst_pipeline_change_state;
90 }
91
92 static void gst_pipeline_init(GstPipeline *pipeline) {
93 }
94
95
96 /**
97  * gst_pipeline_new:
98  * @name: name of new pipeline
99  *
100  * Create a new pipeline with the given name.
101  *
102  * Returns: newly created GstPipeline
103  */
104 GstPipeline *gst_pipeline_new(guchar *name) {
105   GstPipeline *pipeline;
106
107   pipeline = gtk_type_new(gst_pipeline_get_type());
108   gst_element_set_name(GST_ELEMENT(pipeline),name);
109   return pipeline;
110 }
111
112 static void gst_pipeline_prepare(GstPipeline *pipeline) {
113   g_print("GstPipeline: preparing pipeline \"%s\" for playing\n", gst_element_get_name(GST_ELEMENT(pipeline)));
114 }
115
116 static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data) {
117   g_print("GstPipeline: pipeline have type %p\n", (gboolean *)data);
118
119   *(gboolean *)data = TRUE;
120 }
121
122 static guint16 gst_pipeline_typefind(GstPipeline *pipeline, GstElement *element) {
123   gboolean found = FALSE;
124   GstElement *typefind;
125   guint16 type_id = 0;
126
127   g_print("GstPipeline: typefind for element \"%s\" %p\n", gst_element_get_name(element), &found);
128
129   typefind = gst_elementfactory_make("typefind","typefind");
130   g_return_val_if_fail(typefind != NULL, FALSE);
131
132   gtk_signal_connect(GTK_OBJECT(typefind),"have_type",
133                     GTK_SIGNAL_FUNC(gst_pipeline_have_type), &found);
134
135   gst_pad_connect(gst_element_get_pad(element,"src"),
136                   gst_element_get_pad(typefind,"sink"));
137
138   gst_bin_add(GST_BIN(pipeline), typefind);
139
140   gst_bin_create_plan(GST_BIN(pipeline));
141   gst_element_set_state(GST_ELEMENT(element),GST_STATE_READY);
142   gst_element_set_state(GST_ELEMENT(element),GST_STATE_PLAYING);
143
144   while (!found) {
145     gst_src_push(GST_SRC(element));
146   }
147
148   gst_element_set_state(GST_ELEMENT(element),GST_STATE_NULL);
149
150   if (found) {
151     type_id = gst_util_get_int_arg(GTK_OBJECT(typefind),"type");
152   }
153
154   gst_pad_set_type_id(gst_element_get_pad(element, "src"), type_id);
155
156   gst_pad_disconnect(gst_element_get_pad(element,"src"),
157                     gst_element_get_pad(typefind,"sink"));
158   gst_bin_remove(GST_BIN(pipeline), typefind);
159
160   return type_id;
161 }
162
163 gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
164   GList *elements;
165   GstElement *element, *srcelement, *sinkelement;
166   GList *factories;
167   GstElementFactory *factory;
168   GList *src_types, *sink_types;
169   guint16 src_type = 0, sink_type = 0;
170   gboolean complete = FALSE;
171
172   g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
173
174   g_print("GstPipeline: autopluging pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
175
176   elements = gst_bin_get_list(GST_BIN(pipeline));
177
178   // fase 1, find all the sinks and sources...
179   while (elements) {
180     element = GST_ELEMENT(elements->data);
181
182     if (GST_IS_SINK(element)) {
183       g_print("GstPipeline: found sink \"%s\"\n", gst_element_get_name(element));
184
185       if (sink_type) {
186         g_print("GstPipeline: multiple sinks detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
187         return FALSE;
188       }
189       sinkelement = element;
190       factory = gst_element_get_factory(element);
191       
192       sink_types = factory->sink_types;
193       if (sink_types == NULL) {
194         g_print("GstPipeline: sink \"%s\" has no MIME type, can't autoplug \n", gst_element_get_name(element));
195         return FALSE;
196       }
197       else {
198         sink_type = GPOINTER_TO_UINT(sink_types->data);
199         g_print("GstPipeline: sink \"%s\" has MIME type %d \n", gst_element_get_name(element), sink_type);
200       }
201     }
202     else if (GST_IS_SRC(element)) {
203       g_print("GstPipeline: found source \"%s\"\n", gst_element_get_name(element));
204
205       if (src_type) {
206         g_print("GstPipeline: multiple sources detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
207         return FALSE;
208       }
209
210       srcelement = element;
211
212       factory = gst_element_get_factory(element);
213
214       src_types = factory->src_types;
215       if (src_types == NULL) {
216         g_print("GstPipeline: source \"%s\" has no MIME type, running typefind...\n", gst_element_get_name(element));
217
218         src_type = gst_pipeline_typefind(pipeline, element);
219
220         if (src_type) {
221           g_print("GstPipeline: source \"%s\" type found %d\n", gst_element_get_name(element), src_type);
222         }
223         else {
224           g_print("GstPipeline: source \"%s\" has no type\n", gst_element_get_name(element));
225           return FALSE;
226         }
227       }
228       else {
229         while (src_types) {
230           src_types = g_list_next(src_types);
231         }
232       }
233     }
234     else {
235       g_print("GstPipeline: found invalid element \"%s\", not source or sink\n", gst_element_get_name(element));
236     }
237
238     elements = g_list_next(elements);
239   }
240
241   factories = gst_type_get_sink_to_src(src_type, sink_type);
242
243   while (factories) {
244     // fase 2: find elements to form a pad
245        
246     factory = (GstElementFactory *)(factories->data);
247
248     g_print("GstPipeline: factory \"%s\"\n", factory->name);
249
250     element = gst_elementfactory_create(factory, factory->name);
251     gst_bin_add(GST_BIN(pipeline), element);
252
253     // FIXME match paths to connect with MIME types instead
254     // of names.
255     gst_pad_connect(gst_element_get_pad(srcelement,"src"),
256                     gst_element_get_pad(element,"sink"));
257
258     srcelement = element;
259
260     factories = g_list_next(factories);
261
262     complete = TRUE;
263   }
264
265   if (complete) {
266     gst_pad_connect(gst_element_get_pad(srcelement,"src"),
267                     gst_element_get_pad(sinkelement,"sink"));
268     return TRUE;
269   }
270   
271   g_print("GstPipeline: unable to autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
272   return FALSE;
273 }
274
275 static GstElementStateReturn gst_pipeline_change_state(GstElement *element) {
276   GstPipeline *pipeline;
277
278   g_return_val_if_fail(GST_IS_PIPELINE(element), FALSE);
279   pipeline = GST_PIPELINE(element);
280
281
282   switch (GST_STATE_PENDING(pipeline)) {
283     case GST_STATE_READY:
284       // we need to set up internal state
285       g_print("preparing pipeline \"%s\" for iterations:\n",
286               gst_element_get_name(GST_ELEMENT(element)));
287       gst_pipeline_prepare(pipeline);
288       break;
289     default:
290       break;
291   }
292     
293   if (GST_ELEMENT_CLASS(parent_class)->change_state)
294     return GST_ELEMENT_CLASS(parent_class)->change_state(element);
295   return GST_STATE_SUCCESS;
296 }
297
298
299 /**
300  * gst_pipeline_iterate:
301  * @pipeline: GstPipeline to iterate
302  *
303  * Cause the pipeline's contents to be run through one full 'iteration'.
304  */
305 void gst_pipeline_iterate(GstPipeline *pipeline) {
306   g_return_if_fail(pipeline != NULL);
307   g_return_if_fail(GST_IS_PIPELINE(pipeline));
308 }