Merge pull request #564 from Rafostar/disallow-enhancers

clapper: Ability to allow/disallow enhancers
This commit is contained in:
Rafał Dzięgiel
2025-06-24 18:51:52 +02:00
committed by GitHub
8 changed files with 162 additions and 43 deletions

View File

@@ -31,8 +31,10 @@
gint
main (gint argc, gchar **argv)
{
const gchar *clapper_ldir;
GApplication *application;
ClapperEnhancerProxyList *proxies;
const gchar *clapper_ldir;
guint i, n_proxies;
gint status;
#ifdef G_OS_WIN32
@@ -64,6 +66,15 @@ main (gint argc, gchar **argv)
resolution = clapper_app_utils_win_hi_res_clock_start ();
#endif
proxies = clapper_get_global_enhancer_proxies ();
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
/* Allow usage of all enhancers */
for (i = 0; i < n_proxies; ++i) {
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
clapper_enhancer_proxy_set_target_creation_allowed (proxy, TRUE);
}
application = clapper_app_application_new ();
status = g_application_run (application, argc, argv);

View File

@@ -86,6 +86,8 @@ struct _ClapperEnhancerProxy
ClapperEnhancerParamFlags scope;
GstStructure *local_config;
gboolean allowed;
/* GSettings are not thread-safe,
* so store schema instead */
GSettingsSchema *schema;
@@ -100,6 +102,7 @@ enum
PROP_MODULE_DIR,
PROP_DESCRIPTION,
PROP_VERSION,
PROP_TARGET_CREATION_ALLOWED,
PROP_LAST
};
@@ -229,6 +232,8 @@ clapper_enhancer_proxy_copy (ClapperEnhancerProxy *src_proxy, const gchar *copy_
if (src_proxy->local_config)
copy->local_config = gst_structure_copy (src_proxy->local_config);
copy->allowed = src_proxy->allowed;
GST_OBJECT_UNLOCK (src_proxy);
gst_object_ref_sink (copy);
@@ -359,6 +364,8 @@ clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *self)
if (G_UNLIKELY ((self->ifaces[i] = clapper_cache_read_iface (&data)) == 0))
goto abort_reading;
}
/* Reactable type is always last */
self->allowed = (self->ifaces[self->n_ifaces - 1] != CLAPPER_TYPE_REACTABLE);
}
/* Restore ParamSpecs */
@@ -456,6 +463,7 @@ clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *self)
gboolean
clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject *enhancer)
{
/* NOTE: REACTABLE must be last for "allowed" to work as expected */
const GType enhancer_types[] = { CLAPPER_TYPE_EXTRACTABLE, CLAPPER_TYPE_REACTABLE };
GType *ifaces;
GParamSpec **pspecs;
@@ -465,9 +473,12 @@ clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject *
/* Filter to only Clapper interfaces */
ifaces = g_type_interfaces (G_OBJECT_TYPE (enhancer), &n);
for (i = 0; i < n; ++i) {
for (j = 0; j < G_N_ELEMENTS (enhancer_types); ++j) {
const guint n_types = G_N_ELEMENTS (enhancer_types);
for (j = 0; j < n_types; ++j) {
if (ifaces[i] == enhancer_types[j]) {
ifaces[write_index++] = ifaces[i];
self->allowed = (j < n_types - 1);
break; // match found, do next iface
}
}
@@ -1088,6 +1099,58 @@ clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *self, GHash
gst_structure_free (structure);
}
/**
* clapper_enhancer_proxy_set_target_creation_allowed:
* @proxy: a #ClapperEnhancerProxy
* @allowed: whether allowed
*
* Set whether to allow instances of proxy target to be created.
*
* See [property@Clapper.EnhancerProxy:target-creation-allowed] for
* detailed descripton what this does.
*
* Since: 0.10
*/
void
clapper_enhancer_proxy_set_target_creation_allowed (ClapperEnhancerProxy *self, gboolean allowed)
{
gboolean changed;
g_return_if_fail (CLAPPER_IS_ENHANCER_PROXY (self));
GST_OBJECT_LOCK (self);
if ((changed = self->allowed != allowed))
self->allowed = allowed;
GST_OBJECT_UNLOCK (self);
if (changed)
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_TARGET_CREATION_ALLOWED]);
}
/**
* clapper_enhancer_proxy_get_target_creation_allowed:
* @proxy: a #ClapperEnhancerProxy
*
* Get whether it is allowed to create instances of enhancer that this proxy targets.
*
* Returns: whether target creation is allowed.
*
* Since: 0.10
*/
gboolean
clapper_enhancer_proxy_get_target_creation_allowed (ClapperEnhancerProxy *self)
{
gboolean allowed;
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY (self), FALSE);
GST_OBJECT_LOCK (self);
allowed = self->allowed;
GST_OBJECT_UNLOCK (self);
return allowed;
}
static void
clapper_enhancer_proxy_init (ClapperEnhancerProxy *self)
{
@@ -1137,6 +1200,25 @@ clapper_enhancer_proxy_get_property (GObject *object, guint prop_id,
case PROP_VERSION:
g_value_set_string (value, clapper_enhancer_proxy_get_version (self));
break;
case PROP_TARGET_CREATION_ALLOWED:
g_value_set_boolean (value, clapper_enhancer_proxy_get_target_creation_allowed (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clapper_enhancer_proxy_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
ClapperEnhancerProxy *self = CLAPPER_ENHANCER_PROXY_CAST (object);
switch (prop_id) {
case PROP_TARGET_CREATION_ALLOWED:
clapper_enhancer_proxy_set_target_creation_allowed (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1152,6 +1234,7 @@ clapper_enhancer_proxy_class_init (ClapperEnhancerProxyClass *klass)
"Clapper Enhancer Proxy");
gobject_class->get_property = clapper_enhancer_proxy_get_property;
gobject_class->set_property = clapper_enhancer_proxy_set_property;
gobject_class->finalize = clapper_enhancer_proxy_finalize;
/**
@@ -1209,5 +1292,29 @@ clapper_enhancer_proxy_class_init (ClapperEnhancerProxyClass *klass)
NULL, NULL, NULL,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperEnhancerProxy:target-creation-allowed:
*
* Whether to allow instances of proxy target to be created.
*
* This effectively means whether the given enhancer can be used.
*
* By default all enhancers that work on-demand such as [iface@Clapper.Extractable]
* are allowed while enhancers implementing [iface@Clapper.Reactable] are not.
*
* Value of this property from a `GLOBAL` [class@Clapper.EnhancerProxyList] will carry
* over to all newly created [class@Clapper.Player] objects, while altering this on
* `LOCAL` proxy list will only influence given player instance that list belongs to.
*
* Changing this property will not remove already created enhancer instances, thus
* it is usually best practice to allow/disallow creation of given enhancer plugin
* right after [class@Clapper.Player] is created (before it or its queue are used).
*
* Since: 0.10
*/
param_specs[PROP_TARGET_CREATION_ALLOWED] = g_param_spec_boolean ("target-creation-allowed",
NULL, NULL, FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
}

View File

@@ -76,4 +76,10 @@ void clapper_enhancer_proxy_set_locally (ClapperEnhancerProxy *proxy, const gcha
CLAPPER_API
void clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *proxy, GHashTable *table);
CLAPPER_API
void clapper_enhancer_proxy_set_target_creation_allowed (ClapperEnhancerProxy *proxy, gboolean allowed);
CLAPPER_API
gboolean clapper_enhancer_proxy_get_target_creation_allowed (ClapperEnhancerProxy *proxy);
G_END_DECLS

View File

@@ -54,6 +54,28 @@ _import_enhancers (const gchar *enhancers_path)
g_strfreev (dir_paths);
}
static GObject *
_force_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type)
{
GObject *enhancer = NULL;
PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy);
g_mutex_lock (&load_lock);
if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) {
GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_module_name (info));
} else if (!peas_engine_provides_extension (_engine, info, iface_type)) {
GST_LOG ("No \"%s\" enhancer in module: %s", g_type_name (iface_type),
peas_plugin_info_get_module_name (info));
} else {
enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL);
}
g_mutex_unlock (&load_lock);
return enhancer;
}
/*
* clapper_enhancers_loader_initialize:
*
@@ -155,7 +177,7 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
/* We cannot ask libpeas for "any" of our main interfaces, so try each one until found */
for (j = 0; j < G_N_ELEMENTS (main_types); ++j) {
if ((enhancer = clapper_enhancers_loader_create_enhancer (proxy, main_types[j]))) {
if ((enhancer = _force_create_enhancer (proxy, main_types[j]))) {
filled = clapper_enhancer_proxy_fill_from_instance (proxy, enhancer);
g_object_unref (enhancer);
@@ -200,21 +222,8 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
GObject *
clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type)
{
GObject *enhancer = NULL;
PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy);
if (!clapper_enhancer_proxy_get_target_creation_allowed (proxy))
return NULL;
g_mutex_lock (&load_lock);
if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) {
GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_module_name (info));
} else if (!peas_engine_provides_extension (_engine, info, iface_type)) {
GST_LOG ("No \"%s\" enhancer in module: %s", g_type_name (iface_type),
peas_plugin_info_get_module_name (info));
} else {
enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL);
}
g_mutex_unlock (&load_lock);
return enhancer;
return _force_create_enhancer (proxy, iface_type);
}

View File

@@ -2339,8 +2339,6 @@ clapper_player_init (ClapperPlayer *self)
if (clapper_enhancer_proxy_list_has_proxy_with_interface (self->enhancer_proxies, CLAPPER_TYPE_REACTABLE)) {
self->reactables_manager = clapper_reactables_manager_new ();
gst_object_set_parent (GST_OBJECT_CAST (self->reactables_manager), GST_OBJECT_CAST (self));
clapper_reactables_manager_trigger_prepare (self->reactables_manager);
}
self->position_query = gst_query_new_position (GST_FORMAT_TIME);

View File

@@ -36,9 +36,6 @@ void clapper_reactables_manager_initialize (void);
G_GNUC_INTERNAL
ClapperReactablesManager * clapper_reactables_manager_new (void);
G_GNUC_INTERNAL
void clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *manager);
G_GNUC_INTERNAL
void clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *manager, ClapperEnhancerProxy *proxy, GstStructure *config);

View File

@@ -43,6 +43,8 @@ struct _ClapperReactablesManager
GstBus *bus;
GPtrArray *array;
gboolean prepare_called;
};
#define parent_class clapper_reactables_manager_parent_class
@@ -74,15 +76,13 @@ enum
enum
{
CLAPPER_REACTABLES_MANAGER_QUARK_PREPARE = 0,
CLAPPER_REACTABLES_MANAGER_QUARK_CONFIGURE,
CLAPPER_REACTABLES_MANAGER_QUARK_CONFIGURE = 0,
CLAPPER_REACTABLES_MANAGER_QUARK_EVENT,
CLAPPER_REACTABLES_MANAGER_QUARK_VALUE,
CLAPPER_REACTABLES_MANAGER_QUARK_EXTRA_VALUE
};
static ClapperBusQuark _quarks[] = {
{"prepare", 0},
{"configure", 0},
{"event", 0},
{"value", 0},
@@ -161,7 +161,7 @@ clapper_reactables_manager_handle_prepare (ClapperReactablesManager *self)
clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_REACTABLE));
#endif
if (G_LIKELY (reactable != NULL)) {
if (reactable) {
ClapperReactableManagerData *data;
GstStructure *config;
@@ -216,11 +216,9 @@ clapper_reactables_manager_handle_configure (ClapperReactablesManager *self, con
if (data->proxy == proxy) {
clapper_enhancer_proxy_apply_config_to_enhancer (data->proxy,
config, (GObject *) data->reactable);
return;
break;
}
}
GST_ERROR_OBJECT (self, "Triggered configure, but no matching enhancer proxy found");
}
static inline void
@@ -319,9 +317,11 @@ _bus_message_func (GstBus *bus, GstMessage *msg, gpointer user_data G_GNUC_UNUSE
GQuark quark = gst_structure_get_name_id (structure);
if (quark == _QUARK (EVENT)) {
clapper_reactables_manager_handle_event (self, structure);
} else if (quark == _QUARK (PREPARE)) {
if (G_UNLIKELY (!self->prepare_called)) {
clapper_reactables_manager_handle_prepare (self);
self->prepare_called = TRUE;
}
clapper_reactables_manager_handle_event (self, structure);
} else if (quark == _QUARK (CONFIGURE)) {
clapper_reactables_manager_handle_configure (self, structure);
} else {
@@ -365,15 +365,6 @@ clapper_reactables_manager_new (void)
return reactables_manager;
}
void
clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *self)
{
GstStructure *structure = gst_structure_new_id_empty (_QUARK (PREPARE));
gst_bus_post (self->bus, gst_message_new_application (
GST_OBJECT_CAST (self), structure));
}
void
clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *self,
ClapperEnhancerProxy *proxy, GstStructure *config)

View File

@@ -93,7 +93,7 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_EXTRACTABLE));
#endif
if (G_LIKELY (extractable != NULL)) {
if (extractable) {
if (config)
clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) extractable);