19f793120cb56a5670e5d598cc07e11efa552a63
[platform/upstream/gstreamer.git] / gst / gstelementfactory.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstelementfactory.c: GstElementFactory object, support routines
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 DEBUG_ENABLED */
24 #include "gst_private.h"
25
26 #include "gstelement.h"
27
28 static void             gst_element_factory_class_init          (GstElementFactoryClass *klass);
29 static void             gst_element_factory_init                (GstElementFactory *factory);
30
31 #ifndef GST_DISABLE_REGISTRY
32 static void             gst_element_factory_restore_thyself     (GstObject *object, xmlNodePtr parent);
33 static xmlNodePtr       gst_element_factory_save_thyself        (GstObject *object, xmlNodePtr parent);
34 #endif
35
36 static void             gst_element_factory_unload_thyself      (GstPluginFeature *feature);
37
38 /* global list of registered elementfactories */
39 static GList* _gst_elementfactories;
40
41 static GstPluginFeatureClass *parent_class = NULL;
42 /* static guint gst_element_factory_signals[LAST_SIGNAL] = { 0 }; */
43
44 GType 
45 gst_element_factory_get_type (void) 
46 {
47   static GType elementfactory_type = 0;
48
49   if (!elementfactory_type) {
50     static const GTypeInfo elementfactory_info = {
51       sizeof (GstElementFactoryClass),
52       NULL,
53       NULL,
54       (GClassInitFunc) gst_element_factory_class_init,
55       NULL,
56       NULL,
57       sizeof(GstElementFactory),
58       0,
59       (GInstanceInitFunc) gst_element_factory_init,
60       NULL
61     };
62     elementfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
63                                                   "GstElementFactory", &elementfactory_info, 0);
64   }
65   return elementfactory_type;
66 }
67
68 static void
69 gst_element_factory_class_init (GstElementFactoryClass *klass)
70 {
71   GObjectClass *gobject_class;
72   GstObjectClass *gstobject_class;
73   GstPluginFeatureClass *gstpluginfeature_class;
74
75   gobject_class = (GObjectClass*)klass;
76   gstobject_class = (GstObjectClass*)klass;
77   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
78
79   parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
80
81 #ifndef GST_DISABLE_REGISTRY
82   gstobject_class->save_thyself =       GST_DEBUG_FUNCPTR (gst_element_factory_save_thyself);
83   gstobject_class->restore_thyself =    GST_DEBUG_FUNCPTR (gst_element_factory_restore_thyself);
84 #endif
85
86   gstpluginfeature_class->unload_thyself =      GST_DEBUG_FUNCPTR (gst_element_factory_unload_thyself);
87
88   _gst_elementfactories = NULL;
89 }
90
91 static void
92 gst_element_factory_init (GstElementFactory *factory)
93 {
94   factory->padtemplates = NULL;
95   factory->numpadtemplates = 0;
96
97   _gst_elementfactories = g_list_prepend (_gst_elementfactories, factory);
98 }
99
100 /**
101  * gst_element_factory_find:
102  * @name: name of factory to find
103  *
104  * Search for an elementfactory of the given name.
105  *
106  * Returns: #GstElementFactory if found, NULL otherwise
107  */
108 GstElementFactory*
109 gst_element_factory_find (const gchar *name)
110 {
111   GList *walk;
112   GstElementFactory *factory;
113
114   g_return_val_if_fail(name != NULL, NULL);
115
116   walk = _gst_elementfactories;
117   while (walk) {
118     factory = (GstElementFactory *)(walk->data);
119     if (!strcmp(name, GST_OBJECT_NAME (factory)))
120       return factory;
121     walk = g_list_next(walk);
122   }
123
124   /* this should be an ERROR */
125   GST_DEBUG (GST_CAT_ELEMENT_FACTORY,"no such elementfactory \"%s\"", name);
126   return NULL;
127 }
128
129 /**
130  * gst_element_factory_get_list:
131  *
132  * Get the global list of elementfactories.
133  *
134  * Returns: GList of type #GstElementFactory
135  */
136 const GList*
137 gst_element_factory_get_list (void)
138 {
139   return _gst_elementfactories;
140 }
141
142 static void
143 gst_element_details_free (GstElementDetails *dp)
144 {
145   g_return_if_fail (dp);
146
147   if (dp->longname)
148     g_free (dp->longname);
149   if (dp->klass)
150     g_free (dp->klass);
151   if (dp->description)
152     g_free (dp->description);
153   if (dp->version)
154     g_free (dp->version);
155   if (dp->author)
156     g_free (dp->author);
157   if (dp->copyright)
158     g_free (dp->copyright);
159   g_free (dp);
160 }
161
162 /**
163  * gst_element_factory_new:
164  * @name: name of new elementfactory
165  * @type: GType of new element
166  * @details: #GstElementDetails structure with element details
167  *
168  * Create a new elementfactory capable of insantiating objects of the
169  * given type.
170  *
171  * Returns: new elementfactory
172  */
173 GstElementFactory*
174 gst_element_factory_new (const gchar *name, GType type,
175                         GstElementDetails *details)
176 {
177   GstElementFactory *factory;
178
179   g_return_val_if_fail(name != NULL, NULL);
180   g_return_val_if_fail (type, NULL);
181   g_return_val_if_fail (details, NULL);
182
183   factory = gst_element_factory_find (name);
184
185   if (!factory)
186     factory = GST_ELEMENT_FACTORY (g_object_new (GST_TYPE_ELEMENT_FACTORY, NULL));
187
188   if (factory->details_dynamic)
189     {
190       gst_element_details_free (factory->details);
191       factory->details_dynamic = FALSE;
192     }
193
194   factory->details = details;
195
196   if (!factory->type)
197     factory->type = type;
198   else if (factory->type != type)
199     g_critical ("`%s' requested type change (!)", name);
200
201   gst_object_set_name (GST_OBJECT (factory), name);
202
203   return factory;
204 }
205
206 /**
207  * gst_element_factory_create:
208  * @factory: factory to instantiate
209  * @name: name of new element
210  *
211  * Create a new element of the type defined by the given elementfactory.
212  * It wll be given the name supplied, since all elements require a name as
213  * their first argument.
214  *
215  * Returns: new #GstElement
216  */
217 GstElement *
218 gst_element_factory_create (GstElementFactory *factory,
219                            const gchar *name)
220 {
221   GstElement *element;
222   GstElementClass *oclass;
223
224   g_return_val_if_fail(factory != NULL, NULL);
225
226   GST_DEBUG (GST_CAT_ELEMENT_FACTORY,"creating element from factory \"%s\" with name \"%s\" and type %d", 
227              GST_OBJECT_NAME (factory), name, (gint) factory->type);
228
229   if (!gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory)))
230     return NULL;
231
232   if (factory->type == 0) {
233       g_critical ("Factory for `%s' has no type",
234                   gst_object_get_name (GST_OBJECT (factory)));
235       return NULL;
236   }
237
238   /* create an instance of the element */
239   element = GST_ELEMENT(g_object_new(factory->type,NULL));
240   g_assert(element != NULL);
241
242   /* attempt to set the elemenfactory class pointer if necessary */
243   oclass = GST_ELEMENT_CLASS(G_OBJECT_GET_CLASS(element));
244   if (oclass->elementfactory == NULL) {
245     GST_DEBUG (GST_CAT_ELEMENT_FACTORY,"class %s", GST_OBJECT_NAME (factory));
246     oclass->elementfactory = factory;
247
248     /* copy pad template pointers to the element class, allow for custom padtemplates */
249     oclass->padtemplates = g_list_concat (oclass->padtemplates, factory->padtemplates);
250     oclass->numpadtemplates += factory->numpadtemplates;
251   }
252   
253   gst_object_set_name (GST_OBJECT (element),name);
254
255   return element;
256 }
257
258 /**
259  * gst_element_factory_make:
260  * @factoryname: a named factory to instantiate
261  * @name: name of new element
262  *
263  * Create a new element of the type defined by the given elementfactory.
264  * It wll be given the name supplied, since all elements require a name as
265  * their first argument.
266  *
267  * Returns: new #GstElement (or NULL if unable to create element)
268  */
269 GstElement*
270 gst_element_factory_make (const gchar *factoryname, const gchar *name)
271 {
272   GstElementFactory *factory;
273   GstElement *element;
274
275   g_return_val_if_fail (factoryname != NULL, NULL);
276
277   GST_DEBUG (GST_CAT_ELEMENT_FACTORY, "gstelementfactory: make \"%s\" \"%s\"", factoryname, name);
278
279   /* gst_plugin_load_element_factory(factoryname); */
280   factory = gst_element_factory_find(factoryname);
281   if (factory == NULL) {
282     GST_INFO (GST_CAT_ELEMENT_FACTORY,"no such elementfactory \"%s\"!",factoryname);
283     return NULL;
284   }
285   element = gst_element_factory_create(factory,name);
286   if (element == NULL) {
287     GST_INFO (GST_CAT_ELEMENT_FACTORY,"couldn't create instance of elementfactory \"%s\"!",factoryname);
288     return NULL;
289   }
290
291   return element;
292 }
293
294 /**
295  * gst_element_factory_add_pad_template :
296  * @elementfactory: factory to add the src id to
297  * @templ: the padtemplate to add
298  *
299  * Add the given padtemplate to this elementfactory.
300  */
301 void
302 gst_element_factory_add_pad_template (GstElementFactory *factory,
303                                     GstPadTemplate *templ)
304 {
305   GList *padtemplates;
306   
307   g_return_if_fail(factory != NULL);
308   g_return_if_fail(templ != NULL);
309
310   padtemplates = factory->padtemplates;
311
312   gst_object_ref (GST_OBJECT (templ));
313
314   while (padtemplates) {
315     GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
316     
317     if (!strcmp (oldtempl->name_template, templ->name_template)) {
318       gst_object_unref (GST_OBJECT (oldtempl));
319       padtemplates->data = templ;
320       return;
321     }
322     
323     padtemplates = g_list_next (padtemplates);
324   }
325   factory->padtemplates = g_list_append (factory->padtemplates, templ);
326   factory->numpadtemplates++;
327 }
328
329 /**
330  * gst_element_factory_can_src_caps :
331  * @factory: factory to query
332  * @caps: the caps to check
333  *
334  * Checks if the factory can source the given capability.
335  *
336  * Returns: true if it can src the capabilities
337  */
338 gboolean
339 gst_element_factory_can_src_caps (GstElementFactory *factory,
340                                  GstCaps *caps)
341 {
342   GList *templates;
343
344   g_return_val_if_fail(factory != NULL, FALSE);
345   g_return_val_if_fail(caps != NULL, FALSE);
346
347   templates = factory->padtemplates;
348
349   while (templates) {
350     GstPadTemplate *template = (GstPadTemplate *)templates->data;
351
352     if (template->direction == GST_PAD_SRC) {
353       if (gst_caps_check_compatibility (GST_PAD_TEMPLATE_CAPS (template), caps))
354         return TRUE;
355     }
356     templates = g_list_next (templates);
357   }
358
359   return FALSE;
360 }
361
362 /**
363  * gst_element_factory_can_sink_caps :
364  * @factory: factory to query
365  * @caps: the caps to check
366  *
367  * Checks if the factory can sink the given capability.
368  *
369  * Returns: true if it can sink the capabilities
370  */
371 gboolean
372 gst_element_factory_can_sink_caps (GstElementFactory *factory,
373                                   GstCaps *caps)
374 {
375   GList *templates;
376
377   g_return_val_if_fail(factory != NULL, FALSE);
378   g_return_val_if_fail(caps != NULL, FALSE);
379
380   templates = factory->padtemplates;
381
382   while (templates) {
383     GstPadTemplate *template = (GstPadTemplate *)templates->data;
384
385     if (template->direction == GST_PAD_SINK) {
386       if (gst_caps_check_compatibility (caps, GST_PAD_TEMPLATE_CAPS (template)))
387         return TRUE;
388     }
389     templates = g_list_next (templates);
390   }
391
392   return FALSE;
393 }
394
395 static void
396 gst_element_factory_unload_thyself (GstPluginFeature *feature)
397 {
398   GstElementFactory *factory;
399
400   factory = GST_ELEMENT_FACTORY (feature);
401
402   factory->type = 0;
403 }
404
405 #ifndef GST_DISABLE_REGISTRY
406 static xmlNodePtr
407 gst_element_factory_save_thyself (GstObject *object,
408                                  xmlNodePtr parent)
409 {
410   GList *pads;
411   GstElementFactory *factory;
412
413   factory = GST_ELEMENT_FACTORY (object);
414   
415   if (GST_OBJECT_CLASS (parent_class)->save_thyself) {
416     GST_OBJECT_CLASS (parent_class)->save_thyself (object, parent);
417   }
418
419   g_return_val_if_fail(factory != NULL, NULL);
420
421   if (factory->details)
422     {
423       xmlNewChild(parent,NULL,"longname", factory->details->longname);
424       xmlNewChild(parent,NULL,"class", factory->details->klass);
425       xmlNewChild(parent,NULL,"description", factory->details->description);
426       xmlNewChild(parent,NULL,"version", factory->details->version);
427       xmlNewChild(parent,NULL,"author", factory->details->author);
428       xmlNewChild(parent,NULL,"copyright", factory->details->copyright);
429     }
430   else
431     g_warning ("elementfactory `%s' is missing details",
432                object->name);
433
434   pads = factory->padtemplates;
435   if (pads) {
436     while (pads) {
437       xmlNodePtr subtree;
438       GstPadTemplate *padtemplate = (GstPadTemplate *)pads->data;
439
440       subtree = xmlNewChild(parent, NULL, "padtemplate", NULL);
441       gst_pad_template_save_thyself(padtemplate, subtree);
442
443       pads = g_list_next (pads);
444     }
445   }
446   return parent;
447 }
448
449 static void
450 gst_element_factory_restore_thyself (GstObject *object, xmlNodePtr parent)
451 {
452   GstElementFactory *factory = GST_ELEMENT_FACTORY (object);
453   xmlNodePtr children = parent->xmlChildrenNode;
454   
455   factory->details_dynamic = TRUE;
456   factory->details = g_new0(GstElementDetails, 1);
457   factory->padtemplates = NULL;
458
459   if (GST_OBJECT_CLASS (parent_class)->restore_thyself) {
460     GST_OBJECT_CLASS (parent_class)->restore_thyself (object, parent);
461   }
462
463   while (children) {
464     if (!strcmp(children->name, "longname")) {
465       factory->details->longname = xmlNodeGetContent(children);
466     }
467     if (!strcmp(children->name, "class")) {
468       factory->details->klass = xmlNodeGetContent(children);
469     }
470     if (!strcmp(children->name, "description")) {
471       factory->details->description = xmlNodeGetContent(children);
472     }
473     if (!strcmp(children->name, "version")) {
474       factory->details->version = xmlNodeGetContent(children);
475     }
476     if (!strcmp(children->name, "author")) {
477       factory->details->author = xmlNodeGetContent(children);
478     }
479     if (!strcmp(children->name, "copyright")) {
480       factory->details->copyright = xmlNodeGetContent(children);
481     }
482     if (!strcmp(children->name, "padtemplate")) {
483        GstPadTemplate *template;
484
485        template = gst_pad_template_load_thyself (children);
486
487        gst_element_factory_add_pad_template (factory, template);
488     }
489
490     children = children->next;
491   }
492 }
493 #endif /* GST_DISABLE_REGISTRY */