2 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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.
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.
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.
24 #include "gstfrei0r.h"
25 #include "gstfrei0rfilter.h"
26 #include "gstfrei0rsrc.h"
27 #include "gstfrei0rmixer.h"
32 GST_DEBUG_CATEGORY (frei0r_debug);
33 #define GST_CAT_DEFAULT frei0r_debug
35 static GstStaticCaps bgra8888_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
37 static GstStaticCaps rgba8888_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
39 static GstStaticCaps packed32_caps = GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
40 ("{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV }"));
43 gst_frei0r_caps_from_color_model (gint color_model)
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);
60 gst_frei0r_klass_install_properties (GObjectClass * gobject_class,
61 GstFrei0rFuncTable * ftable, GstFrei0rProperty * properties,
65 f0r_instance_t *instance = ftable->construct (640, 480);
69 for (i = 0; i < n_properties; i++) {
70 f0r_param_info_t *param_info = &properties[i].info;
73 ftable->get_param_info (param_info, i);
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)));
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;
88 prop_name = g_strconcat ("param-", prop_name, NULL);
92 properties[i].prop_id = count;
93 properties[i].prop_idx = i;
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);
100 switch (param_info->type) {
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 GST_PARAM_DOC_SHOW_DEFAULT));
108 properties[i].n_prop_ids = 1;
110 case F0R_PARAM_DOUBLE:{
111 gdouble def = properties[i].default_value.data.d;
113 /* If the default is NAN, +-INF we use 0.0 */
114 if (!(def >= 0.0 && def <= 1.0))
117 g_object_class_install_property (gobject_class, count++,
118 g_param_spec_double (prop_name, param_info->name,
119 param_info->explanation, 0.0, 1.0, def,
120 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
121 GST_PARAM_DOC_SHOW_DEFAULT));
122 properties[i].n_prop_ids = 1;
125 case F0R_PARAM_STRING:
126 g_object_class_install_property (gobject_class, count++,
127 g_param_spec_string (prop_name, param_info->name,
128 param_info->explanation, properties[i].default_value.data.s,
129 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
130 GST_PARAM_DOC_SHOW_DEFAULT));
131 properties[i].n_prop_ids = 1;
133 case F0R_PARAM_COLOR:{
134 gchar *prop_name_full;
135 gchar *prop_nick_full;
138 def = properties[i].default_value.data.color.r;
139 /* If the default is out of range we use 0.0 */
140 if (!(def <= 1.0 && def >= 0.0))
142 prop_name_full = g_strconcat (prop_name, "-r", NULL);
143 prop_nick_full = g_strconcat (param_info->name, " (R)", NULL);
144 g_object_class_install_property (gobject_class, count++,
145 g_param_spec_float (prop_name_full, prop_nick_full,
146 param_info->explanation, 0.0, 1.0, def,
147 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
148 GST_PARAM_DOC_SHOW_DEFAULT));
149 g_free (prop_name_full);
150 g_free (prop_nick_full);
152 def = properties[i].default_value.data.color.g;
153 /* If the default is out of range we use 0.0 */
154 if (!(def <= 1.0 && def >= 0.0))
156 prop_name_full = g_strconcat (prop_name, "-g", NULL);
157 prop_nick_full = g_strconcat (param_info->name, " (G)", NULL);
158 g_object_class_install_property (gobject_class, count++,
159 g_param_spec_float (prop_name_full, prop_nick_full,
160 param_info->explanation, 0.0, 1.0, def,
161 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
162 GST_PARAM_DOC_SHOW_DEFAULT));
163 g_free (prop_name_full);
164 g_free (prop_nick_full);
166 def = properties[i].default_value.data.color.b;
167 /* If the default is out of range we use 0.0 */
168 if (!(def <= 1.0 && def >= 0.0))
170 prop_name_full = g_strconcat (prop_name, "-b", NULL);
171 prop_nick_full = g_strconcat (param_info->name, " (B)", NULL);
172 g_object_class_install_property (gobject_class, count++,
173 g_param_spec_float (prop_name_full, prop_nick_full,
174 param_info->explanation, 0.0, 1.0, def,
175 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
176 GST_PARAM_DOC_SHOW_DEFAULT));
177 g_free (prop_name_full);
178 g_free (prop_nick_full);
180 properties[i].n_prop_ids = 3;
183 case F0R_PARAM_POSITION:{
184 gchar *prop_name_full;
185 gchar *prop_nick_full;
188 def = properties[i].default_value.data.position.x;
189 /* If the default is out of range we use 0.0 */
190 if (!(def <= 1.0 && def >= 0.0))
192 prop_name_full = g_strconcat (prop_name, "-x", NULL);
193 prop_nick_full = g_strconcat (param_info->name, " (X)", NULL);
194 g_object_class_install_property (gobject_class, count++,
195 g_param_spec_double (prop_name_full, prop_nick_full,
196 param_info->explanation, 0.0, 1.0, def,
197 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
198 GST_PARAM_DOC_SHOW_DEFAULT));
199 g_free (prop_name_full);
200 g_free (prop_nick_full);
202 def = properties[i].default_value.data.position.y;
203 /* If the default is out of range we use 0.0 */
204 if (!(def <= 1.0 && def >= 0.0))
206 prop_name_full = g_strconcat (prop_name, "-Y", NULL);
207 prop_nick_full = g_strconcat (param_info->name, " (Y)", NULL);
208 g_object_class_install_property (gobject_class, count++,
209 g_param_spec_double (prop_name_full, prop_nick_full,
210 param_info->explanation, 0.0, 1.0, def,
211 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
212 GST_PARAM_DOC_SHOW_DEFAULT));
213 g_free (prop_name_full);
214 g_free (prop_nick_full);
216 properties[i].n_prop_ids = 2;
220 g_assert_not_reached ();
227 ftable->destruct (instance);
230 GstFrei0rPropertyValue *
231 gst_frei0r_property_cache_init (GstFrei0rProperty * properties,
235 GstFrei0rPropertyValue *ret = g_new0 (GstFrei0rPropertyValue, n_properties);
237 for (i = 0; i < n_properties; i++) {
238 memcpy (&ret[i].data, &properties[i].default_value,
239 sizeof (GstFrei0rPropertyValue));
241 if (properties[i].info.type == F0R_PARAM_STRING)
242 ret[i].data.s = g_strdup (ret[i].data.s);
249 gst_frei0r_property_cache_free (GstFrei0rProperty * properties,
250 GstFrei0rPropertyValue * property_cache, gint n_properties)
254 for (i = 0; i < n_properties; i++) {
255 if (properties[i].info.type == F0R_PARAM_STRING)
256 g_free (property_cache[i].data.s);
258 g_free (property_cache);
262 gst_frei0r_instance_construct (GstFrei0rFuncTable * ftable,
263 GstFrei0rProperty * properties, gint n_properties,
264 GstFrei0rPropertyValue * property_cache, gint width, gint height)
266 f0r_instance_t *instance = ftable->construct (width, height);
269 for (i = 0; i < n_properties; i++)
270 ftable->set_param_value (instance, &property_cache[i].data, i);
276 gst_frei0r_get_property (f0r_instance_t * instance, GstFrei0rFuncTable * ftable,
277 GstFrei0rProperty * properties, gint n_properties,
278 GstFrei0rPropertyValue * property_cache, guint prop_id, GValue * value)
281 GstFrei0rProperty *prop = NULL;
283 for (i = 0; i < n_properties; i++) {
284 if (properties[i].prop_id <= prop_id &&
285 properties[i].prop_id + properties[i].n_prop_ids > prop_id) {
286 prop = &properties[i];
294 switch (prop->info.type) {
295 case F0R_PARAM_BOOL:{
299 ftable->get_param_value (instance, &d, prop->prop_idx);
301 d = property_cache[prop->prop_idx].data.b;
303 g_value_set_boolean (value, (d < 0.5) ? FALSE : TRUE);
306 case F0R_PARAM_DOUBLE:{
310 ftable->get_param_value (instance, &d, prop->prop_idx);
312 d = property_cache[prop->prop_idx].data.d;
314 g_value_set_double (value, d);
317 case F0R_PARAM_STRING:{
321 ftable->get_param_value (instance, &s, prop->prop_idx);
323 s = property_cache[prop->prop_idx].data.s;
324 g_value_set_string (value, s);
327 case F0R_PARAM_COLOR:{
328 f0r_param_color_t color;
331 ftable->get_param_value (instance, &color, prop->prop_idx);
333 color = property_cache[prop->prop_idx].data.color;
335 switch (prop_id - prop->prop_id) {
337 g_value_set_float (value, color.r);
340 g_value_set_float (value, color.g);
343 g_value_set_float (value, color.b);
348 case F0R_PARAM_POSITION:{
349 f0r_param_position_t position;
352 ftable->get_param_value (instance, &position, prop->prop_idx);
354 position = property_cache[prop->prop_idx].data.position;
356 switch (prop_id - prop->prop_id) {
358 g_value_set_double (value, position.x);
361 g_value_set_double (value, position.y);
367 g_assert_not_reached ();
375 gst_frei0r_set_property (f0r_instance_t * instance, GstFrei0rFuncTable * ftable,
376 GstFrei0rProperty * properties, gint n_properties,
377 GstFrei0rPropertyValue * property_cache, guint prop_id,
378 const GValue * value)
380 GstFrei0rProperty *prop = NULL;
383 for (i = 0; i < n_properties; i++) {
384 if (properties[i].prop_id <= prop_id &&
385 properties[i].prop_id + properties[i].n_prop_ids > prop_id) {
386 prop = &properties[i];
394 switch (prop->info.type) {
395 case F0R_PARAM_BOOL:{
396 gboolean b = g_value_get_boolean (value);
397 gdouble d = b ? 1.0 : 0.0;
400 ftable->set_param_value (instance, &d, prop->prop_idx);
401 property_cache[prop->prop_idx].data.b = d;
404 case F0R_PARAM_DOUBLE:{
405 gdouble d = g_value_get_double (value);
408 ftable->set_param_value (instance, &d, prop->prop_idx);
409 property_cache[prop->prop_idx].data.d = d;
412 case F0R_PARAM_STRING:{
413 gchar *s = g_value_dup_string (value);
415 /* Copies the string */
417 ftable->set_param_value (instance, s, prop->prop_idx);
418 property_cache[prop->prop_idx].data.s = s;
421 case F0R_PARAM_COLOR:{
422 gfloat f = g_value_get_float (value);
423 f0r_param_color_t *color = &property_cache[prop->prop_idx].data.color;
425 switch (prop_id - prop->prop_id) {
436 g_assert_not_reached ();
440 ftable->set_param_value (instance, color, prop->prop_idx);
443 case F0R_PARAM_POSITION:{
444 gdouble d = g_value_get_double (value);
445 f0r_param_position_t *position =
446 &property_cache[prop->prop_idx].data.position;
448 switch (prop_id - prop->prop_id) {
456 g_assert_not_reached ();
459 ftable->set_param_value (instance, position, prop->prop_idx);
463 g_assert_not_reached ();
471 register_plugin (GstPlugin * plugin, const gchar * vendor,
472 const gchar * filename)
475 GstFrei0rPluginRegisterReturn ret = GST_FREI0R_PLUGIN_REGISTER_RETURN_FAILED;
476 GstFrei0rFuncTable ftable = { NULL, };
478 f0r_plugin_info_t info = { NULL, };
479 f0r_instance_t *instance = NULL;
481 GST_DEBUG ("Registering plugin '%s'", filename);
483 module = g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
485 GST_WARNING ("Failed to load plugin");
489 if (!g_module_symbol (module, "f0r_init", (gpointer *) & ftable.init)) {
490 GST_INFO ("No frei0r plugin");
491 g_module_close (module);
495 if (!g_module_symbol (module, "f0r_deinit", (gpointer *) & ftable.deinit) ||
496 !g_module_symbol (module, "f0r_construct",
497 (gpointer *) & ftable.construct)
498 || !g_module_symbol (module, "f0r_destruct",
499 (gpointer *) & ftable.destruct)
500 || !g_module_symbol (module, "f0r_get_plugin_info",
501 (gpointer *) & ftable.get_plugin_info)
502 || !g_module_symbol (module, "f0r_get_param_info",
503 (gpointer *) & ftable.get_param_info)
504 || !g_module_symbol (module, "f0r_set_param_value",
505 (gpointer *) & ftable.set_param_value)
506 || !g_module_symbol (module, "f0r_get_param_value",
507 (gpointer *) & ftable.get_param_value))
508 goto invalid_frei0r_plugin;
510 /* One of these must exist */
511 g_module_symbol (module, "f0r_update", (gpointer *) & ftable.update);
512 g_module_symbol (module, "f0r_update2", (gpointer *) & ftable.update2);
514 if (!ftable.init ()) {
515 GST_WARNING ("Failed to initialize plugin");
516 g_module_close (module);
520 if (!ftable.update && !ftable.update2)
521 goto invalid_frei0r_plugin;
523 ftable.get_plugin_info (&info);
525 if (info.frei0r_version > 1) {
526 GST_WARNING ("Unsupported frei0r version %d", info.frei0r_version);
528 g_module_close (module);
532 if (info.color_model > F0R_COLOR_MODEL_PACKED32) {
533 GST_WARNING ("Unsupported color model %d", info.color_model);
535 g_module_close (module);
539 for (i = 0; i < info.num_params; i++) {
540 f0r_param_info_t pinfo = { NULL, };
542 ftable.get_param_info (&pinfo, i);
543 if (pinfo.type > F0R_PARAM_STRING) {
544 GST_WARNING ("Unsupported parameter type %d", pinfo.type);
546 g_module_close (module);
551 instance = ftable.construct (640, 480);
553 GST_WARNING ("Failed to instanciate plugin '%s'", info.name);
555 g_module_close (module);
558 ftable.destruct (instance);
560 switch (info.plugin_type) {
561 case F0R_PLUGIN_TYPE_FILTER:
562 ret = gst_frei0r_filter_register (plugin, vendor, &info, &ftable);
564 case F0R_PLUGIN_TYPE_SOURCE:
565 ret = gst_frei0r_src_register (plugin, vendor, &info, &ftable);
567 case F0R_PLUGIN_TYPE_MIXER2:
568 case F0R_PLUGIN_TYPE_MIXER3:
569 ret = gst_frei0r_mixer_register (plugin, vendor, &info, &ftable);
576 case GST_FREI0R_PLUGIN_REGISTER_RETURN_OK:
578 case GST_FREI0R_PLUGIN_REGISTER_RETURN_FAILED:
579 GST_ERROR ("Failed to register frei0r plugin");
581 g_module_close (module);
583 case GST_FREI0R_PLUGIN_REGISTER_RETURN_ALREADY_REGISTERED:
584 GST_DEBUG ("frei0r plugin already registered");
586 g_module_close (module);
589 g_return_val_if_reached (FALSE);
592 g_return_val_if_reached (FALSE);
594 invalid_frei0r_plugin:
595 GST_ERROR ("Invalid frei0r plugin");
597 g_module_close (module);
603 register_plugins (GstPlugin * plugin, GHashTable * plugin_names,
604 const gchar * path, const gchar * base_path)
608 const gchar *entry_name;
611 GST_DEBUG ("Scanning directory '%s' for frei0r plugins", path);
613 dir = g_dir_open (path, 0, NULL);
617 while ((entry_name = g_dir_read_name (dir))) {
618 gchar *tmp, *vendor = NULL;
619 gchar *hashtable_name;
621 tmp = g_strdup (path + strlen (base_path));
622 if (*tmp == G_DIR_SEPARATOR && *(tmp + 1))
628 hashtable_name = g_strconcat (vendor, "-", entry_name, NULL);
630 hashtable_name = g_strdup (entry_name);
632 if (g_hash_table_lookup_extended (plugin_names, hashtable_name, NULL, NULL)) {
633 g_free (hashtable_name);
637 filename = g_build_filename (path, entry_name, NULL);
638 if ((g_str_has_suffix (filename, G_MODULE_SUFFIX)
639 #ifdef GST_EXTRA_MODULE_SUFFIX
640 || g_str_has_suffix (filename, GST_EXTRA_MODULE_SUFFIX)
642 ) && g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
645 this_ret = register_plugin (plugin, vendor, filename);
647 g_hash_table_insert (plugin_names, g_strdup (hashtable_name), NULL);
649 ret = ret && this_ret;
650 } else if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
651 ret = ret && register_plugins (plugin, plugin_names, filename, base_path);
654 g_free (hashtable_name);
663 plugin_init (GstPlugin * plugin)
665 const gchar *homedir;
666 gchar *path, *libdir_path;
667 GHashTable *plugin_names;
668 const gchar *frei0r_path;
670 GST_DEBUG_CATEGORY_INIT (frei0r_debug, "frei0r", 0, "frei0r");
672 gst_plugin_add_dependency_simple (plugin,
673 "FREI0R_PATH:HOME/.frei0r-1/lib",
675 "/usr/lib/frei0r-1:/usr/local/lib/frei0r-1:"
676 "/usr/lib32/frei0r-1:/usr/local/lib32/frei0r-1:"
677 "/usr/lib64/frei0r-1:/usr/local/lib64/frei0r-1",
678 NULL, GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
681 g_hash_table_new_full ((GHashFunc) g_str_hash, (GEqualFunc) g_str_equal,
682 (GDestroyNotify) g_free, NULL);
684 frei0r_path = g_getenv ("FREI0R_PATH");
685 if (frei0r_path && *frei0r_path) {
686 gchar **p, **paths = g_strsplit (frei0r_path, ":", -1);
688 for (p = paths; *p; p++) {
689 register_plugins (plugin, plugin_names, *p, *p);
694 #define register_plugins2(plugin, pn, p) register_plugins(plugin, pn, p, p)
695 homedir = g_get_home_dir ();
696 path = g_build_filename (homedir, ".frei0r-1", "lib", NULL);
697 libdir_path = g_build_filename (LIBDIR, "frei0r-1", NULL);
698 register_plugins2 (plugin, plugin_names, path);
700 register_plugins2 (plugin, plugin_names, libdir_path);
701 g_free (libdir_path);
702 register_plugins2 (plugin, plugin_names, "/usr/local/lib/frei0r-1");
703 register_plugins2 (plugin, plugin_names, "/usr/lib/frei0r-1");
704 register_plugins2 (plugin, plugin_names, "/usr/local/lib32/frei0r-1");
705 register_plugins2 (plugin, plugin_names, "/usr/lib32/frei0r-1");
706 register_plugins2 (plugin, plugin_names, "/usr/local/lib64/frei0r-1");
707 register_plugins2 (plugin, plugin_names, "/usr/lib64/frei0r-1");
708 #undef register_plugins2
711 g_hash_table_unref (plugin_names);
716 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
719 "frei0r plugin library",
720 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)