mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-07-02 04:35:55 +00:00
preset: allow applications to specify an extra preset dir
An extra application preset dir help to organize presets created for special purposes. Fixes #660760 API: gst_preset_set_app_dir(), gst_preset_get_app_dir()
This commit is contained in:
parent
a6bb6d0fc3
commit
f2b5b79eeb
|
@ -1999,6 +1999,8 @@ gst_preset_rename_preset
|
||||||
gst_preset_delete_preset
|
gst_preset_delete_preset
|
||||||
gst_preset_set_meta
|
gst_preset_set_meta
|
||||||
gst_preset_get_meta
|
gst_preset_get_meta
|
||||||
|
gst_preset_set_app_dir
|
||||||
|
gst_preset_get_app_dir
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GST_PRESET
|
GST_PRESET
|
||||||
GST_IS_PRESET
|
GST_IS_PRESET
|
||||||
|
|
198
gst/gstpreset.c
198
gst/gstpreset.c
|
@ -34,6 +34,13 @@
|
||||||
* native preset format of those wrapped plugins.
|
* native preset format of those wrapped plugins.
|
||||||
* One method that is useful to be overridden is gst_preset_get_property_names().
|
* One method that is useful to be overridden is gst_preset_get_property_names().
|
||||||
* With that one can control which properties are saved and in which order.
|
* With that one can control which properties are saved and in which order.
|
||||||
|
*
|
||||||
|
* The default implementation supports presets located in a system directory,
|
||||||
|
* application specific directory and in the users home directory. When getting
|
||||||
|
* a list of presets individual presets are read and overlaid in 1) system,
|
||||||
|
* 2) application and 3) user order. Whenever an earlier entry is newer, the
|
||||||
|
* later entries will be updated.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
/* FIXME:
|
/* FIXME:
|
||||||
* - non racyness
|
* - non racyness
|
||||||
|
@ -106,11 +113,18 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||||
#define PRESET_HEADER_VERSION "version"
|
#define PRESET_HEADER_VERSION "version"
|
||||||
|
|
||||||
static GQuark preset_user_path_quark = 0;
|
static GQuark preset_user_path_quark = 0;
|
||||||
|
static GQuark preset_app_path_quark = 0;
|
||||||
static GQuark preset_system_path_quark = 0;
|
static GQuark preset_system_path_quark = 0;
|
||||||
static GQuark preset_quark = 0;
|
static GQuark preset_quark = 0;
|
||||||
|
|
||||||
/*static GQuark property_list_quark = 0;*/
|
/*static GQuark property_list_quark = 0;*/
|
||||||
|
|
||||||
|
/* the application can set a custom path that is checked in addition to standart
|
||||||
|
* system and user dirs. This helps to develop new presets first local to the
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
static gchar *preset_app_dir = NULL;
|
||||||
|
|
||||||
/* default iface implementation */
|
/* default iface implementation */
|
||||||
|
|
||||||
static gboolean gst_preset_default_save_presets_file (GstPreset * preset);
|
static gboolean gst_preset_default_save_presets_file (GstPreset * preset);
|
||||||
|
@ -119,16 +133,17 @@ static gboolean gst_preset_default_save_presets_file (GstPreset * preset);
|
||||||
* preset_get_paths:
|
* preset_get_paths:
|
||||||
* @preset: a #GObject that implements #GstPreset
|
* @preset: a #GObject that implements #GstPreset
|
||||||
* @preset_user_path: location for path or %NULL
|
* @preset_user_path: location for path or %NULL
|
||||||
|
* @preset_app_path: location for path or %NULL
|
||||||
* @preset_system_path: location for path or %NULL
|
* @preset_system_path: location for path or %NULL
|
||||||
*
|
*
|
||||||
* Fetch the preset_path for user local and system wide settings. Don't free
|
* Fetch the preset_path for user local, application specific and system wide
|
||||||
* after use.
|
* settings. Don't free after use.
|
||||||
*
|
*
|
||||||
* Returns: %FALSE if no paths could be found.
|
* Returns: %FALSE if no paths could be found.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
preset_get_paths (GstPreset * preset, const gchar ** preset_user_path,
|
preset_get_paths (GstPreset * preset, const gchar ** preset_user_path,
|
||||||
const gchar ** preset_system_path)
|
const gchar ** preset_app_path, const gchar ** preset_system_path)
|
||||||
{
|
{
|
||||||
GType type = G_TYPE_FROM_INSTANCE (preset);
|
GType type = G_TYPE_FROM_INSTANCE (preset);
|
||||||
gchar *preset_path;
|
gchar *preset_path;
|
||||||
|
@ -161,6 +176,22 @@ preset_get_paths (GstPreset * preset, const gchar ** preset_user_path,
|
||||||
*preset_user_path = preset_path;
|
*preset_user_path = preset_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preset_app_path) {
|
||||||
|
if (preset_app_dir) {
|
||||||
|
if (!(preset_path = g_type_get_qdata (type, preset_system_path_quark))) {
|
||||||
|
preset_path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s.prs",
|
||||||
|
preset_app_dir, element_name);
|
||||||
|
GST_INFO_OBJECT (preset, "application_preset_path: '%s'", preset_path);
|
||||||
|
|
||||||
|
/* cache the preset path to the type */
|
||||||
|
g_type_set_qdata (type, preset_app_path_quark, preset_path);
|
||||||
|
}
|
||||||
|
*preset_app_path = preset_path;
|
||||||
|
} else {
|
||||||
|
*preset_app_path = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (preset_system_path) {
|
if (preset_system_path) {
|
||||||
/* preset system path requested, see if we have it cached in the qdata */
|
/* preset system path requested, see if we have it cached in the qdata */
|
||||||
if (!(preset_path = g_type_get_qdata (type, preset_system_path_quark))) {
|
if (!(preset_path = g_type_get_qdata (type, preset_system_path_quark))) {
|
||||||
|
@ -195,10 +226,30 @@ preset_skip_property (GParamSpec * property)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* caller must free @preset_version after use */
|
static guint64
|
||||||
|
preset_parse_version (const gchar * str_version)
|
||||||
|
{
|
||||||
|
guint major, minor, micro, nano;
|
||||||
|
gint num;
|
||||||
|
|
||||||
|
major = minor = micro = nano = 0;
|
||||||
|
|
||||||
|
/* parse version (e.g. 0.10.15.1) to guint64 */
|
||||||
|
num = sscanf (str_version, "%u.%u.%u.%u", &major, &minor, µ, &nano);
|
||||||
|
/* make sure we have atleast "major.minor" */
|
||||||
|
if (num > 1) {
|
||||||
|
guint64 version;
|
||||||
|
|
||||||
|
version = ((((major << 8 | minor) << 8) | micro) << 8) | nano;
|
||||||
|
GST_DEBUG ("version %s -> %" G_GUINT64_FORMAT, str_version, version);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
return G_GUINT64_CONSTANT (0);
|
||||||
|
}
|
||||||
|
|
||||||
static GKeyFile *
|
static GKeyFile *
|
||||||
preset_open_and_parse_header (GstPreset * preset, const gchar * preset_path,
|
preset_open_and_parse_header (GstPreset * preset, const gchar * preset_path,
|
||||||
gchar ** preset_version)
|
guint64 * preset_version)
|
||||||
{
|
{
|
||||||
GKeyFile *in;
|
GKeyFile *in;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
@ -226,9 +277,12 @@ preset_open_and_parse_header (GstPreset * preset, const gchar * preset_path,
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
/* get the version now so that the caller can check it */
|
/* get the version now so that the caller can check it */
|
||||||
if (preset_version)
|
if (preset_version) {
|
||||||
*preset_version =
|
gchar *str =
|
||||||
g_key_file_get_value (in, PRESET_HEADER, PRESET_HEADER_VERSION, NULL);
|
g_key_file_get_value (in, PRESET_HEADER, PRESET_HEADER_VERSION, NULL);
|
||||||
|
*preset_version = preset_parse_version (str);
|
||||||
|
g_free (str);
|
||||||
|
}
|
||||||
|
|
||||||
return in;
|
return in;
|
||||||
|
|
||||||
|
@ -252,27 +306,6 @@ wrong_name:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint64
|
|
||||||
preset_parse_version (const gchar * str_version)
|
|
||||||
{
|
|
||||||
guint major, minor, micro, nano;
|
|
||||||
gint num;
|
|
||||||
|
|
||||||
major = minor = micro = nano = 0;
|
|
||||||
|
|
||||||
/* parse version (e.g. 0.10.15.1) to guint64 */
|
|
||||||
num = sscanf (str_version, "%u.%u.%u.%u", &major, &minor, µ, &nano);
|
|
||||||
/* make sure we have atleast "major.minor" */
|
|
||||||
if (num > 1) {
|
|
||||||
guint64 version;
|
|
||||||
|
|
||||||
version = ((((major << 8 | minor) << 8) | micro) << 8) | nano;
|
|
||||||
GST_DEBUG ("version %s -> %" G_GUINT64_FORMAT, str_version, version);
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
return G_GUINT64_CONSTANT (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
preset_merge (GKeyFile * system, GKeyFile * user)
|
preset_merge (GKeyFile * system, GKeyFile * user)
|
||||||
{
|
{
|
||||||
|
@ -331,56 +364,70 @@ preset_get_keyfile (GstPreset * preset)
|
||||||
|
|
||||||
/* first see if the have a cached version for the type */
|
/* first see if the have a cached version for the type */
|
||||||
if (!(presets = g_type_get_qdata (type, preset_quark))) {
|
if (!(presets = g_type_get_qdata (type, preset_quark))) {
|
||||||
const gchar *preset_user_path, *preset_system_path;
|
const gchar *preset_user_path, *preset_app_path, *preset_system_path;
|
||||||
gchar *str_version_user = NULL, *str_version_system = NULL;
|
guint64 version_system = G_GUINT64_CONSTANT (0);
|
||||||
gboolean updated_from_system = FALSE;
|
guint64 version_app = G_GUINT64_CONSTANT (0);
|
||||||
GKeyFile *in_user, *in_system;
|
guint64 version_user = G_GUINT64_CONSTANT (0);
|
||||||
|
guint64 version = G_GUINT64_CONSTANT (0);
|
||||||
|
gboolean merged = FALSE;
|
||||||
|
GKeyFile *in_user, *in_app = NULL, *in_system;
|
||||||
|
|
||||||
preset_get_paths (preset, &preset_user_path, &preset_system_path);
|
preset_get_paths (preset, &preset_user_path, &preset_app_path,
|
||||||
|
&preset_system_path);
|
||||||
|
|
||||||
/* try to load the user and system presets, we do this to get the versions
|
/* try to load the user, app and system presets, we do this to get the
|
||||||
* of both files. */
|
* versions of all files. */
|
||||||
in_user = preset_open_and_parse_header (preset, preset_user_path,
|
in_user = preset_open_and_parse_header (preset, preset_user_path,
|
||||||
&str_version_user);
|
&version_user);
|
||||||
|
if (preset_app_path) {
|
||||||
|
in_app = preset_open_and_parse_header (preset, preset_app_path,
|
||||||
|
&version_app);
|
||||||
|
}
|
||||||
in_system = preset_open_and_parse_header (preset, preset_system_path,
|
in_system = preset_open_and_parse_header (preset, preset_system_path,
|
||||||
&str_version_system);
|
&version_system);
|
||||||
|
|
||||||
/* compare version to check for merge */
|
/* compare version to check for merge */
|
||||||
if (in_system) {
|
if (in_system) {
|
||||||
/* keep system presets if there is no user preset or when the system
|
presets = in_system;
|
||||||
* version is higher than the user version. */
|
version = version_system;
|
||||||
if (!in_user) {
|
}
|
||||||
presets = in_system;
|
if (in_app) {
|
||||||
} else if (preset_parse_version (str_version_system) >
|
/* if system version is higher, merge */
|
||||||
preset_parse_version (str_version_user)) {
|
if (version > version_app) {
|
||||||
presets = in_system;
|
preset_merge (presets, in_app);
|
||||||
updated_from_system = TRUE;
|
g_key_file_free (in_app);
|
||||||
|
} else {
|
||||||
|
if (presets)
|
||||||
|
g_key_file_free (presets);
|
||||||
|
presets = in_app;
|
||||||
|
version = version_system;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_user) {
|
if (in_user) {
|
||||||
if (updated_from_system) {
|
/* if system or app version is higher, merge */
|
||||||
/* merge user on top of system presets */
|
if (version > version_user) {
|
||||||
preset_merge (presets, in_user);
|
preset_merge (presets, in_user);
|
||||||
g_key_file_free (in_user);
|
g_key_file_free (in_user);
|
||||||
|
merged = TRUE;
|
||||||
} else {
|
} else {
|
||||||
/* keep user presets */
|
if (presets)
|
||||||
|
g_key_file_free (presets);
|
||||||
presets = in_user;
|
presets = in_user;
|
||||||
|
version = version_user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!in_user && !in_system) {
|
|
||||||
/* we did not load a user or system presets file, create a new one */
|
if (!presets) {
|
||||||
|
/* we did not load a user, app or system presets file, create a new one */
|
||||||
presets = g_key_file_new ();
|
presets = g_key_file_new ();
|
||||||
g_key_file_set_string (presets, PRESET_HEADER, PRESET_HEADER_ELEMENT_NAME,
|
g_key_file_set_string (presets, PRESET_HEADER, PRESET_HEADER_ELEMENT_NAME,
|
||||||
G_OBJECT_TYPE_NAME (preset));
|
G_OBJECT_TYPE_NAME (preset));
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (str_version_user);
|
|
||||||
g_free (str_version_system);
|
|
||||||
|
|
||||||
/* attach the preset to the type */
|
/* attach the preset to the type */
|
||||||
g_type_set_qdata (type, preset_quark, (gpointer) presets);
|
g_type_set_qdata (type, preset_quark, (gpointer) presets);
|
||||||
|
|
||||||
if (updated_from_system) {
|
if (merged) {
|
||||||
gst_preset_default_save_presets_file (preset);
|
gst_preset_default_save_presets_file (preset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +625,7 @@ gst_preset_default_save_presets_file (GstPreset * preset)
|
||||||
gchar *data;
|
gchar *data;
|
||||||
gsize data_size;
|
gsize data_size;
|
||||||
|
|
||||||
preset_get_paths (preset, &preset_path, NULL);
|
preset_get_paths (preset, &preset_path, NULL, NULL);
|
||||||
|
|
||||||
/* get the presets from the type */
|
/* get the presets from the type */
|
||||||
if (!(presets = preset_get_keyfile (preset)))
|
if (!(presets = preset_get_keyfile (preset)))
|
||||||
|
@ -1041,6 +1088,46 @@ gst_preset_get_meta (GstPreset * preset, const gchar * name, const gchar * tag,
|
||||||
return GST_PRESET_GET_INTERFACE (preset)->get_meta (preset, name, tag, value);
|
return GST_PRESET_GET_INTERFACE (preset)->get_meta (preset, name, tag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_preset_set_app_dir:
|
||||||
|
* @app_dir: the application specific preset dir
|
||||||
|
*
|
||||||
|
* Sets an extra directory as an absolute path that should be considered when
|
||||||
|
* looking for presets. Any presets in the application dir will shadow the
|
||||||
|
* system presets.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE for success, %FALSE if the dir already has been set
|
||||||
|
*
|
||||||
|
* Since: 0.10.36
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_preset_set_app_dir (const gchar * app_dir)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (app_dir, FALSE);
|
||||||
|
|
||||||
|
if (!preset_app_dir) {
|
||||||
|
preset_app_dir = g_strdup (app_dir);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_preset_get_app_dir:
|
||||||
|
*
|
||||||
|
* Gets the directory for application specific presets if set by the
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* Returns: the directory or %NULL, don't free or modify the string
|
||||||
|
*
|
||||||
|
* Since: 0.10.36
|
||||||
|
*/
|
||||||
|
const gchar *
|
||||||
|
gst_preset_get_app_dir (void)
|
||||||
|
{
|
||||||
|
return preset_app_dir;
|
||||||
|
}
|
||||||
|
|
||||||
/* class internals */
|
/* class internals */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1072,6 +1159,7 @@ gst_preset_base_init (gpointer g_class)
|
||||||
preset_quark = g_quark_from_static_string ("GstPreset::presets");
|
preset_quark = g_quark_from_static_string ("GstPreset::presets");
|
||||||
preset_user_path_quark =
|
preset_user_path_quark =
|
||||||
g_quark_from_static_string ("GstPreset::user_path");
|
g_quark_from_static_string ("GstPreset::user_path");
|
||||||
|
preset_app_path_quark = g_quark_from_static_string ("GstPreset::app_path");
|
||||||
preset_system_path_quark =
|
preset_system_path_quark =
|
||||||
g_quark_from_static_string ("GstPreset::system_path");
|
g_quark_from_static_string ("GstPreset::system_path");
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,9 @@ gboolean gst_preset_set_meta (GstPreset *preset, const gchar *name
|
||||||
gboolean gst_preset_get_meta (GstPreset *preset, const gchar *name,
|
gboolean gst_preset_get_meta (GstPreset *preset, const gchar *name,
|
||||||
const gchar *tag, gchar **value);
|
const gchar *tag, gchar **value);
|
||||||
|
|
||||||
|
gboolean gst_preset_set_app_dir (const gchar *app_dir);
|
||||||
|
const gchar *gst_preset_get_app_dir (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_PRESET_H__ */
|
#endif /* __GST_PRESET_H__ */
|
||||||
|
|
|
@ -835,6 +835,7 @@ EXPORTS
|
||||||
gst_poll_wait
|
gst_poll_wait
|
||||||
gst_poll_write_control
|
gst_poll_write_control
|
||||||
gst_preset_delete_preset
|
gst_preset_delete_preset
|
||||||
|
gst_preset_get_app_dir
|
||||||
gst_preset_get_meta
|
gst_preset_get_meta
|
||||||
gst_preset_get_preset_names
|
gst_preset_get_preset_names
|
||||||
gst_preset_get_property_names
|
gst_preset_get_property_names
|
||||||
|
@ -842,6 +843,7 @@ EXPORTS
|
||||||
gst_preset_load_preset
|
gst_preset_load_preset
|
||||||
gst_preset_rename_preset
|
gst_preset_rename_preset
|
||||||
gst_preset_save_preset
|
gst_preset_save_preset
|
||||||
|
gst_preset_set_app_dir
|
||||||
gst_preset_set_meta
|
gst_preset_set_meta
|
||||||
gst_print_element_args
|
gst_print_element_args
|
||||||
gst_print_pad_caps
|
gst_print_pad_caps
|
||||||
|
|
Loading…
Reference in a new issue