/* GStreamer * Copyright (C) 2006 Stefan Kost * * gstpreset.c: helper interface for element presets * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:gstpreset * @short_description: helper interface for element presets * * This interface offers methods to query and manipulate parameter preset sets. * A preset is a bunch of property settings, together with meta data and a name. * The name of a preset serves as key for subsequent method calls to manipulate * single presets. * All instances of one type will share the list of presets. The list is created * on demand, if presets are not used, the list is not created. * */ /* @todo: * - we need locks to avoid two instances manipulating the preset list -> flock * - need to add support for GstChildProxy * - how can we support both Preferences and Presets, * - preferences = static settings (non controlable) * - preset = a snapshot of dynamic params * - flag * - we could save all, but have a flag when loading * - we could use a flag for _get_preset_names() * * - should there be a 'preset-list' property to get the preset list * (and to connect a notify:: to to listen for changes) * - should there be a 'preset-name' property so that we can set a preset via * gst-launch * * - do we want to ship presets for some elements? */ #include "gst_private.h" #include "gstpreset.h" #include "stdlib.h" #include #include #define GST_CAT_DEFAULT preset_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); static GQuark preset_list_quark = 0; static GQuark preset_path_quark = 0; static GQuark preset_data_quark = 0; static GQuark preset_meta_quark = 0; static GQuark instance_list_quark = 0; /* default iface implementation */ /* max character per line */ #define LINE_LEN 200 static gboolean preset_get_storage (GstPreset * self, GList ** presets, GHashTable ** preset_meta, GHashTable ** preset_data) { gboolean res = FALSE; GType type = G_TYPE_FROM_INSTANCE (self); g_assert (presets); if ((*presets = g_type_get_qdata (type, preset_list_quark))) { GST_DEBUG ("have presets"); res = TRUE; } if (preset_meta) { if (!(*preset_meta = g_type_get_qdata (type, preset_meta_quark))) { *preset_meta = g_hash_table_new (g_str_hash, g_str_equal); g_type_set_qdata (type, preset_meta_quark, (gpointer) * preset_meta); GST_DEBUG ("new meta hash"); } } if (preset_data) { if (!(*preset_data = g_type_get_qdata (type, preset_data_quark))) { *preset_data = g_hash_table_new (g_str_hash, g_str_equal); g_type_set_qdata (type, preset_data_quark, (gpointer) * preset_data); GST_DEBUG ("new data hash"); } } GST_INFO ("%ld:%s: presets: %p, %p, %p", type, G_OBJECT_TYPE_NAME (self), *presets, (preset_meta ? *preset_meta : 0), (preset_data ? *preset_data : 0)); return (res); } static const gchar * preset_get_path (GstPreset * self) { GType type = G_TYPE_FROM_INSTANCE (self); gchar *preset_path; preset_path = (gchar *) g_type_get_qdata (type, preset_path_quark); if (!preset_path) { const gchar *element_name, *plugin_name, *file_name; gchar *preset_dir; GstElementFactory *factory; GstPlugin *plugin; element_name = G_OBJECT_TYPE_NAME (self); GST_INFO ("element_name: '%s'", element_name); factory = GST_ELEMENT_GET_CLASS (self)->elementfactory; GST_INFO ("factory: %p", factory); if (factory) { plugin_name = GST_PLUGIN_FEATURE (factory)->plugin_name; GST_INFO ("plugin_name: '%s'", plugin_name); plugin = gst_default_registry_find_plugin (plugin_name); GST_INFO ("plugin: %p", plugin); file_name = gst_plugin_get_filename (plugin); GST_INFO ("file_name: '%s'", file_name); /* '/home/ensonic/buzztard/lib/gstreamer-0.10/libgstsimsyn.so' -> '/home/ensonic/buzztard/share/gstreamer-0.10/GstSimSyn.xml' -> '$HOME/.gstreamer-0.10/presets/GstSimSyn.xml' '/usr/lib/gstreamer-0.10/libgstaudiofx.so' -> '/usr/share/gstreamer-0.10/GstAudioPanorama.xml' -> '$HOME/.gstreamer-0.10/presets/GstAudioPanorama.xml' */ } preset_dir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10", "presets", NULL); GST_INFO ("preset_dir: '%s'", preset_dir); preset_path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s.prs", preset_dir, element_name); GST_INFO ("preset_path: '%s'", preset_path); g_mkdir_with_parents (preset_dir, 0755); g_free (preset_dir); /* attach the preset path to the type */ g_type_set_qdata (type, preset_path_quark, (gpointer) preset_path); } return (preset_path); } static void preset_cleanup (gpointer user_data, GObject * self) { GType type = (GType) user_data; GList *instances; /* remove instance from instance list (if not yet there) */ instances = (GList *) g_type_get_qdata (type, instance_list_quark); if (instances != NULL) { instances = g_list_remove (instances, self); GST_INFO ("old instanc removed"); g_type_set_qdata (type, instance_list_quark, (gpointer) instances); } } static GList * gst_preset_default_get_preset_names (GstPreset * self) { GType type = G_TYPE_FROM_INSTANCE (self); GList *presets; GList *instances; GHashTable *preset_meta, *preset_data; gboolean found = FALSE; /* get the presets from the type */ if (!preset_get_storage (self, &presets, &preset_meta, &preset_data)) { const gchar *preset_path = preset_get_path (self); FILE *in; GST_DEBUG ("probing preset file: '%s'", preset_path); /* read presets */ if ((in = fopen (preset_path, "rb"))) { const gchar *element_name = G_OBJECT_TYPE_NAME (self); gchar line[LINE_LEN + 1], *str, *val; gboolean parse_preset; gchar *preset_name; GHashTable *meta; GHashTable *data; GObjectClass *klass; GParamSpec *property; GST_DEBUG ("loading preset file: '%s'", preset_path); /* read header */ if (!fgets (line, LINE_LEN, in)) goto eof_error; if (strcmp (line, "GStreamer Preset\n")) { GST_WARNING ("%s:1: file id expected", preset_path); goto eof_error; } if (!fgets (line, LINE_LEN, in)) goto eof_error; /* @todo: what version (core?) */ if (!fgets (line, LINE_LEN, in)) goto eof_error; if (strcmp (g_strchomp (line), element_name)) { GST_WARNING ("%s:3: wrong element name", preset_path); goto eof_error; } if (!fgets (line, LINE_LEN, in)) goto eof_error; if (*line != '\n') { GST_WARNING ("%s:4: blank line expected", preset_path); goto eof_error; } klass = G_OBJECT_CLASS (GST_ELEMENT_GET_CLASS (self)); /* read preset entries */ while (!feof (in)) { /* read preset entry */ fgets (line, LINE_LEN, in); g_strchomp (line); if (*line) { preset_name = g_strdup (line); GST_INFO ("%s: preset '%s'", preset_path, preset_name); data = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); meta = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* read preset lines */ parse_preset = TRUE; while (parse_preset) { fgets (line, LINE_LEN, in); if (feof (in) || (*line == '\n')) { GST_DEBUG ("preset done"); parse_preset = FALSE; break; } str = g_strchomp (line); while (*str) { if (*str == ':') { *str = '\0'; GST_DEBUG ("meta[%s]='%s'", line, &str[1]); if ((val = g_hash_table_lookup (meta, line))) { g_free (val); g_hash_table_insert (meta, (gpointer) line, (gpointer) g_strdup (&str[1])); } else { g_hash_table_insert (meta, (gpointer) g_strdup (line), (gpointer) g_strdup (&str[1])); } break; } else if (*str == '=') { *str = '\0'; GST_DEBUG ("data[%s]='%s'", line, &str[1]); if ((property = g_object_class_find_property (klass, line))) { g_hash_table_insert (data, (gpointer) property->name, (gpointer) g_strdup (&str[1])); } else { GST_WARNING ("%s: Invalid property '%s'", preset_path, line); } break; } str++; } /* @todo: handle childproxy properties * [child]= */ } GST_INFO ("preset: %p, %p", meta, data); g_hash_table_insert (preset_data, (gpointer) preset_name, (gpointer) data); g_hash_table_insert (preset_meta, (gpointer) preset_name, (gpointer) meta); presets = g_list_insert_sorted (presets, (gpointer) preset_name, (GCompareFunc) strcmp); } } eof_error: fclose (in); } else { GST_INFO ("can't open preset file: '%s'", preset_path); } /* attach the preset to the type */ g_type_set_qdata (type, preset_list_quark, (gpointer) presets); } /* insert instance in instance list (if not yet there) */ instances = (GList *) g_type_get_qdata (type, instance_list_quark); if (instances != NULL) { if (g_list_find (instances, self)) found = TRUE; } if (!found) { GST_INFO ("new instance added"); /* register a weak ref, to clean up when the object gets destroyed */ g_object_weak_ref (G_OBJECT (self), preset_cleanup, (gpointer) type); instances = g_list_prepend (instances, self); g_type_set_qdata (type, instance_list_quark, (gpointer) instances); } return (presets); } static gboolean gst_preset_default_load_preset (GstPreset * self, const gchar * name) { GList *presets; GHashTable *preset_data; /* get the presets from the type */ if (preset_get_storage (self, &presets, NULL, &preset_data)) { GList *node; if ((node = g_list_find_custom (presets, name, (GCompareFunc) strcmp))) { GHashTable *data = g_hash_table_lookup (preset_data, node->data); GParamSpec **properties, *property; GType base, parent; guint i, number_of_properties; gchar *val = NULL; GST_DEBUG ("loading preset : '%s', data : %p (size=%d)", name, data, g_hash_table_size (data)); /* preset found, now set values */ if ((properties = g_object_class_list_properties (G_OBJECT_CLASS (GST_ELEMENT_GET_CLASS (self)), &number_of_properties))) { for (i = 0; i < number_of_properties; i++) { property = properties[i]; /* skip non-controlable */ if (!(property->flags & GST_PARAM_CONTROLLABLE)) continue; /* check if we have a settings for this property */ if ((val = (gchar *) g_hash_table_lookup (data, property->name))) { GST_DEBUG ("setting value '%s' for property '%s'", val, property->name); /* get base type */ base = property->value_type; while ((parent = g_type_parent (base))) { base = parent; } switch (base) { case G_TYPE_INT: case G_TYPE_UINT: case G_TYPE_BOOLEAN: case G_TYPE_ENUM: g_object_set (G_OBJECT (self), property->name, atoi (val), NULL); break; case G_TYPE_LONG: case G_TYPE_ULONG: g_object_set (G_OBJECT (self), property->name, atol (val), NULL); break; case G_TYPE_FLOAT: g_object_set (G_OBJECT (self), property->name, (float) g_ascii_strtod (val, NULL), NULL); break; case G_TYPE_DOUBLE: g_object_set (G_OBJECT (self), property->name, g_ascii_strtod (val, NULL), NULL); break; case G_TYPE_STRING: g_object_set (G_OBJECT (self), property->name, val, NULL); break; default: GST_WARNING ("incomplete implementation for GParamSpec type '%s'", G_PARAM_SPEC_TYPE_NAME (property)); } } else { GST_INFO ("parameter '%s' not in preset", property->name); } } return (TRUE); } } } else { GST_INFO ("no presets"); } return (FALSE); } static void preset_store_meta (gpointer key, gpointer value, gpointer user_data) { if (key && value) { fprintf ((FILE *) user_data, "%s:%s\n", (gchar *) key, (gchar *) value); } } static void preset_store_data (gpointer key, gpointer value, gpointer user_data) { if (key && value) { fprintf ((FILE *) user_data, "%s=%s\n", (gchar *) key, (gchar *) value); } } static gboolean gst_preset_default_save_presets_file (GstPreset * self) { gboolean res = FALSE; GList *presets; GHashTable *preset_meta, *preset_data; const gchar *preset_path = preset_get_path (self); /* get the presets from the type */ if (preset_get_storage (self, &presets, &preset_meta, &preset_data)) { FILE *out; gchar *bak_file_name; gboolean backup = TRUE; GST_DEBUG ("saving preset file: '%s'", preset_path); /* create backup if possible */ bak_file_name = g_strdup_printf ("%s.bak", preset_path); if (g_file_test (bak_file_name, G_FILE_TEST_EXISTS)) { if (g_unlink (bak_file_name)) { backup = FALSE; GST_INFO ("cannot remove old backup file : %s", bak_file_name); } } if (backup) { if (g_rename (preset_path, bak_file_name)) { GST_INFO ("cannot backup file : %s -> %s", preset_path, bak_file_name); } } g_free (bak_file_name); /* write presets */ if ((out = fopen (preset_path, "wb"))) { const gchar *element_name = G_OBJECT_TYPE_NAME (self); gchar *preset_name; GList *node; GHashTable *meta, *data; /* write header */ if (!(fputs ("GStreamer Preset\n", out))) goto eof_error; /* @todo: what version (core?) */ if (!(fputs ("1.0\n", out))) goto eof_error; if (!(fputs (element_name, out))) goto eof_error; if (!(fputs ("\n\n", out))) goto eof_error; /* write preset entries */ for (node = presets; node; node = g_list_next (node)) { preset_name = node->data; /* write preset entry */ if (!(fputs (preset_name, out))) goto eof_error; if (!(fputs ("\n", out))) goto eof_error; /* write data */ meta = g_hash_table_lookup (preset_meta, (gpointer) preset_name); g_hash_table_foreach (meta, preset_store_meta, out); data = g_hash_table_lookup (preset_data, (gpointer) preset_name); g_hash_table_foreach (data, preset_store_data, out); if (!(fputs ("\n", out))) goto eof_error; } res = TRUE; eof_error: fclose (out); } } else { GST_DEBUG ("no presets, trying to unlink possibly existing preset file: '%s'", preset_path); unlink (preset_path); } return (res); } static gboolean gst_preset_default_save_preset (GstPreset * self, const gchar * name) { GType type = G_TYPE_FROM_INSTANCE (self); GList *presets; GHashTable *preset_meta, *preset_data; GHashTable *meta, *data; GParamSpec **properties, *property; GType base, parent; guint i, number_of_properties; gchar *str = NULL, buffer[30 + 1]; /*guint flags; */ GST_INFO ("saving new preset: %s", name); /* get the presets from the type */ preset_get_storage (self, &presets, &preset_meta, &preset_data); data = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); meta = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* take copies of current gobject properties from self */ if ((properties = g_object_class_list_properties (G_OBJECT_CLASS (GST_ELEMENT_GET_CLASS (self)), &number_of_properties))) { for (i = 0; i < number_of_properties; i++) { property = properties[i]; /*flags=GPOINTER_TO_INT(g_param_spec_get_qdata(property,gst_property_meta_quark_flags)); */ /* skip non-controlable */ if (!(property->flags & GST_PARAM_CONTROLLABLE)) continue; /* get base type */ base = property->value_type; while ((parent = g_type_parent (base))) { base = parent; } /* get value and serialize */ GST_INFO (" storing property: %s (type is %s)", property->name, g_type_name (base)); switch (base) { case G_TYPE_BOOLEAN: case G_TYPE_ENUM: case G_TYPE_INT:{ gint val; g_object_get (G_OBJECT (self), property->name, &val, NULL); str = g_strdup_printf ("%d", val); } break; case G_TYPE_UINT:{ guint val; g_object_get (G_OBJECT (self), property->name, &val, NULL); str = g_strdup_printf ("%u", val); } break; case G_TYPE_LONG:{ glong val; g_object_get (G_OBJECT (self), property->name, &val, NULL); str = g_strdup_printf ("%ld", val); } break; case G_TYPE_ULONG:{ gulong val; g_object_get (G_OBJECT (self), property->name, &val, NULL); str = g_strdup_printf ("%lu", val); } break; case G_TYPE_FLOAT:{ gfloat val; g_object_get (G_OBJECT (self), property->name, &val, NULL); g_ascii_dtostr (buffer, 30, (gdouble) val); str = g_strdup (buffer); } break; case G_TYPE_DOUBLE:{ gdouble val; g_object_get (G_OBJECT (self), property->name, &val, NULL); g_ascii_dtostr (buffer, 30, val); str = g_strdup (buffer); } break; case G_TYPE_STRING: g_object_get (G_OBJECT (self), property->name, &str, NULL); if (str && !*str) str = NULL; break; default: GST_WARNING ("incomplete implementation for GParamSpec type '%s'", G_PARAM_SPEC_TYPE_NAME (property)); } if (str) { g_hash_table_insert (data, (gpointer) property->name, (gpointer) str); str = NULL; } } GST_INFO (" saved"); } /* * flock(fileno()) * http://www.ecst.csuchico.edu/~beej/guide/ipc/flock.html */ g_hash_table_insert (preset_data, (gpointer) name, (gpointer) data); g_hash_table_insert (preset_meta, (gpointer) name, (gpointer) meta); presets = g_list_insert_sorted (presets, (gpointer) name, (GCompareFunc) strcmp); /* attach the preset list to the type */ g_type_set_qdata (type, preset_list_quark, (gpointer) presets); GST_INFO ("done"); return (gst_preset_default_save_presets_file (self)); } static gboolean gst_preset_default_rename_preset (GstPreset * self, const gchar * old_name, const gchar * new_name) { GType type = G_TYPE_FROM_INSTANCE (self); GList *presets; GHashTable *preset_meta, *preset_data; /* get the presets from the type */ if (preset_get_storage (self, &presets, &preset_meta, &preset_data)) { GList *node; if ((node = g_list_find_custom (presets, old_name, (GCompareFunc) strcmp))) { GHashTable *meta, *data; /* readd under new name */ presets = g_list_insert_sorted (presets, (gpointer) new_name, (GCompareFunc) strcmp); /* readd the hash entries */ if ((meta = g_hash_table_lookup (preset_meta, node->data))) { g_hash_table_remove (preset_meta, node->data); g_hash_table_insert (preset_meta, (gpointer) new_name, (gpointer) meta); } if ((data = g_hash_table_lookup (preset_data, node->data))) { g_hash_table_remove (preset_data, node->data); g_hash_table_insert (preset_data, (gpointer) new_name, (gpointer) data); } /* remove the old one */ presets = g_list_delete_link (presets, node); GST_INFO ("preset moved '%s' -> '%s'", old_name, new_name); g_type_set_qdata (type, preset_list_quark, (gpointer) presets); return (gst_preset_default_save_presets_file (self)); } } else { GST_WARNING ("no presets"); } return (FALSE); } static gboolean gst_preset_default_delete_preset (GstPreset * self, const gchar * name) { GType type = G_TYPE_FROM_INSTANCE (self); GList *presets; GHashTable *preset_meta, *preset_data; /* get the presets from the type */ if (preset_get_storage (self, &presets, &preset_meta, &preset_data)) { GList *node; if ((node = g_list_find_custom (presets, name, (GCompareFunc) strcmp))) { GHashTable *meta, *data; /* free the hash entries */ if ((meta = g_hash_table_lookup (preset_meta, node->data))) { g_hash_table_remove (preset_meta, node->data); g_hash_table_destroy (meta); } if ((data = g_hash_table_lookup (preset_data, node->data))) { g_hash_table_remove (preset_data, node->data); g_hash_table_destroy (data); } /* remove the found one */ presets = g_list_delete_link (presets, node); GST_INFO ("preset removed '%s'", name); g_type_set_qdata (type, preset_list_quark, (gpointer) presets); g_free ((gpointer) name); return (gst_preset_default_save_presets_file (self)); } } else { GST_WARNING ("no presets"); } return (FALSE); } static gboolean gst_preset_default_set_meta (GstPreset * self, const gchar * name, const gchar * tag, gchar * value) { gboolean res = FALSE; GList *presets; GHashTable *preset_meta; /* get the presets from the type */ if (preset_get_storage (self, &presets, &preset_meta, NULL)) { GList *node; if ((node = g_list_find_custom (presets, name, (GCompareFunc) strcmp))) { GHashTable *meta = g_hash_table_lookup (preset_meta, node->data); gchar *old_value; gboolean changed = FALSE; if ((old_value = g_hash_table_lookup (meta, tag))) { g_free (old_value); changed = TRUE; } if (value) { if (changed) tag = g_strdup (tag); g_hash_table_insert (meta, (gpointer) tag, g_strdup (value)); changed = TRUE; } if (changed) { res = gst_preset_default_save_presets_file (self); } } } else { GST_WARNING ("no presets"); } return (res); } static gboolean gst_preset_default_get_meta (GstPreset * self, const gchar * name, const gchar * tag, gchar ** value) { gboolean res = FALSE; GList *presets; GHashTable *preset_meta; /* get the presets from the type */ if (preset_get_storage (self, &presets, &preset_meta, NULL)) { GList *node; if ((node = g_list_find_custom (presets, name, (GCompareFunc) strcmp))) { GHashTable *meta = g_hash_table_lookup (preset_meta, node->data); gchar *new_value; if ((new_value = g_hash_table_lookup (meta, tag))) { *value = g_strdup (new_value); res = TRUE; } } } else { GST_WARNING ("no presets"); } if (!res) *value = NULL; return (res); } static void gst_preset_default_create_preset (GstPreset * self) { GParamSpec **properties, *property; guint i, number_of_properties; GType param_type, base_type; if ((properties = g_object_class_list_properties (G_OBJECT_CLASS (GST_OBJECT_GET_CLASS (self)), &number_of_properties))) { gdouble rnd; GST_INFO ("nr of values : %d", number_of_properties); for (i = 0; i < number_of_properties; i++) { property = properties[i]; /* skip non-controlable, and non persistent params */ if (!(property->flags & GST_PARAM_CONTROLLABLE)) continue; /* we do not want to create a setting for trigger properties, buzztard has more flags attached to g_param_specs else { guint flags=0; if(BT_IS_PROPERTY_META(self)) { flags=GPOINTER_TO_INT(g_param_spec_get_qdata(property,bt_property_meta_quark_flags)); } if(!(flags&BT_PROPERTY_META_STATE)) continue; } */ GST_INFO ("property '%s' (GType=%d)", property->name, property->value_type); param_type = property->value_type; while ((base_type = g_type_parent (param_type))) param_type = base_type; rnd = ((gdouble) rand ()) / (RAND_MAX + 1.0); switch (param_type) { case G_TYPE_BOOLEAN:{ g_object_set (self, property->name, (gboolean) (2.0 * rnd), NULL); } break; case G_TYPE_INT:{ const GParamSpecInt *int_property = G_PARAM_SPEC_INT (property); g_object_set (self, property->name, (gint) (int_property->minimum + ((int_property->maximum - int_property->minimum) * rnd)), NULL); } break; case G_TYPE_UINT:{ const GParamSpecUInt *uint_property = G_PARAM_SPEC_UINT (property); g_object_set (self, property->name, (guint) (uint_property->minimum + ((uint_property->maximum - uint_property->minimum) * rnd)), NULL); } break; case G_TYPE_DOUBLE:{ const GParamSpecDouble *double_property = G_PARAM_SPEC_DOUBLE (property); g_object_set (self, property->name, (gdouble) (double_property->minimum + ((double_property->maximum - double_property->minimum) * rnd)), NULL); } break; case G_TYPE_ENUM:{ const GParamSpecEnum *enum_property = G_PARAM_SPEC_ENUM (property); const GEnumClass *enum_class = enum_property->enum_class; g_object_set (self, property->name, (gulong) (enum_class->minimum + ((enum_class->maximum - enum_class->minimum) * rnd)), NULL); } break; default: GST_WARNING ("unhandled GType=%d", param_type); } } /* @todo: handle childproxy properties as well */ } } /* wrapper */ /** * gst_preset_get_preset_names: * @self: a #GObject that implements #GstPreset * * Get a copy of the preset list names. Free list when done. * * Returns: list with names */ GList * gst_preset_get_preset_names (GstPreset * self) { g_return_val_if_fail (GST_IS_PRESET (self), NULL); return (GST_PRESET_GET_INTERFACE (self)->get_preset_names (self)); } /** * gst_preset_load_preset: * @self: a #GObject that implements #GstPreset * @name: preset name to load * * Load the given preset. * * Returns: %TRUE for success, %FALSE if e.g. there is no preset with that @name */ gboolean gst_preset_load_preset (GstPreset * self, const gchar * name) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (name, FALSE); return (GST_PRESET_GET_INTERFACE (self)->load_preset (self, name)); } /** * gst_preset_save_preset: * @self: a #GObject that implements #GstPreset * @name: preset name to save * * Save the current preset under the given name. If there is already a preset by * this @name it will be overwritten. * * Returns: %TRUE for success, %FALSE */ gboolean gst_preset_save_preset (GstPreset * self, const gchar * name) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (name, FALSE); return (GST_PRESET_GET_INTERFACE (self)->save_preset (self, name)); } /** * gst_preset_rename_preset: * @self: a #GObject that implements #GstPreset * @old_name: current preset name * @new_name: new preset name * * Renames a preset. If there is already a preset by thr @new_name it will be * overwritten. * * Returns: %TRUE for success, %FALSE if e.g. there is no preset with @old_name */ gboolean gst_preset_rename_preset (GstPreset * self, const gchar * old_name, const gchar * new_name) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (old_name, FALSE); g_return_val_if_fail (new_name, FALSE); return (GST_PRESET_GET_INTERFACE (self)->rename_preset (self, old_name, new_name)); } /** * gst_preset_delete_preset: * @self: a #GObject that implements #GstPreset * @name: preset name to remove * * Delete the given preset. * * Returns: %TRUE for success, %FALSE if e.g. there is no preset with that @name */ gboolean gst_preset_delete_preset (GstPreset * self, const gchar * name) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (name, FALSE); return (GST_PRESET_GET_INTERFACE (self)->delete_preset (self, name)); } /** * gst_preset_set_meta: * @self: a #GObject that implements #GstPreset * @name: preset name * @tag: meta data item name * @value: new value * * Sets a new @value for an existing meta data item or adds a new item. Meta * data @tag names can be something like e.g. "comment". Supplying %NULL for the * @value will unset an existing value. * * Returns: %TRUE for success, %FALSE if e.g. there is no preset with that @name */ gboolean gst_preset_set_meta (GstPreset * self, const gchar * name, const gchar * tag, gchar * value) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (name, FALSE); g_return_val_if_fail (tag, FALSE); return GST_PRESET_GET_INTERFACE (self)->set_meta (self, name, tag, value); } /** * gst_preset_get_meta: * @self: a #GObject that implements #GstPreset * @name: preset name * @tag: meta data item name * @value: value * * Gets the @value for an existing meta data @tag. Meta data @tag names can be * something like e.g. "comment". Returned values need to be released when done. * * Returns: %TRUE for success, %FALSE if e.g. there is no preset with that @name * or no value for the given @tag */ gboolean gst_preset_get_meta (GstPreset * self, const gchar * name, const gchar * tag, gchar ** value) { g_return_val_if_fail (GST_IS_PRESET (self), FALSE); g_return_val_if_fail (name, FALSE); g_return_val_if_fail (tag, FALSE); g_return_val_if_fail (value, FALSE); return GST_PRESET_GET_INTERFACE (self)->get_meta (self, name, tag, value); } /** * gst_preset_create_preset: * @self: a #GObject that implements #GstPreset * * Create a new randomized preset. This method is optional. If not implemented * true randomization will be applied. */ void gst_preset_create_preset (GstPreset * self) { g_return_if_fail (GST_IS_PRESET (self)); GST_PRESET_GET_INTERFACE (self)->create_preset (self); } /* class internals */ static void gst_preset_class_init (GstPresetInterface * iface) { iface->get_preset_names = gst_preset_default_get_preset_names; iface->load_preset = gst_preset_default_load_preset; iface->save_preset = gst_preset_default_save_preset; iface->rename_preset = gst_preset_default_rename_preset; iface->delete_preset = gst_preset_default_delete_preset; iface->set_meta = gst_preset_default_set_meta; iface->get_meta = gst_preset_default_get_meta; iface->create_preset = gst_preset_default_create_preset; } static void gst_preset_base_init (gpointer g_class) { static gboolean initialized = FALSE; if (!initialized) { /* init default implementation */ GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "preset", GST_DEBUG_FG_WHITE | GST_DEBUG_BG_BLACK, "preset interface"); /* create quarks for use with g_type_{g,s}et_qdata() */ preset_list_quark = g_quark_from_string ("GstPreset::presets"); preset_path_quark = g_quark_from_string ("GstPreset::path"); preset_data_quark = g_quark_from_string ("GstPreset::data"); preset_meta_quark = g_quark_from_string ("GstPreset::meta"); instance_list_quark = g_quark_from_string ("GstPreset::instances"); initialized = TRUE; } } GType gst_preset_get_type (void) { static GType type = 0; if (type == 0) { const GTypeInfo info = { sizeof (GstPresetInterface), (GBaseInitFunc) gst_preset_base_init, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) gst_preset_class_init, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ 0, 0, /* n_preallocs */ NULL /* instance_init */ }; type = g_type_register_static (G_TYPE_INTERFACE, "GstPreset", &info, 0); } return type; }