1 /* GStreamer
2  * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "gstfrei0r.h"
25 #include "gstfrei0rfilter.h"
26 #include "gstfrei0rsrc.h"
27 #include "gstfrei0rmixer.h"
28 
29 #include <string.h>
30 #include <gmodule.h>
31 
32 GST_DEBUG_CATEGORY (frei0r_debug);
33 #define GST_CAT_DEFAULT frei0r_debug
34 
35 static GstStaticCaps bgra8888_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
36     ("BGRA"));
37 static GstStaticCaps rgba8888_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
38     ("RGBA"));
39 static GstStaticCaps packed32_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
40     ("{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV }"));
41 
42 GstCaps *
gst_frei0r_caps_from_color_model(gint color_model)43 gst_frei0r_caps_from_color_model (gint color_model)
44 {
45   switch (color_model) {
46     case F0R_COLOR_MODEL_BGRA8888:
47       return gst_static_caps_get (&bgra8888_caps);
48     case F0R_COLOR_MODEL_RGBA8888:
49       return gst_static_caps_get (&rgba8888_caps);
50     case F0R_COLOR_MODEL_PACKED32:
51       return gst_static_caps_get (&packed32_caps);
52     default:
53       break;
54   }
55 
56   return NULL;
57 }
58 
59 void
gst_frei0r_klass_install_properties(GObjectClass * gobject_class,GstFrei0rFuncTable * ftable,GstFrei0rProperty * properties,gint n_properties)60 gst_frei0r_klass_install_properties (GObjectClass * gobject_class,
61     GstFrei0rFuncTable * ftable, GstFrei0rProperty * properties,
62     gint n_properties)
63 {
64   gint i, count = 1;
65   f0r_instance_t *instance = ftable->construct (640, 480);
66 
67   g_assert (instance);
68 
69   for (i = 0; i < n_properties; i++) {
70     f0r_param_info_t *param_info = &properties[i].info;
71     gchar *prop_name;
72 
73     ftable->get_param_info (param_info, i);
74 
75     if (!param_info->name) {
76       GST_ERROR ("Property %d of %s without a valid name", i,
77           g_type_name (G_TYPE_FROM_CLASS (gobject_class)));
78       continue;
79     }
80 
81     prop_name = g_ascii_strdown (param_info->name, -1);
82     g_strcanon (prop_name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-+", '-');
83     /* satisfy glib2 (argname[0] must be [A-Za-z]) */
84     if (!((prop_name[0] >= 'a' && prop_name[0] <= 'z') ||
85             (prop_name[0] >= 'A' && prop_name[0] <= 'Z'))) {
86       gchar *tempstr = prop_name;
87 
88       prop_name = g_strconcat ("param-", prop_name, NULL);
89       g_free (tempstr);
90     }
91 
92     properties[i].prop_id = count;
93     properties[i].prop_idx = i;
94 
95     ftable->get_param_value (instance, &properties[i].default_value, i);
96     if (param_info->type == F0R_PARAM_STRING)
97       properties[i].default_value.data.s =
98           g_strdup (properties[i].default_value.data.s);
99 
100     switch (param_info->type) {
101       case F0R_PARAM_BOOL:
102         g_object_class_install_property (gobject_class, count++,
103             g_param_spec_boolean (prop_name, param_info->name,
104                 param_info->explanation,
105                 properties[i].default_value.data.b ? TRUE : FALSE,
106                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
107         properties[i].n_prop_ids = 1;
108         break;
109       case F0R_PARAM_DOUBLE:{
110         gdouble def = properties[i].default_value.data.d;
111 
112         /* If the default is NAN, +-INF we use 0.0 */
113         if (!(def >= 0.0 && def <= 1.0))
114           def = 0.0;
115 
116         g_object_class_install_property (gobject_class, count++,
117             g_param_spec_double (prop_name, param_info->name,
118                 param_info->explanation, 0.0, 1.0, def,
119                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
120         properties[i].n_prop_ids = 1;
121         break;
122       }
123       case F0R_PARAM_STRING:
124         g_object_class_install_property (gobject_class, count++,
125             g_param_spec_string (prop_name, param_info->name,
126                 param_info->explanation, properties[i].default_value.data.s,
127                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
128         properties[i].n_prop_ids = 1;
129         break;
130       case F0R_PARAM_COLOR:{
131         gchar *prop_name_full;
132         gchar *prop_nick_full;
133         gdouble def;
134 
135         def = properties[i].default_value.data.color.r;
136         /* If the default is out of range we use 0.0 */
137         if (!(def <= 1.0 && def >= 0.0))
138           def = 0.0;
139         prop_name_full = g_strconcat (prop_name, "-r", NULL);
140         prop_nick_full = g_strconcat (param_info->name, " (R)", NULL);
141         g_object_class_install_property (gobject_class, count++,
142             g_param_spec_float (prop_name_full, prop_nick_full,
143                 param_info->explanation, 0.0, 1.0, def,
144                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
145         g_free (prop_name_full);
146         g_free (prop_nick_full);
147 
148         def = properties[i].default_value.data.color.g;
149         /* If the default is out of range we use 0.0 */
150         if (!(def <= 1.0 && def >= 0.0))
151           def = 0.0;
152         prop_name_full = g_strconcat (prop_name, "-g", NULL);
153         prop_nick_full = g_strconcat (param_info->name, " (G)", NULL);
154         g_object_class_install_property (gobject_class, count++,
155             g_param_spec_float (prop_name_full, prop_nick_full,
156                 param_info->explanation, 0.0, 1.0, def,
157                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
158         g_free (prop_name_full);
159         g_free (prop_nick_full);
160 
161         def = properties[i].default_value.data.color.b;
162         /* If the default is out of range we use 0.0 */
163         if (!(def <= 1.0 && def >= 0.0))
164           def = 0.0;
165         prop_name_full = g_strconcat (prop_name, "-b", NULL);
166         prop_nick_full = g_strconcat (param_info->name, " (B)", NULL);
167         g_object_class_install_property (gobject_class, count++,
168             g_param_spec_float (prop_name_full, prop_nick_full,
169                 param_info->explanation, 0.0, 1.0, def,
170                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
171         g_free (prop_name_full);
172         g_free (prop_nick_full);
173 
174         properties[i].n_prop_ids = 3;
175         break;
176       }
177       case F0R_PARAM_POSITION:{
178         gchar *prop_name_full;
179         gchar *prop_nick_full;
180         gdouble def;
181 
182         def = properties[i].default_value.data.position.x;
183         /* If the default is out of range we use 0.0 */
184         if (!(def <= 1.0 && def >= 0.0))
185           def = 0.0;
186         prop_name_full = g_strconcat (prop_name, "-x", NULL);
187         prop_nick_full = g_strconcat (param_info->name, " (X)", NULL);
188         g_object_class_install_property (gobject_class, count++,
189             g_param_spec_double (prop_name_full, prop_nick_full,
190                 param_info->explanation, 0.0, 1.0, def,
191                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
192         g_free (prop_name_full);
193         g_free (prop_nick_full);
194 
195         def = properties[i].default_value.data.position.y;
196         /* If the default is out of range we use 0.0 */
197         if (!(def <= 1.0 && def >= 0.0))
198           def = 0.0;
199         prop_name_full = g_strconcat (prop_name, "-Y", NULL);
200         prop_nick_full = g_strconcat (param_info->name, " (Y)", NULL);
201         g_object_class_install_property (gobject_class, count++,
202             g_param_spec_double (prop_name_full, prop_nick_full,
203                 param_info->explanation, 0.0, 1.0, def,
204                 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
205         g_free (prop_name_full);
206         g_free (prop_nick_full);
207 
208         properties[i].n_prop_ids = 2;
209         break;
210       }
211       default:
212         g_assert_not_reached ();
213         break;
214     }
215 
216     g_free (prop_name);
217   }
218 
219   ftable->destruct (instance);
220 }
221 
222 GstFrei0rPropertyValue *
gst_frei0r_property_cache_init(GstFrei0rProperty * properties,gint n_properties)223 gst_frei0r_property_cache_init (GstFrei0rProperty * properties,
224     gint n_properties)
225 {
226   gint i;
227   GstFrei0rPropertyValue *ret = g_new0 (GstFrei0rPropertyValue, n_properties);
228 
229   for (i = 0; i < n_properties; i++) {
230     memcpy (&ret[i].data, &properties[i].default_value,
231         sizeof (GstFrei0rPropertyValue));
232 
233     if (properties[i].info.type == F0R_PARAM_STRING)
234       ret[i].data.s = g_strdup (ret[i].data.s);
235   }
236 
237   return ret;
238 }
239 
240 void
gst_frei0r_property_cache_free(GstFrei0rProperty * properties,GstFrei0rPropertyValue * property_cache,gint n_properties)241 gst_frei0r_property_cache_free (GstFrei0rProperty * properties,
242     GstFrei0rPropertyValue * property_cache, gint n_properties)
243 {
244   gint i;
245 
246   for (i = 0; i < n_properties; i++) {
247     if (properties[i].info.type == F0R_PARAM_STRING)
248       g_free (property_cache[i].data.s);
249   }
250   g_free (property_cache);
251 }
252 
253 f0r_instance_t *
gst_frei0r_instance_construct(GstFrei0rFuncTable * ftable,GstFrei0rProperty * properties,gint n_properties,GstFrei0rPropertyValue * property_cache,gint width,gint height)254 gst_frei0r_instance_construct (GstFrei0rFuncTable * ftable,
255     GstFrei0rProperty * properties, gint n_properties,
256     GstFrei0rPropertyValue * property_cache, gint width, gint height)
257 {
258   f0r_instance_t *instance = ftable->construct (width, height);
259   gint i;
260 
261   for (i = 0; i < n_properties; i++)
262     ftable->set_param_value (instance, &property_cache[i].data, i);
263 
264   return instance;
265 }
266 
267 gboolean
gst_frei0r_get_property(f0r_instance_t * instance,GstFrei0rFuncTable * ftable,GstFrei0rProperty * properties,gint n_properties,GstFrei0rPropertyValue * property_cache,guint prop_id,GValue * value)268 gst_frei0r_get_property (f0r_instance_t * instance, GstFrei0rFuncTable * ftable,
269     GstFrei0rProperty * properties, gint n_properties,
270     GstFrei0rPropertyValue * property_cache, guint prop_id, GValue * value)
271 {
272   gint i;
273   GstFrei0rProperty *prop = NULL;
274 
275   for (i = 0; i < n_properties; i++) {
276     if (properties[i].prop_id <= prop_id &&
277         properties[i].prop_id + properties[i].n_prop_ids > prop_id) {
278       prop = &properties[i];
279       break;
280     }
281   }
282 
283   if (!prop)
284     return FALSE;
285 
286   switch (prop->info.type) {
287     case F0R_PARAM_BOOL:{
288       gdouble d;
289 
290       if (instance)
291         ftable->get_param_value (instance, &d, prop->prop_idx);
292       else
293         d = property_cache[prop->prop_idx].data.b;
294 
295       g_value_set_boolean (value, (d < 0.5) ? FALSE : TRUE);
296       break;
297     }
298     case F0R_PARAM_DOUBLE:{
299       gdouble d;
300 
301       if (instance)
302         ftable->get_param_value (instance, &d, prop->prop_idx);
303       else
304         d = property_cache[prop->prop_idx].data.d;
305 
306       g_value_set_double (value, d);
307       break;
308     }
309     case F0R_PARAM_STRING:{
310       gchar *s;
311 
312       if (instance)
313         ftable->get_param_value (instance, &s, prop->prop_idx);
314       else
315         s = property_cache[prop->prop_idx].data.s;
316       g_value_set_string (value, s);
317       break;
318     }
319     case F0R_PARAM_COLOR:{
320       f0r_param_color_t color;
321 
322       if (instance)
323         ftable->get_param_value (instance, &color, prop->prop_idx);
324       else
325         color = property_cache[prop->prop_idx].data.color;
326 
327       switch (prop_id - prop->prop_id) {
328         case 0:
329           g_value_set_float (value, color.r);
330           break;
331         case 1:
332           g_value_set_float (value, color.g);
333           break;
334         case 2:
335           g_value_set_float (value, color.b);
336           break;
337       }
338       break;
339     }
340     case F0R_PARAM_POSITION:{
341       f0r_param_position_t position;
342 
343       if (instance)
344         ftable->get_param_value (instance, &position, prop->prop_idx);
345       else
346         position = property_cache[prop->prop_idx].data.position;
347 
348       switch (prop_id - prop->prop_id) {
349         case 0:
350           g_value_set_double (value, position.x);
351           break;
352         case 1:
353           g_value_set_double (value, position.y);
354           break;
355       }
356       break;
357     }
358     default:
359       g_assert_not_reached ();
360       break;
361   }
362 
363   return TRUE;
364 }
365 
366 gboolean
gst_frei0r_set_property(f0r_instance_t * instance,GstFrei0rFuncTable * ftable,GstFrei0rProperty * properties,gint n_properties,GstFrei0rPropertyValue * property_cache,guint prop_id,const GValue * value)367 gst_frei0r_set_property (f0r_instance_t * instance, GstFrei0rFuncTable * ftable,
368     GstFrei0rProperty * properties, gint n_properties,
369     GstFrei0rPropertyValue * property_cache, guint prop_id,
370     const GValue * value)
371 {
372   GstFrei0rProperty *prop = NULL;
373   gint i;
374 
375   for (i = 0; i < n_properties; i++) {
376     if (properties[i].prop_id <= prop_id &&
377         properties[i].prop_id + properties[i].n_prop_ids > prop_id) {
378       prop = &properties[i];
379       break;
380     }
381   }
382 
383   if (!prop)
384     return FALSE;
385 
386   switch (prop->info.type) {
387     case F0R_PARAM_BOOL:{
388       gboolean b = g_value_get_boolean (value);
389       gdouble d = b ? 1.0 : 0.0;
390 
391       if (instance)
392         ftable->set_param_value (instance, &d, prop->prop_idx);
393       property_cache[prop->prop_idx].data.b = d;
394       break;
395     }
396     case F0R_PARAM_DOUBLE:{
397       gdouble d = g_value_get_double (value);
398 
399       if (instance)
400         ftable->set_param_value (instance, &d, prop->prop_idx);
401       property_cache[prop->prop_idx].data.d = d;
402       break;
403     }
404     case F0R_PARAM_STRING:{
405       gchar *s = g_value_dup_string (value);
406 
407       /* Copies the string */
408       if (instance)
409         ftable->set_param_value (instance, s, prop->prop_idx);
410       property_cache[prop->prop_idx].data.s = s;
411       break;
412     }
413     case F0R_PARAM_COLOR:{
414       gfloat f = g_value_get_float (value);
415       f0r_param_color_t *color = &property_cache[prop->prop_idx].data.color;
416 
417       switch (prop_id - prop->prop_id) {
418         case 0:
419           color->r = f;
420           break;
421         case 1:
422           color->g = f;
423           break;
424         case 2:
425           color->b = f;
426           break;
427         default:
428           g_assert_not_reached ();
429       }
430 
431       if (instance)
432         ftable->set_param_value (instance, color, prop->prop_idx);
433       break;
434     }
435     case F0R_PARAM_POSITION:{
436       gdouble d = g_value_get_double (value);
437       f0r_param_position_t *position =
438           &property_cache[prop->prop_idx].data.position;
439 
440       switch (prop_id - prop->prop_id) {
441         case 0:
442           position->x = d;
443           break;
444         case 1:
445           position->y = d;
446           break;
447         default:
448           g_assert_not_reached ();
449       }
450       if (instance)
451         ftable->set_param_value (instance, position, prop->prop_idx);
452       break;
453     }
454     default:
455       g_assert_not_reached ();
456       break;
457   }
458 
459   return TRUE;
460 }
461 
462 static gboolean
register_plugin(GstPlugin * plugin,const gchar * vendor,const gchar * filename)463 register_plugin (GstPlugin * plugin, const gchar * vendor,
464     const gchar * filename)
465 {
466   GModule *module;
467   GstFrei0rPluginRegisterReturn ret = GST_FREI0R_PLUGIN_REGISTER_RETURN_FAILED;
468   GstFrei0rFuncTable ftable = { NULL, };
469   gint i;
470   f0r_plugin_info_t info = { NULL, };
471   f0r_instance_t *instance = NULL;
472 
473   GST_DEBUG ("Registering plugin '%s'", filename);
474 
475   module = g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
476   if (!module) {
477     GST_WARNING ("Failed to load plugin");
478     return FALSE;
479   }
480 
481   if (!g_module_symbol (module, "f0r_init", (gpointer *) & ftable.init)) {
482     GST_INFO ("No frei0r plugin");
483     g_module_close (module);
484     return FALSE;
485   }
486 
487   if (!g_module_symbol (module, "f0r_deinit", (gpointer *) & ftable.deinit) ||
488       !g_module_symbol (module, "f0r_construct",
489           (gpointer *) & ftable.construct)
490       || !g_module_symbol (module, "f0r_destruct",
491           (gpointer *) & ftable.destruct)
492       || !g_module_symbol (module, "f0r_get_plugin_info",
493           (gpointer *) & ftable.get_plugin_info)
494       || !g_module_symbol (module, "f0r_get_param_info",
495           (gpointer *) & ftable.get_param_info)
496       || !g_module_symbol (module, "f0r_set_param_value",
497           (gpointer *) & ftable.set_param_value)
498       || !g_module_symbol (module, "f0r_get_param_value",
499           (gpointer *) & ftable.get_param_value))
500     goto invalid_frei0r_plugin;
501 
502   /* One of these must exist */
503   g_module_symbol (module, "f0r_update", (gpointer *) & ftable.update);
504   g_module_symbol (module, "f0r_update2", (gpointer *) & ftable.update2);
505 
506   if (!ftable.init ()) {
507     GST_WARNING ("Failed to initialize plugin");
508     g_module_close (module);
509     return FALSE;
510   }
511 
512   if (!ftable.update && !ftable.update2)
513     goto invalid_frei0r_plugin;
514 
515   ftable.get_plugin_info (&info);
516 
517   if (info.frei0r_version > 1) {
518     GST_WARNING ("Unsupported frei0r version %d", info.frei0r_version);
519     ftable.deinit ();
520     g_module_close (module);
521     return FALSE;
522   }
523 
524   if (info.color_model > F0R_COLOR_MODEL_PACKED32) {
525     GST_WARNING ("Unsupported color model %d", info.color_model);
526     ftable.deinit ();
527     g_module_close (module);
528     return FALSE;
529   }
530 
531   for (i = 0; i < info.num_params; i++) {
532     f0r_param_info_t pinfo = { NULL, };
533 
534     ftable.get_param_info (&pinfo, i);
535     if (pinfo.type > F0R_PARAM_STRING) {
536       GST_WARNING ("Unsupported parameter type %d", pinfo.type);
537       ftable.deinit ();
538       g_module_close (module);
539       return FALSE;
540     }
541   }
542 
543   instance = ftable.construct (640, 480);
544   if (!instance) {
545     GST_WARNING ("Failed to instanciate plugin '%s'", info.name);
546     ftable.deinit ();
547     g_module_close (module);
548     return FALSE;
549   }
550   ftable.destruct (instance);
551 
552   switch (info.plugin_type) {
553     case F0R_PLUGIN_TYPE_FILTER:
554       ret = gst_frei0r_filter_register (plugin, vendor, &info, &ftable);
555       break;
556     case F0R_PLUGIN_TYPE_SOURCE:
557       ret = gst_frei0r_src_register (plugin, vendor, &info, &ftable);
558       break;
559     case F0R_PLUGIN_TYPE_MIXER2:
560     case F0R_PLUGIN_TYPE_MIXER3:
561       ret = gst_frei0r_mixer_register (plugin, vendor, &info, &ftable);
562       break;
563     default:
564       break;
565   }
566 
567   switch (ret) {
568     case GST_FREI0R_PLUGIN_REGISTER_RETURN_OK:
569       return TRUE;
570     case GST_FREI0R_PLUGIN_REGISTER_RETURN_FAILED:
571       GST_ERROR ("Failed to register frei0r plugin");
572       ftable.deinit ();
573       g_module_close (module);
574       return FALSE;
575     case GST_FREI0R_PLUGIN_REGISTER_RETURN_ALREADY_REGISTERED:
576       GST_DEBUG ("frei0r plugin already registered");
577       ftable.deinit ();
578       g_module_close (module);
579       return TRUE;
580     default:
581       g_return_val_if_reached (FALSE);
582   }
583 
584   g_return_val_if_reached (FALSE);
585 
586 invalid_frei0r_plugin:
587   GST_ERROR ("Invalid frei0r plugin");
588   ftable.deinit ();
589   g_module_close (module);
590 
591   return FALSE;
592 }
593 
594 static gboolean
register_plugins(GstPlugin * plugin,GHashTable * plugin_names,const gchar * path,const gchar * base_path)595 register_plugins (GstPlugin * plugin, GHashTable * plugin_names,
596     const gchar * path, const gchar * base_path)
597 {
598   GDir *dir;
599   gchar *filename;
600   const gchar *entry_name;
601   gboolean ret = TRUE;
602 
603   GST_DEBUG ("Scanning directory '%s' for frei0r plugins", path);
604 
605   dir = g_dir_open (path, 0, NULL);
606   if (!dir)
607     return FALSE;
608 
609   while ((entry_name = g_dir_read_name (dir))) {
610     gchar *tmp, *vendor = NULL;
611     gchar *hashtable_name;
612 
613     tmp = g_strdup (path + strlen (base_path));
614     if (*tmp == G_DIR_SEPARATOR && *(tmp + 1))
615       vendor = tmp + 1;
616     else if (*tmp)
617       vendor = tmp;
618 
619     if (vendor)
620       hashtable_name = g_strconcat (vendor, "-", entry_name, NULL);
621     else
622       hashtable_name = g_strdup (entry_name);
623 
624     if (g_hash_table_lookup_extended (plugin_names, hashtable_name, NULL, NULL)) {
625       g_free (hashtable_name);
626       continue;
627     }
628 
629     filename = g_build_filename (path, entry_name, NULL);
630     if ((g_str_has_suffix (filename, G_MODULE_SUFFIX)
631 #ifdef GST_EXTRA_MODULE_SUFFIX
632             || g_str_has_suffix (filename, GST_EXTRA_MODULE_SUFFIX)
633 #endif
634         ) && g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
635       gboolean this_ret;
636 
637       this_ret = register_plugin (plugin, vendor, filename);
638       if (this_ret)
639         g_hash_table_insert (plugin_names, g_strdup (hashtable_name), NULL);
640 
641       ret = ret && this_ret;
642     } else if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
643       ret = ret && register_plugins (plugin, plugin_names, filename, base_path);
644     }
645     g_free (filename);
646     g_free (hashtable_name);
647     g_free (tmp);
648   }
649   g_dir_close (dir);
650 
651   return ret;
652 }
653 
654 static gboolean
plugin_init(GstPlugin * plugin)655 plugin_init (GstPlugin * plugin)
656 {
657   const gchar *homedir;
658   gchar *path, *libdir_path;
659   GHashTable *plugin_names;
660   const gchar *frei0r_path;
661 
662   GST_DEBUG_CATEGORY_INIT (frei0r_debug, "frei0r", 0, "frei0r");
663 
664   gst_plugin_add_dependency_simple (plugin,
665       "FREI0R_PATH:HOME/.frei0r-1/lib",
666       LIBDIR "/frei0r-1:"
667       "/usr/lib/frei0r-1:/usr/local/lib/frei0r-1:"
668       "/usr/lib32/frei0r-1:/usr/local/lib32/frei0r-1:"
669       "/usr/lib64/frei0r-1:/usr/local/lib64/frei0r-1",
670       NULL, GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
671 
672   plugin_names =
673       g_hash_table_new_full ((GHashFunc) g_str_hash, (GEqualFunc) g_str_equal,
674       (GDestroyNotify) g_free, NULL);
675 
676   frei0r_path = g_getenv ("FREI0R_PATH");
677   if (frei0r_path && *frei0r_path) {
678     gchar **p, **paths = g_strsplit (frei0r_path, ":", -1);
679 
680     for (p = paths; *p; p++) {
681       register_plugins (plugin, plugin_names, *p, *p);
682     }
683 
684     g_strfreev (paths);
685   } else {
686 #define register_plugins2(plugin, pn, p) register_plugins(plugin, pn, p, p)
687     homedir = g_get_home_dir ();
688     path = g_build_filename (homedir, ".frei0r-1", "lib", NULL);
689     libdir_path = g_build_filename (LIBDIR, "frei0r-1", NULL);
690     register_plugins2 (plugin, plugin_names, path);
691     g_free (path);
692     register_plugins2 (plugin, plugin_names, libdir_path);
693     g_free (libdir_path);
694     register_plugins2 (plugin, plugin_names, "/usr/local/lib/frei0r-1");
695     register_plugins2 (plugin, plugin_names, "/usr/lib/frei0r-1");
696     register_plugins2 (plugin, plugin_names, "/usr/local/lib32/frei0r-1");
697     register_plugins2 (plugin, plugin_names, "/usr/lib32/frei0r-1");
698     register_plugins2 (plugin, plugin_names, "/usr/local/lib64/frei0r-1");
699     register_plugins2 (plugin, plugin_names, "/usr/lib64/frei0r-1");
700 #undef register_plugins2
701   }
702 
703   g_hash_table_unref (plugin_names);
704 
705   return TRUE;
706 }
707 
708 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
709     GST_VERSION_MINOR,
710     frei0r,
711     "frei0r plugin library",
712     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
713