merge from EVENTS1 on 20011016
[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_elementfactory_class_init           (GstElementFactoryClass *klass);
29 static void                     gst_elementfactory_init                 (GstElementFactory *factory);
30
31 #ifndef GST_DISABLE_REGISTRY
32 static void                     gst_elementfactory_restore_thyself      (GstObject *object, xmlNodePtr parent);
33 static xmlNodePtr               gst_elementfactory_save_thyself         (GstObject *object, xmlNodePtr parent);
34 #endif
35
36 static void                     gst_elementfactory_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_elementfactory_signals[LAST_SIGNAL] = { 0 };
43
44 GType 
45 gst_elementfactory_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_elementfactory_class_init,
55       NULL,
56       NULL,
57       sizeof(GstElementFactory),
58       0,
59       (GInstanceInitFunc) gst_elementfactory_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_elementfactory_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_elementfactory_save_thyself);
83   gstobject_class->restore_thyself =    GST_DEBUG_FUNCPTR (gst_elementfactory_restore_thyself);
84 #endif
85
86   gstpluginfeature_class->unload_thyself =      GST_DEBUG_FUNCPTR (gst_elementfactory_unload_thyself);
87
88   _gst_elementfactories = NULL;
89 }
90
91 static void
92 gst_elementfactory_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_elementfactory_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_elementfactory_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_ELEMENTFACTORY,"no such elementfactory \"%s\"\n", name);
126   return NULL;
127 }
128
129 /**
130  * gst_elementfactory_get_list:
131  *
132  * Get the global list of elementfactories.
133  *
134  * Returns: GList of type #GstElementFactory
135  */
136 const GList*
137 gst_elementfactory_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_elementfactory_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_elementfactory_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_elementfactory_find (name);
184
185   if (!factory)
186     factory = GST_ELEMENTFACTORY (g_object_new (GST_TYPE_ELEMENTFACTORY, 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 /* FIXME: g_critical is glib-2.0, not glib-1.2
200     g_critical ("`%s' requested type change (!)", name);
201 */
202     g_warning ("`%s' requested type change (!)", name);
203   gst_object_set_name (GST_OBJECT (factory), name);
204
205   return factory;
206 }
207
208 /**
209  * gst_elementfactory_create:
210  * @factory: factory to instantiate
211  * @name: name of new element
212  *
213  * Create a new element of the type defined by the given elementfactory.
214  * It wll be given the name supplied, since all elements require a name as
215  * their first argument.
216  *
217  * Returns: new #GstElement
218  */
219 GstElement *
220 gst_elementfactory_create (GstElementFactory *factory,
221                            const gchar *name)
222 {
223   GstElement *element;
224   GstElementClass *oclass;
225
226   g_return_val_if_fail(factory != NULL, NULL);
227   g_return_val_if_fail(name != NULL, NULL);
228
229   GST_DEBUG (GST_CAT_ELEMENTFACTORY,"creating element from factory \"%s\" with name \"%s\" and type %d\n", 
230              GST_OBJECT_NAME (factory), name, factory->type);
231
232   gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory));
233
234   if (factory->type == 0)
235     {
236 /* FIXME: g_critical is glib-2.0, not glib-1.2
237       g_critical ("Factory for `%s' has no type",
238 */
239       g_warning ("Factory for `%s' has no type",
240                   gst_object_get_name (GST_OBJECT (factory)));
241       return NULL;
242     }
243
244   // create an instance of the element
245   element = GST_ELEMENT(g_object_new(factory->type,NULL));
246   g_assert(element != NULL);
247
248   // attempt to set the elemenfactory class pointer if necessary
249   oclass = GST_ELEMENT_CLASS(G_OBJECT_GET_CLASS(element));
250   if (oclass->elementfactory == NULL) {
251     GST_DEBUG (GST_CAT_ELEMENTFACTORY,"class %s\n", GST_OBJECT_NAME (factory));
252     oclass->elementfactory = factory;
253   }
254   
255   // copy pad template pointers to the element class
256   oclass->padtemplates = g_list_copy(factory->padtemplates);
257   oclass->numpadtemplates = factory->numpadtemplates;
258   
259   gst_object_set_name (GST_OBJECT (element),name);
260
261   return element;
262 }
263
264 /**
265  * gst_elementfactory_make:
266  * @factoryname: a named factory to instantiate
267  * @name: name of new element
268  *
269  * Create a new element of the type defined by the given elementfactory.
270  * It wll be given the name supplied, since all elements require a name as
271  * their first argument.
272  *
273  * Returns: new #GstElement
274  */
275 GstElement*
276 gst_elementfactory_make (const gchar *factoryname, const gchar *name)
277 {
278   GstElementFactory *factory;
279   GstElement *element;
280
281   g_return_val_if_fail (factoryname != NULL, NULL);
282   g_return_val_if_fail (name != NULL, NULL);
283
284   GST_DEBUG (GST_CAT_ELEMENTFACTORY, "gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
285
286   //gst_plugin_load_elementfactory(factoryname);
287   factory = gst_elementfactory_find(factoryname);
288   if (factory == NULL) {
289     GST_INFO (GST_CAT_ELEMENTFACTORY,"no such elementfactory \"%s\"!",factoryname);
290     return NULL;
291   }
292   element = gst_elementfactory_create(factory,name);
293   if (element == NULL) {
294     GST_INFO (GST_CAT_ELEMENTFACTORY,"couldn't create instance of elementfactory \"%s\"!",factoryname);
295     return NULL;
296   }
297
298   return element;
299 }
300
301 /**
302  * gst_elementfactory_add_padtemplate :
303  * @elementfactory: factory to add the src id to
304  * @templ: the padtemplate to add
305  *
306  * Add the given padtemplate to this elementfactory.
307  */
308 void
309 gst_elementfactory_add_padtemplate (GstElementFactory *factory,
310                                     GstPadTemplate *templ)
311 {
312   GList *padtemplates;
313   
314   g_return_if_fail(factory != NULL);
315   g_return_if_fail(templ != NULL);
316
317   padtemplates = factory->padtemplates;
318
319   gst_object_ref (GST_OBJECT (templ));
320
321   while (padtemplates) {
322     GstPadTemplate *oldtempl = GST_PADTEMPLATE (padtemplates->data);
323     
324     if (!strcmp (oldtempl->name_template, templ->name_template)) {
325       gst_object_unref (GST_OBJECT (oldtempl));
326       padtemplates->data = templ;
327       return;
328     }
329     
330     padtemplates = g_list_next (padtemplates);
331   }
332   factory->padtemplates = g_list_append (factory->padtemplates, templ);
333   factory->numpadtemplates++;
334 }
335
336 /**
337  * gst_elementfactory_can_src_caps :
338  * @factory: factory to query
339  * @caps: the caps to check
340  *
341  * Checks if the factory can source the given capability.
342  *
343  * Returns: true if it can src the capabilities
344  */
345 gboolean
346 gst_elementfactory_can_src_caps (GstElementFactory *factory,
347                                  GstCaps *caps)
348 {
349   GList *templates;
350
351   g_return_val_if_fail(factory != NULL, FALSE);
352   g_return_val_if_fail(caps != NULL, FALSE);
353
354   templates = factory->padtemplates;
355
356   while (templates) {
357     GstPadTemplate *template = (GstPadTemplate *)templates->data;
358
359     if (template->direction == GST_PAD_SRC) {
360       if (gst_caps_check_compatibility (GST_PADTEMPLATE_CAPS (template), caps))
361         return TRUE;
362     }
363     templates = g_list_next (templates);
364   }
365
366   return FALSE;
367 }
368
369 /**
370  * gst_elementfactory_can_sink_caps :
371  * @factory: factory to query
372  * @caps: the caps to check
373  *
374  * Checks if the factory can sink the given capability.
375  *
376  * Returns: true if it can sink the capabilities
377  */
378 gboolean
379 gst_elementfactory_can_sink_caps (GstElementFactory *factory,
380                                   GstCaps *caps)
381 {
382   GList *templates;
383
384   g_return_val_if_fail(factory != NULL, FALSE);
385   g_return_val_if_fail(caps != NULL, FALSE);
386
387   templates = factory->padtemplates;
388
389   while (templates) {
390     GstPadTemplate *template = (GstPadTemplate *)templates->data;
391
392     if (template->direction == GST_PAD_SINK) {
393       if (gst_caps_check_compatibility (caps, GST_PADTEMPLATE_CAPS (template)))
394         return TRUE;
395     }
396     templates = g_list_next (templates);
397   }
398
399   return FALSE;
400 }
401
402 static void
403 gst_elementfactory_unload_thyself (GstPluginFeature *feature)
404 {
405   GstElementFactory *factory;
406
407   factory = GST_ELEMENTFACTORY (feature);
408
409   factory->type = 0;
410 }
411
412 #ifndef GST_DISABLE_REGISTRY
413 static xmlNodePtr
414 gst_elementfactory_save_thyself (GstObject *object,
415                                  xmlNodePtr parent)
416 {
417   GList *pads;
418   GstElementFactory *factory;
419
420   factory = GST_ELEMENTFACTORY (object);
421   
422   if (GST_OBJECT_CLASS (parent_class)->save_thyself) {
423     GST_OBJECT_CLASS (parent_class)->save_thyself (object, parent);
424   }
425
426   g_return_val_if_fail(factory != NULL, NULL);
427
428   if (factory->details)
429     {
430       xmlNewChild(parent,NULL,"longname", factory->details->longname);
431       xmlNewChild(parent,NULL,"class", factory->details->klass);
432       xmlNewChild(parent,NULL,"description", factory->details->description);
433       xmlNewChild(parent,NULL,"version", factory->details->version);
434       xmlNewChild(parent,NULL,"author", factory->details->author);
435       xmlNewChild(parent,NULL,"copyright", factory->details->copyright);
436     }
437   else
438     g_warning ("elementfactory `%s' is missing details",
439                object->name);
440
441   pads = factory->padtemplates;
442   if (pads) {
443     while (pads) {
444       xmlNodePtr subtree;
445       GstPadTemplate *padtemplate = (GstPadTemplate *)pads->data;
446
447       subtree = xmlNewChild(parent, NULL, "padtemplate", NULL);
448       gst_padtemplate_save_thyself(padtemplate, subtree);
449
450       pads = g_list_next (pads);
451     }
452   }
453   return parent;
454 }
455
456 static void
457 gst_elementfactory_restore_thyself (GstObject *object, xmlNodePtr parent)
458 {
459   GstElementFactory *factory = GST_ELEMENTFACTORY (object);
460   xmlNodePtr children = parent->xmlChildrenNode;
461   
462   factory->details_dynamic = TRUE;
463   factory->details = g_new0(GstElementDetails, 1);
464   factory->padtemplates = NULL;
465
466   if (GST_OBJECT_CLASS (parent_class)->restore_thyself) {
467     GST_OBJECT_CLASS (parent_class)->restore_thyself (object, parent);
468   }
469
470   while (children) {
471     if (!strcmp(children->name, "longname")) {
472       factory->details->longname = xmlNodeGetContent(children);
473     }
474     if (!strcmp(children->name, "class")) {
475       factory->details->klass = xmlNodeGetContent(children);
476     }
477     if (!strcmp(children->name, "description")) {
478       factory->details->description = xmlNodeGetContent(children);
479     }
480     if (!strcmp(children->name, "version")) {
481       factory->details->version = xmlNodeGetContent(children);
482     }
483     if (!strcmp(children->name, "author")) {
484       factory->details->author = xmlNodeGetContent(children);
485     }
486     if (!strcmp(children->name, "copyright")) {
487       factory->details->copyright = xmlNodeGetContent(children);
488     }
489     if (!strcmp(children->name, "padtemplate")) {
490        GstPadTemplate *template;
491
492        template = gst_padtemplate_load_thyself (children);
493
494        gst_elementfactory_add_padtemplate (factory, template);
495     }
496
497     children = children->next;
498   }
499 }
500 #endif /* GST_DISABLE_REGISTRY */