clapper: Implement data cache

Add data cache functions and use them to store enhancer data into local cache file.
This way we can restore all properties and interfaces used in enhancer without
creating its instance. This avoids loading interpreters like Python at init time
making startup a lot faster.
This commit is contained in:
Rafał Dzięgiel
2025-05-12 22:22:28 +02:00
parent 3ef6e9694a
commit c6c4fe309b
7 changed files with 766 additions and 6 deletions

View File

@@ -0,0 +1,93 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL
void clapper_cache_initialize (void);
G_GNUC_INTERNAL
GMappedFile * clapper_cache_open (const gchar *filename, const gchar **data, GError **error);
G_GNUC_INTERNAL
gboolean clapper_cache_read_boolean (const gchar **data);
G_GNUC_INTERNAL
gint clapper_cache_read_int (const gchar **data);
G_GNUC_INTERNAL
guint clapper_cache_read_uint (const gchar **data);
G_GNUC_INTERNAL
gdouble clapper_cache_read_double (const gchar **data);
G_GNUC_INTERNAL
const gchar * clapper_cache_read_string (const gchar **data);
G_GNUC_INTERNAL
GType clapper_cache_read_enum (const gchar **data);
G_GNUC_INTERNAL
GType clapper_cache_read_flags (const gchar **data);
G_GNUC_INTERNAL
GType clapper_cache_read_iface (const gchar **data);
G_GNUC_INTERNAL
GParamSpec * clapper_cache_read_pspec (const gchar **data);
G_GNUC_INTERNAL
GByteArray * clapper_cache_create (void);
G_GNUC_INTERNAL
void clapper_cache_store_boolean (GByteArray *bytes, gboolean val);
G_GNUC_INTERNAL
void clapper_cache_store_int (GByteArray *bytes, gint val);
G_GNUC_INTERNAL
void clapper_cache_store_uint (GByteArray *bytes, guint val);
G_GNUC_INTERNAL
void clapper_cache_store_double (GByteArray *bytes, gdouble val);
G_GNUC_INTERNAL
void clapper_cache_store_string (GByteArray *bytes, const gchar *val);
G_GNUC_INTERNAL
void clapper_cache_store_enum (GByteArray *bytes, GType enum_type);
G_GNUC_INTERNAL
void clapper_cache_store_flags (GByteArray *bytes, GType flags_type);
G_GNUC_INTERNAL
gboolean clapper_cache_store_iface (GByteArray *bytes, GType iface);
G_GNUC_INTERNAL
gboolean clapper_cache_store_pspec (GByteArray *bytes, GParamSpec *pspec);
G_GNUC_INTERNAL
gboolean clapper_cache_write (const gchar *filename, GByteArray *bytes, GError **error);
G_END_DECLS

View File

@@ -0,0 +1,491 @@
/* Clapper Playback Library
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "clapper-cache-private.h"
#include "clapper-version.h"
#include "clapper-extractable.h"
#define CLAPPER_CACHE_HEADER "CLAPPER"
typedef enum
{
CLAPPER_CACHE_IFACE_EXTRACTABLE = 1,
} ClapperCacheIfaces;
static GArray *enum_registry = NULL;
static GArray *flags_registry = NULL;
static gboolean cache_disabled = FALSE;
void
clapper_cache_initialize (void)
{
const gchar *env = g_getenv ("CLAPPER_DISABLE_CACHE");
if (G_LIKELY (!env || !g_str_has_prefix (env, "1"))) {
enum_registry = g_array_new (FALSE, TRUE, sizeof (GEnumValue *));
flags_registry = g_array_new (FALSE, TRUE, sizeof (GFlagsValue *));
} else {
cache_disabled = TRUE;
}
}
GMappedFile *
clapper_cache_open (const gchar *filename, const gchar **data, GError **error)
{
GMappedFile *file;
if (G_UNLIKELY (cache_disabled))
return NULL;
if (!(file = g_mapped_file_new (filename, FALSE, error)))
return NULL;
if (G_UNLIKELY (g_mapped_file_get_length (file) == 0)) {
g_mapped_file_unref (file);
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"File is empty");
return NULL;
}
*data = g_mapped_file_get_contents (file);
/* Header name check */
if (G_UNLIKELY (g_strcmp0 (*data, CLAPPER_CACHE_HEADER) != 0)) {
g_mapped_file_unref (file);
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Invalid file header");
return NULL;
}
*data += strlen (*data) + 1;
/* Header version check */
if (clapper_cache_read_uint (data) != CLAPPER_VERSION_HEX) {
g_mapped_file_unref (file);
/* Just different version, so no error set */
return NULL;
}
return file;
}
inline gboolean
clapper_cache_read_boolean (const gchar **data)
{
gboolean val = *(const gboolean *) *data;
*data += sizeof (gboolean);
return val;
}
inline gint
clapper_cache_read_int (const gchar **data)
{
gint val = *(const gint *) *data;
*data += sizeof (gint);
return val;
}
inline guint
clapper_cache_read_uint (const gchar **data)
{
guint val = *(const guint *) *data;
*data += sizeof (guint);
return val;
}
inline gdouble
clapper_cache_read_double (const gchar **data)
{
gdouble val = *(const gdouble *) *data;
*data += sizeof (gdouble);
return val;
}
inline const gchar *
clapper_cache_read_string (const gchar **data)
{
const gboolean is_null = clapper_cache_read_boolean (data);
const gchar *str = NULL;
if (!is_null) {
str = *data;
*data += strlen (str) + 1;
}
return str;
}
inline GType
clapper_cache_read_enum (const gchar **data)
{
GType type;
const gchar *enum_name;
guint i, n_values;
enum_name = clapper_cache_read_string (data);
n_values = clapper_cache_read_uint (data);
/* If not registered yet */
if ((type = g_type_from_name (enum_name)) == 0) {
GEnumValue *values = g_new0 (GEnumValue, n_values + 1);
for (i = 0; i < n_values; ++i) {
values[i].value = clapper_cache_read_int (data);
values[i].value_name = g_intern_string (clapper_cache_read_string (data));
values[i].value_nick = g_intern_string (clapper_cache_read_string (data));
}
g_array_append_val (enum_registry, values); // store statically
type = g_enum_register_static (g_intern_string (enum_name),
g_array_index (enum_registry, GEnumValue *, enum_registry->len - 1));
} else {
/* Skip over data */
for (i = 0; i < n_values; ++i) {
clapper_cache_read_int (data); // value
clapper_cache_read_string (data); // value_name
clapper_cache_read_string (data); // value_nick
}
}
return type;
}
inline GType
clapper_cache_read_flags (const gchar **data)
{
GType type;
const gchar *flags_name;
guint i, n_values;
flags_name = clapper_cache_read_string (data);
n_values = clapper_cache_read_uint (data);
/* If not registered yet */
if ((type = g_type_from_name (flags_name)) == 0) {
GFlagsValue *values = g_new0 (GFlagsValue, n_values + 1);
for (i = 0; i < n_values; ++i) {
values[i].value = clapper_cache_read_int (data);
values[i].value_name = g_intern_string (clapper_cache_read_string (data));
values[i].value_nick = g_intern_string (clapper_cache_read_string (data));
}
g_array_append_val (flags_registry, values); // store statically
type = g_flags_register_static (g_intern_string (flags_name),
g_array_index (flags_registry, GFlagsValue *, flags_registry->len - 1));
} else {
/* Skip over data */
for (i = 0; i < n_values; ++i) {
clapper_cache_read_int (data); // value
clapper_cache_read_string (data); // value_name
clapper_cache_read_string (data); // value_nick
}
}
return type;
}
GType
clapper_cache_read_iface (const gchar **data)
{
gint iface_id = clapper_cache_read_int (data);
switch (iface_id) {
case CLAPPER_CACHE_IFACE_EXTRACTABLE:
return CLAPPER_TYPE_EXTRACTABLE;
default:
return 0;
}
}
GParamSpec *
clapper_cache_read_pspec (const gchar **data)
{
GParamSpec *pspec;
GType value_type;
const gchar *name, *nick, *blurb;
GParamFlags flags;
value_type = *(const GType *) *data;
*data += sizeof (GType);
name = clapper_cache_read_string (data);
nick = clapper_cache_read_string (data);
blurb = clapper_cache_read_string (data);
flags = *(const GParamFlags *) *data;
*data += sizeof (GParamFlags);
/* NOTE: C does not guarantee order in which function arguments
* are evaluated, so read into variables and then create pspec */
switch (value_type) {
case G_TYPE_BOOLEAN:
pspec = g_param_spec_boolean (name, nick, blurb,
clapper_cache_read_boolean (data), flags);
break;
case G_TYPE_INT:{
gint minimum = clapper_cache_read_int (data);
gint maximum = clapper_cache_read_int (data);
gint default_value = clapper_cache_read_int (data);
pspec = g_param_spec_int (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_UINT:{
guint minimum = clapper_cache_read_uint (data);
guint maximum = clapper_cache_read_uint (data);
guint default_value = clapper_cache_read_uint (data);
pspec = g_param_spec_uint (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_DOUBLE:{
gdouble minimum = clapper_cache_read_double (data);
gdouble maximum = clapper_cache_read_double (data);
gdouble default_value = clapper_cache_read_double (data);
pspec = g_param_spec_double (name, nick, blurb,
minimum, maximum, default_value, flags);
break;
}
case G_TYPE_STRING:
pspec = g_param_spec_string (name, nick, blurb,
clapper_cache_read_string (data), flags);
break;
case G_TYPE_ENUM:{
GType enum_type = clapper_cache_read_enum (data);
gint default_value = clapper_cache_read_int (data);
pspec = g_param_spec_enum (name, nick, blurb,
enum_type, default_value, flags);
break;
}
case G_TYPE_FLAGS:{
GType flags_type = clapper_cache_read_flags (data);
guint default_value = clapper_cache_read_uint (data);
pspec = g_param_spec_flags (name, nick, blurb,
flags_type, default_value, flags);
break;
}
default:
return NULL;
}
return g_param_spec_ref_sink (pspec);
}
GByteArray *
clapper_cache_create (void)
{
GByteArray *bytes;
if (G_UNLIKELY (cache_disabled))
return NULL;
bytes = g_byte_array_new ();
/* NOTE: We do not store whether string is NULL here, since it never is */
g_byte_array_append (bytes, (const guint8 *) CLAPPER_CACHE_HEADER, 8); // 7 + 1
clapper_cache_store_uint (bytes, CLAPPER_VERSION_HEX);
return bytes;
}
inline void
clapper_cache_store_boolean (GByteArray *bytes, gboolean val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gboolean));
}
inline void
clapper_cache_store_int (GByteArray *bytes, gint val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gint));
}
inline void
clapper_cache_store_uint (GByteArray *bytes, guint val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (guint));
}
inline void
clapper_cache_store_double (GByteArray *bytes, gdouble val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gdouble));
}
inline void
clapper_cache_store_string (GByteArray *bytes, const gchar *val)
{
/* Distinguish empty string from NULL */
const gboolean is_null = (val == NULL);
clapper_cache_store_boolean (bytes, is_null);
if (!is_null)
g_byte_array_append (bytes, (const guint8 *) val, strlen (val) + 1);
}
inline void
clapper_cache_store_enum (GByteArray *bytes, GType enum_type)
{
GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_peek (enum_type));
guint i;
clapper_cache_store_string (bytes, g_type_name (enum_type));
clapper_cache_store_uint (bytes, enum_class->n_values);
for (i = 0; i < enum_class->n_values; ++i) {
clapper_cache_store_int (bytes, enum_class->values[i].value);
clapper_cache_store_string (bytes, enum_class->values[i].value_name);
clapper_cache_store_string (bytes, enum_class->values[i].value_nick);
}
}
inline void
clapper_cache_store_flags (GByteArray *bytes, GType flags_type)
{
GFlagsClass *flags_class = G_FLAGS_CLASS (g_type_class_peek (flags_type));
guint i;
clapper_cache_store_string (bytes, g_type_name (flags_type));
clapper_cache_store_uint (bytes, flags_class->n_values);
for (i = 0; i < flags_class->n_values; ++i) {
clapper_cache_store_int (bytes, flags_class->values[i].value);
clapper_cache_store_string (bytes, flags_class->values[i].value_name);
clapper_cache_store_string (bytes, flags_class->values[i].value_nick);
}
}
gboolean
clapper_cache_store_iface (GByteArray *bytes, GType iface)
{
gint iface_id = 0;
if (iface == CLAPPER_TYPE_EXTRACTABLE)
iface_id = CLAPPER_CACHE_IFACE_EXTRACTABLE;
else
return FALSE;
clapper_cache_store_int (bytes, iface_id);
return TRUE;
}
gboolean
clapper_cache_store_pspec (GByteArray *bytes, GParamSpec *pspec)
{
GParamFlags flags;
const gboolean is_enum = G_IS_PARAM_SPEC_ENUM (pspec);
const gboolean is_flags = (!is_enum && G_IS_PARAM_SPEC_FLAGS (pspec));
if (is_enum) {
GType enum_type = G_TYPE_ENUM;
g_byte_array_append (bytes, (const guint8 *) &enum_type, sizeof (GType));
} else if (is_flags) {
GType flags_type = G_TYPE_FLAGS;
g_byte_array_append (bytes, (const guint8 *) &flags_type, sizeof (GType));
} else {
g_byte_array_append (bytes, (const guint8 *) &pspec->value_type, sizeof (GType));
}
clapper_cache_store_string (bytes, g_param_spec_get_name (pspec));
clapper_cache_store_string (bytes, g_param_spec_get_nick (pspec));
clapper_cache_store_string (bytes, g_param_spec_get_blurb (pspec));
flags = pspec->flags;
flags &= ~G_PARAM_STATIC_STRINGS; // Data read from cache is never static
g_byte_array_append (bytes, (const guint8 *) &flags, sizeof (GParamFlags));
switch (pspec->value_type) {
case G_TYPE_BOOLEAN:{
GParamSpecBoolean *p = (GParamSpecBoolean *) pspec;
clapper_cache_store_boolean (bytes, p->default_value);
break;
}
case G_TYPE_INT:{
GParamSpecInt *p = (GParamSpecInt *) pspec;
clapper_cache_store_int (bytes, p->minimum);
clapper_cache_store_int (bytes, p->maximum);
clapper_cache_store_int (bytes, p->default_value);
break;
}
case G_TYPE_UINT:{
GParamSpecUInt *p = (GParamSpecUInt *) pspec;
clapper_cache_store_uint (bytes, p->minimum);
clapper_cache_store_uint (bytes, p->maximum);
clapper_cache_store_uint (bytes, p->default_value);
break;
}
case G_TYPE_DOUBLE:{
GParamSpecDouble *p = (GParamSpecDouble *) pspec;
clapper_cache_store_double (bytes, p->minimum);
clapper_cache_store_double (bytes, p->maximum);
clapper_cache_store_double (bytes, p->default_value);
break;
}
case G_TYPE_STRING:{
GParamSpecString *p = (GParamSpecString *) pspec;
clapper_cache_store_string (bytes, p->default_value);
break;
}
default:{
if (is_enum) {
GParamSpecEnum *p = (GParamSpecEnum *) pspec;
clapper_cache_store_enum (bytes, pspec->value_type);
clapper_cache_store_int (bytes, p->default_value);
break;
} else if (is_flags) {
GParamSpecFlags *p = (GParamSpecFlags *) pspec;
clapper_cache_store_flags (bytes, pspec->value_type);
clapper_cache_store_uint (bytes, p->default_value);
break;
}
return FALSE;
}
}
return TRUE;
}
gboolean
clapper_cache_write (const gchar *filename, GByteArray *bytes, GError **error)
{
gchar *dirname = g_path_get_dirname (filename);
gboolean has_dir;
has_dir = (g_mkdir_with_parents (dirname, 0755) == 0);
g_free (dirname);
if (!has_dir) {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not create directory to store cache content");
return FALSE;
}
/* Using "g_file_set_contents" to replace file atomically */
return g_file_set_contents (filename, (const gchar *) bytes->data, bytes->len, error);
}

View File

@@ -38,6 +38,9 @@ gboolean clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
gboolean clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *proxy, GObject *enhancer);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
GObject * clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *proxy);

View File

@@ -45,6 +45,7 @@
#include "clapper.h"
#include "clapper-enhancer-proxy-private.h"
#include "clapper-cache-private.h"
#include "clapper-extractable.h"
#include "clapper-enums.h"
@@ -308,21 +309,183 @@ _init_schema (ClapperEnhancerProxy *self)
GST_OBJECT_UNLOCK (self);
}
static inline gchar *
_build_cache_filename (ClapperEnhancerProxy *self)
{
return g_build_filename (g_get_user_cache_dir (), CLAPPER_API_NAME,
"enhancers", self->module_name, "cache.bin", NULL);
}
gboolean
clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *self)
{
GST_FIXME_OBJECT (self, "Implement enhancer proxy caching");
GMappedFile *mapped_file;
GError *error = NULL;
gchar *filename;
const gchar *data;
guint i;
filename = _build_cache_filename (self);
mapped_file = clapper_cache_open (filename, &data, &error);
g_free (filename);
if (!mapped_file) {
/* No error if cache disabled or version mismatch */
if (error) {
if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
GST_DEBUG_OBJECT (self, "No cache file found");
else
GST_ERROR_OBJECT (self, "Could not restore from cache, reason: %s", error->message);
g_error_free (error);
}
return FALSE;
}
/* Plugin version check */
if (g_strcmp0 (clapper_cache_read_string (&data), self->version) != 0)
return FALSE; // not an error
/* Restore Interfaces */
if ((self->n_ifaces = clapper_cache_read_uint (&data)) > 0) {
self->ifaces = g_new (GType, self->n_ifaces);
for (i = 0; i < self->n_ifaces; ++i) {
if (G_UNLIKELY ((self->ifaces[i] = clapper_cache_read_iface (&data)) == 0))
goto abort_reading;
}
}
/* Restore ParamSpecs */
if ((self->n_pspecs = clapper_cache_read_uint (&data)) > 0) {
self->pspecs = g_new (GParamSpec *, self->n_pspecs);
for (i = 0; i < self->n_pspecs; ++i) {
if (G_UNLIKELY ((self->pspecs[i] = clapper_cache_read_pspec (&data)) == NULL))
goto abort_reading;
}
}
g_mapped_file_unref (mapped_file);
GST_DEBUG_OBJECT (self, "Filled proxy \"%s\" from cache, n_ifaces: %u, n_pspecs: %u",
self->friendly_name, self->n_ifaces, self->n_pspecs);
return TRUE;
abort_reading:
GST_ERROR_OBJECT (self, "Cache file is corrupted or invalid");
g_free (self->ifaces);
self->n_ifaces = 0;
for (i = 0; i < self->n_pspecs; ++i) {
g_clear_pointer (&self->pspecs[i], g_param_spec_unref);
}
g_free (self->pspecs);
self->n_pspecs = 0;
g_mapped_file_unref (mapped_file);
return FALSE;
}
void
clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *self)
{
GByteArray *bytes;
GError *error = NULL;
gchar *filename;
gboolean data_ok = TRUE;
guint i;
bytes = clapper_cache_create ();
/* If cache disabled */
if (G_UNLIKELY (bytes == NULL))
return;
filename = _build_cache_filename (self);
GST_TRACE_OBJECT (self, "Exporting data to cache file: \"%s\"", filename);
/* Store version */
clapper_cache_store_string (bytes, self->version);
/* Store Interfaces */
clapper_cache_store_uint (bytes, self->n_ifaces);
for (i = 0; i < self->n_ifaces; ++i) {
/* This should never happen, as we only store Clapper interfaces */
if (G_UNLIKELY (!(data_ok = clapper_cache_store_iface (bytes, self->ifaces[i])))) {
g_warning ("Cannot cache enhancer \"%s\" (%s), as it contains"
" unsupported interface type \"%s\"",
self->friendly_name, self->module_name, g_type_name (self->ifaces[i]));
break;
}
}
if (data_ok) {
/* Store ParamSpecs */
clapper_cache_store_uint (bytes, self->n_pspecs);
for (i = 0; i < self->n_pspecs; ++i) {
/* Can happen if someone writes an enhancer with unsupported
* param spec type with ClapperEnhancerParamFlags set */
if (G_UNLIKELY (!(data_ok = clapper_cache_store_pspec (bytes, self->pspecs[i])))) {
g_warning ("Cannot cache enhancer \"%s\" (%s), as it contains"
" property \"%s\" of unsupported type",
self->friendly_name, self->module_name, self->pspecs[i]->name);
break;
}
}
}
if (data_ok && clapper_cache_write (filename, bytes, &error)) {
GST_TRACE_OBJECT (self, "Successfully exported data to cache file");
} else if (error) {
GST_ERROR_OBJECT (self, "Could not cache data, reason: %s", error->message);
g_error_free (error);
}
g_free (filename);
g_byte_array_free (bytes, TRUE);
}
gboolean
clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject *enhancer)
{
self->ifaces = g_type_interfaces (G_OBJECT_TYPE (enhancer), &self->n_ifaces);
self->pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (enhancer), &self->n_pspecs);
GType enhancer_types[1] = { CLAPPER_TYPE_EXTRACTABLE };
GType *ifaces;
GParamSpec **pspecs;
GParamFlags enhancer_flags;
guint i, j, n, write_index = 0;
GST_DEBUG_OBJECT (self, "Filled proxy \"%s\", n_ifaces: %u, n_pspecs: %u",
/* 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) {
if (ifaces[i] == enhancer_types[j]) {
ifaces[write_index++] = ifaces[i];
break; // match found, do next iface
}
}
}
/* Resize memory */
self->n_ifaces = write_index;
self->ifaces = g_realloc (ifaces, self->n_ifaces * sizeof (GType));
/* Filter to only Clapper param specs */
write_index = 0;
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (enhancer), &n);
enhancer_flags = (CLAPPER_ENHANCER_PARAM_GLOBAL | CLAPPER_ENHANCER_PARAM_LOCAL);
for (i = 0; i < n; ++i) {
if (pspecs[i]->flags & enhancer_flags)
pspecs[write_index++] = g_param_spec_ref (pspecs[i]);
}
/* Resize memory */
self->n_pspecs = write_index;
self->pspecs = g_realloc (pspecs, self->n_pspecs * sizeof (GParamSpec *));
GST_DEBUG_OBJECT (self, "Filled proxy \"%s\" from instance, n_ifaces: %u, n_pspecs: %u",
self->friendly_name, self->n_ifaces, self->n_pspecs);
return TRUE;
@@ -925,14 +1088,20 @@ static void
clapper_enhancer_proxy_finalize (GObject *object)
{
ClapperEnhancerProxy *self = CLAPPER_ENHANCER_PROXY_CAST (object);
guint i;
GST_TRACE_OBJECT (self, "Finalize");
g_object_unref (self->peas_info);
g_free (self->ifaces);
for (i = 0; i < self->n_pspecs; ++i) {
g_param_spec_unref (self->pspecs[i]);
}
g_free (self->pspecs);
g_clear_pointer (&self->schema, g_settings_schema_unref);
gst_clear_structure (&self->local_config);
g_clear_pointer (&self->schema, g_settings_schema_unref);
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View File

@@ -128,7 +128,7 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
filled = clapper_enhancer_proxy_fill_from_instance (proxy, enhancer);
g_object_unref (enhancer);
GST_FIXME_OBJECT (proxy, "Save enhancer proxy data to cache");
clapper_enhancer_proxy_export_to_cache (proxy);
break;
}
}

View File

@@ -23,6 +23,7 @@
#include <gst/pbutils/pbutils.h>
#include "clapper.h"
#include "clapper-cache-private.h"
#include "clapper-utils-private.h"
#include "clapper-playbin-bus-private.h"
#include "clapper-app-bus-private.h"
@@ -48,6 +49,7 @@ clapper_init_check_internal (int *argc, char **argv[])
gst_pb_utils_init ();
clapper_cache_initialize ();
clapper_utils_initialize ();
clapper_playbin_bus_initialize ();
clapper_app_bus_initialize ();

View File

@@ -54,6 +54,7 @@ config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
config_h.set_quoted('PACKAGE_ORIGIN', 'https://github.com/Rafostar/clapper')
config_h.set_quoted('PLUGIN_DESC', 'Clapper elements')
config_h.set_quoted('PLUGIN_LICENSE', 'LGPL')
config_h.set_quoted('CLAPPER_API_NAME', clapper_api_name)
config_h.set_quoted('CLAPPER_ENHANCERS_ID', 'com.github.rafostar.Clapper.Enhancers')
config_h.set_quoted('CLAPPER_ENHANCERS_PATH', clapper_enhancers_dir)
@@ -133,6 +134,7 @@ clapper_sources = [
'clapper.c',
'clapper-app-bus.c',
'clapper-audio-stream.c',
'clapper-cache.c',
'clapper-enhancer-proxy.c',
'clapper-enhancer-proxy-list.c',
'clapper-extractable.c',