set the "name" property on pad templates
[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 element factory 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 element factories.
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 will 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 element factory.
264  * If name is NULL, then the element will receive a guaranteed unique name,
265  * consisting of the element factory name and a number.
266  * If name is given, it will be given the name supplied.
267  *
268  * Returns: new #GstElement (or NULL if unable to create element)
269  */
270 GstElement*
271 gst_element_factory_make (const gchar *factoryname, const gchar *name)
272 {
273   GstElementFactory *factory;
274   GstElement *element;
275
276   g_return_val_if_fail (factoryname != NULL, NULL);
277
278   GST_DEBUG (GST_CAT_ELEMENT_FACTORY, "gstelementfactory: make \"%s\" \"%s\"", factoryname, name);
279
280   /* gst_plugin_load_element_factory(factoryname); */
281   factory = gst_element_factory_find(factoryname);
282   if (factory == NULL) {
283     GST_INFO (GST_CAT_ELEMENT_FACTORY,"no such elementfactory \"%s\"!",factoryname);
284     return NULL;
285   }
286   element = gst_element_factory_create (factory, name);
287   if (element == NULL) {
288     GST_INFO (GST_CAT_ELEMENT_FACTORY,"couldn't create instance of elementfactory \"%s\"!",factoryname);
289     return NULL;
290   }
291
292   return element;
293 }
294
295 /**
296  * gst_element_factory_add_pad_template :
297  * @elementfactory: factory to add the src id to
298  * @templ: the padtemplate to add
299  *
300  * Add the given padtemplate to this elementfactory.
301  */
302 void
303 gst_element_factory_add_pad_template (GstElementFactory *factory,
304                                     GstPadTemplate *templ)
305 {
306   GList *padtemplates;
307   
308   g_return_if_fail(factory != NULL);
309   g_return_if_fail(templ != NULL);
310
311   padtemplates = factory->padtemplates;
312
313   gst_object_ref (GST_OBJECT (templ));
314
315   while (padtemplates) {
316     GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
317     
318     if (!strcmp (oldtempl->name_template, templ->name_template)) {
319       gst_object_unref (GST_OBJECT (oldtempl));
320       padtemplates->data = templ;
321       return;
322     }
323     
324     padtemplates = g_list_next (padtemplates);
325   }
326   factory->padtemplates = g_list_append (factory->padtemplates, templ);
327   factory->numpadtemplates++;
328 }
329
330 /**
331  * gst_element_factory_can_src_caps :
332  * @factory: factory to query
333  * @caps: the caps to check
334  *
335  * Checks if the factory can source the given capability.
336  *
337  * Returns: true if it can src the capabilities
338  */
339 gboolean
340 gst_element_factory_can_src_caps (GstElementFactory *factory,
341                                  GstCaps *caps)
342 {
343   GList *templates;
344
345   g_return_val_if_fail(factory != NULL, FALSE);
346   g_return_val_if_fail(caps != NULL, FALSE);
347
348   templates = factory->padtemplates;
349
350   while (templates) {
351     GstPadTemplate *template = (GstPadTemplate *)templates->data;
352
353     if (template->direction == GST_PAD_SRC) {
354       if (gst_caps_check_compatibility (GST_PAD_TEMPLATE_CAPS (template), caps))
355         return TRUE;
356     }
357     templates = g_list_next (templates);
358   }
359
360   return FALSE;
361 }
362
363 /**
364  * gst_element_factory_can_sink_caps :
365  * @factory: factory to query
366  * @caps: the caps to check
367  *
368  * Checks if the factory can sink the given capability.
369  *
370  * Returns: true if it can sink the capabilities
371  */
372 gboolean
373 gst_element_factory_can_sink_caps (GstElementFactory *factory,
374                                   GstCaps *caps)
375 {
376   GList *templates;
377
378   g_return_val_if_fail(factory != NULL, FALSE);
379   g_return_val_if_fail(caps != NULL, FALSE);
380
381   templates = factory->padtemplates;
382
383   while (templates) {
384     GstPadTemplate *template = (GstPadTemplate *)templates->data;
385
386     if (template->direction == GST_PAD_SINK) {
387       if (gst_caps_check_compatibility (caps, GST_PAD_TEMPLATE_CAPS (template)))
388         return TRUE;
389     }
390     templates = g_list_next (templates);
391   }
392
393   return FALSE;
394 }
395
396 static void
397 gst_element_factory_unload_thyself (GstPluginFeature *feature)
398 {
399   GstElementFactory *factory;
400
401   factory = GST_ELEMENT_FACTORY (feature);
402
403   factory->type = 0;
404 }
405
406 #ifndef GST_DISABLE_REGISTRY
407 static xmlNodePtr
408 gst_element_factory_save_thyself (GstObject *object,
409                                  xmlNodePtr parent)
410 {
411   GList *pads;
412   GstElementFactory *factory;
413
414   factory = GST_ELEMENT_FACTORY (object);
415   
416   if (GST_OBJECT_CLASS (parent_class)->save_thyself) {
417     GST_OBJECT_CLASS (parent_class)->save_thyself (object, parent);
418   }
419
420   g_return_val_if_fail(factory != NULL, NULL);
421
422   if (factory->details)
423     {
424       xmlNewChild(parent,NULL,"longname", factory->details->longname);
425       xmlNewChild(parent,NULL,"class", factory->details->klass);
426       xmlNewChild(parent,NULL,"description", factory->details->description);
427       xmlNewChild(parent,NULL,"version", factory->details->version);
428       xmlNewChild(parent,NULL,"author", factory->details->author);
429       xmlNewChild(parent,NULL,"copyright", factory->details->copyright);
430     }
431   else
432     g_warning ("elementfactory `%s' is missing details",
433                object->name);
434
435   pads = factory->padtemplates;
436   if (pads) {
437     while (pads) {
438       xmlNodePtr subtree;
439       GstPadTemplate *padtemplate = (GstPadTemplate *)pads->data;
440
441       subtree = xmlNewChild(parent, NULL, "padtemplate", NULL);
442       gst_pad_template_save_thyself(padtemplate, subtree);
443
444       pads = g_list_next (pads);
445     }
446   }
447   return parent;
448 }
449
450 static void
451 gst_element_factory_restore_thyself (GstObject *object, xmlNodePtr parent)
452 {
453   GstElementFactory *factory = GST_ELEMENT_FACTORY (object);
454   xmlNodePtr children = parent->xmlChildrenNode;
455   
456   factory->details_dynamic = TRUE;
457   factory->details = g_new0(GstElementDetails, 1);
458   factory->padtemplates = NULL;
459
460   if (GST_OBJECT_CLASS (parent_class)->restore_thyself) {
461     GST_OBJECT_CLASS (parent_class)->restore_thyself (object, parent);
462   }
463
464   while (children) {
465     if (!strcmp(children->name, "longname")) {
466       factory->details->longname = xmlNodeGetContent(children);
467     }
468     if (!strcmp(children->name, "class")) {
469       factory->details->klass = xmlNodeGetContent(children);
470     }
471     if (!strcmp(children->name, "description")) {
472       factory->details->description = xmlNodeGetContent(children);
473     }
474     if (!strcmp(children->name, "version")) {
475       factory->details->version = xmlNodeGetContent(children);
476     }
477     if (!strcmp(children->name, "author")) {
478       factory->details->author = xmlNodeGetContent(children);
479     }
480     if (!strcmp(children->name, "copyright")) {
481       factory->details->copyright = xmlNodeGetContent(children);
482     }
483     if (!strcmp(children->name, "padtemplate")) {
484        GstPadTemplate *template;
485
486        template = gst_pad_template_load_thyself (children);
487
488        gst_element_factory_add_pad_template (factory, template);
489     }
490
491     children = children->next;
492   }
493 }
494 #endif /* GST_DISABLE_REGISTRY */