mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
clapper: Introduce "ClapperEnhancerProxy" objects
Add support for configuring Clapper Enhancers. In order to do that, introduce enhancer proxy object that act as intermediary between player and enhancer plugin. We cannot give direct access to enhancer instances from code, since they are managed (created and destroyed) by player as/when needed. Also due to some interpreted languages not working with multiple threads. Instead, give proxy objects that will store each enhancer configuration to be applied when an enhancer instance is created. With this, implementations also gain ability to browse available enhancers, see what they support and change their properties. Enhancers are now also assigned to player, instead of being only global. This allows to configure them separately on a per player instance basis. Writing configurable enhancers is super easy too, as all plugin has to do is install standard GParamSpec properties to its class with a corresponding gschema file (for global props only) and its done.
This commit is contained in:
41
src/lib/clapper/clapper-enhancer-proxy-list-private.h
Normal file
41
src/lib/clapper/clapper-enhancer-proxy-list-private.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 "clapper-enhancer-proxy-list.h"
|
||||
#include "clapper-enhancer-proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
ClapperEnhancerProxyList * clapper_enhancer_proxy_list_new_named (const gchar *name);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancer_proxy_list_take_proxy (ClapperEnhancerProxyList *list, ClapperEnhancerProxy *proxy);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancer_proxy_list_fill_from_global_proxies (ClapperEnhancerProxyList *list);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *list);
|
||||
|
||||
G_END_DECLS
|
329
src/lib/clapper/clapper-enhancer-proxy-list.c
Normal file
329
src/lib/clapper/clapper-enhancer-proxy-list.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ClapperEnhancerProxyList:
|
||||
*
|
||||
* A list of enhancer proxies.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "clapper.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "clapper-enhancer-proxy-private.h"
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_enhancer_proxy_list_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
struct _ClapperEnhancerProxyList
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GPtrArray *proxies;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_N_PROXIES,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static void clapper_enhancer_proxy_list_model_iface_init (GListModelInterface *iface);
|
||||
|
||||
#define parent_class clapper_enhancer_proxy_list_parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (ClapperEnhancerProxyList, clapper_enhancer_proxy_list, GST_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, clapper_enhancer_proxy_list_model_iface_init));
|
||||
|
||||
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
|
||||
|
||||
static GType
|
||||
clapper_enhancer_proxy_list_model_get_item_type (GListModel *model)
|
||||
{
|
||||
return CLAPPER_TYPE_ENHANCER_PROXY;
|
||||
}
|
||||
|
||||
static guint
|
||||
clapper_enhancer_proxy_list_model_get_n_items (GListModel *model)
|
||||
{
|
||||
return CLAPPER_ENHANCER_PROXY_LIST_CAST (model)->proxies->len;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
clapper_enhancer_proxy_list_model_get_item (GListModel *model, guint index)
|
||||
{
|
||||
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (model);
|
||||
ClapperEnhancerProxy *proxy = NULL;
|
||||
|
||||
if (G_LIKELY (index < self->proxies->len))
|
||||
proxy = gst_object_ref (g_ptr_array_index (self->proxies, index));
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_proxy_list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = clapper_enhancer_proxy_list_model_get_item_type;
|
||||
iface->get_n_items = clapper_enhancer_proxy_list_model_get_n_items;
|
||||
iface->get_item = clapper_enhancer_proxy_list_model_get_item;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancer_proxy_list_new_named:
|
||||
* @name: (nullable): name of the #GstObject
|
||||
*
|
||||
* Returns: (transfer full): a new #ClapperEnhancerProxyList instance
|
||||
*/
|
||||
ClapperEnhancerProxyList *
|
||||
clapper_enhancer_proxy_list_new_named (const gchar *name)
|
||||
{
|
||||
ClapperEnhancerProxyList *list;
|
||||
|
||||
list = g_object_new (CLAPPER_TYPE_ENHANCER_PROXY_LIST,
|
||||
"name", name, NULL);
|
||||
gst_object_ref_sink (list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_enhancer_proxy_list_take_proxy (ClapperEnhancerProxyList *self, ClapperEnhancerProxy *proxy)
|
||||
{
|
||||
g_ptr_array_add (self->proxies, proxy);
|
||||
gst_object_set_parent (GST_OBJECT_CAST (proxy), GST_OBJECT_CAST (self));
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancer_proxy_list_fill_from_global_proxies:
|
||||
*
|
||||
* Fill list with unconfigured proxies from global proxies list.
|
||||
*/
|
||||
void
|
||||
clapper_enhancer_proxy_list_fill_from_global_proxies (ClapperEnhancerProxyList *self)
|
||||
{
|
||||
ClapperEnhancerProxyList *global_list = clapper_get_global_enhancer_proxies ();
|
||||
static guint _list_id = 0;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < global_list->proxies->len; ++i) {
|
||||
ClapperEnhancerProxy *proxy, *proxy_copy;
|
||||
gchar obj_name[64];
|
||||
|
||||
proxy = clapper_enhancer_proxy_list_peek_proxy (global_list, i);
|
||||
|
||||
/* Name newly created proxy, very useful for debugging. Keep index per
|
||||
* list, so it will be the same as the player that proxy belongs to. */
|
||||
g_snprintf (obj_name, sizeof (obj_name), "%s-proxy%u",
|
||||
clapper_enhancer_proxy_get_friendly_name (proxy), _list_id);
|
||||
proxy_copy = clapper_enhancer_proxy_copy (proxy, obj_name);
|
||||
|
||||
clapper_enhancer_proxy_list_take_proxy (self, proxy_copy);
|
||||
}
|
||||
_list_id++;
|
||||
}
|
||||
|
||||
static gint
|
||||
_sort_values_by_name (ClapperEnhancerProxy *proxy_a, ClapperEnhancerProxy *proxy_b)
|
||||
{
|
||||
return g_ascii_strcasecmp (
|
||||
clapper_enhancer_proxy_get_friendly_name (proxy_a),
|
||||
clapper_enhancer_proxy_get_friendly_name (proxy_b));
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancer_proxy_list_sort:
|
||||
*
|
||||
* Sort all list elements by enhancer friendly name.
|
||||
*/
|
||||
void
|
||||
clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *self)
|
||||
{
|
||||
g_ptr_array_sort_values (self->proxies, (GCompareFunc) _sort_values_by_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_list_get_proxy:
|
||||
* @list: a #ClapperEnhancerProxyList
|
||||
* @index: an enhancer proxy index
|
||||
*
|
||||
* Get the #ClapperEnhancerProxy at index.
|
||||
*
|
||||
* This behaves the same as [method@Gio.ListModel.get_item], and is here
|
||||
* for code uniformity and convenience to avoid type casting by user.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): The #ClapperEnhancerProxy at @index.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
ClapperEnhancerProxy *
|
||||
clapper_enhancer_proxy_list_get_proxy (ClapperEnhancerProxyList *self, guint index)
|
||||
{
|
||||
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
|
||||
|
||||
return g_list_model_get_item (G_LIST_MODEL (self), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_list_peek_proxy: (skip)
|
||||
* @list: a #ClapperEnhancerProxyList
|
||||
* @index: an enhancer proxy index
|
||||
*
|
||||
* Get the #ClapperEnhancerProxy at index.
|
||||
*
|
||||
* Similar to [method@Clapper.EnhancerProxyList.get_proxy], but does not take
|
||||
* a new reference on proxy.
|
||||
*
|
||||
* Proxies in a list are only removed when a [class@Clapper.Player] instance
|
||||
* they originate from is destroyed, so do not use returned object afterwards
|
||||
* unless you take an additional reference on it.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): The #ClapperEnhancerProxy at @index.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
ClapperEnhancerProxy *
|
||||
clapper_enhancer_proxy_list_peek_proxy (ClapperEnhancerProxyList *self, guint index)
|
||||
{
|
||||
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
|
||||
|
||||
return g_ptr_array_index (self->proxies, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_list_get_proxy_by_module:
|
||||
* @list: a #ClapperEnhancerProxyList
|
||||
* @module_name: an enhancer module name
|
||||
*
|
||||
* Get the #ClapperEnhancerProxy by module name as defined in its plugin file.
|
||||
*
|
||||
* A convenience function to find a #ClapperEnhancerProxy by its unique
|
||||
* module name in the list.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): The #ClapperEnhancerProxy with requested module name.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
ClapperEnhancerProxy *
|
||||
clapper_enhancer_proxy_list_get_proxy_by_module (ClapperEnhancerProxyList *self, const gchar *module_name)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), NULL);
|
||||
g_return_val_if_fail (module_name != NULL, NULL);
|
||||
|
||||
for (i = 0; i < self->proxies->len; ++i) {
|
||||
ClapperEnhancerProxy *proxy = g_ptr_array_index (self->proxies, i);
|
||||
|
||||
if (strcmp (clapper_enhancer_proxy_get_module_name (proxy), module_name) == 0)
|
||||
return gst_object_ref (proxy);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_list_get_n_proxies:
|
||||
* @list: a #ClapperEnhancerProxyList
|
||||
*
|
||||
* Get the number of proxies in #ClapperEnhancerProxyList.
|
||||
*
|
||||
* This behaves the same as [method@Gio.ListModel.get_n_items], and is here
|
||||
* for code uniformity and convenience to avoid type casting by user.
|
||||
*
|
||||
* Returns: The number of proxies in #ClapperEnhancerProxyList.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
guint
|
||||
clapper_enhancer_proxy_list_get_n_proxies (ClapperEnhancerProxyList *self)
|
||||
{
|
||||
g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY_LIST (self), 0);
|
||||
|
||||
return g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
}
|
||||
|
||||
static void
|
||||
_proxy_remove_func (ClapperEnhancerProxy *proxy)
|
||||
{
|
||||
gst_object_unparent (GST_OBJECT_CAST (proxy));
|
||||
gst_object_unref (proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_proxy_list_init (ClapperEnhancerProxyList *self)
|
||||
{
|
||||
self->proxies = g_ptr_array_new_with_free_func ((GDestroyNotify) _proxy_remove_func);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_proxy_list_finalize (GObject *object)
|
||||
{
|
||||
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (object);
|
||||
|
||||
GST_TRACE_OBJECT (self, "Finalize");
|
||||
|
||||
g_ptr_array_unref (self->proxies);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_proxy_list_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
ClapperEnhancerProxyList *self = CLAPPER_ENHANCER_PROXY_LIST_CAST (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_N_PROXIES:
|
||||
g_value_set_uint (value, clapper_enhancer_proxy_list_get_n_proxies (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_proxy_list_class_init (ClapperEnhancerProxyListClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperenhancerproxylist", 0,
|
||||
"Clapper Enhancer Proxy List");
|
||||
|
||||
gobject_class->get_property = clapper_enhancer_proxy_list_get_property;
|
||||
gobject_class->finalize = clapper_enhancer_proxy_list_finalize;
|
||||
|
||||
/**
|
||||
* ClapperEnhancerProxyList:n-proxies:
|
||||
*
|
||||
* Number of proxies in the list.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
param_specs[PROP_N_PROXIES] = g_param_spec_uint ("n-proxies",
|
||||
NULL, NULL, 0, G_MAXUINT, 0,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
|
||||
}
|
53
src/lib/clapper/clapper-enhancer-proxy-list.h
Normal file
53
src/lib/clapper/clapper-enhancer-proxy-list.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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
|
||||
|
||||
#if !defined(__CLAPPER_INSIDE__) && !defined(CLAPPER_COMPILATION)
|
||||
#error "Only <clapper/clapper.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <clapper/clapper-visibility.h>
|
||||
#include <clapper/clapper-enhancer-proxy.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLAPPER_TYPE_ENHANCER_PROXY_LIST (clapper_enhancer_proxy_list_get_type())
|
||||
#define CLAPPER_ENHANCER_PROXY_LIST_CAST(obj) ((ClapperEnhancerProxyList *)(obj))
|
||||
|
||||
CLAPPER_API
|
||||
G_DECLARE_FINAL_TYPE (ClapperEnhancerProxyList, clapper_enhancer_proxy_list, CLAPPER, ENHANCER_PROXY_LIST, GstObject)
|
||||
|
||||
CLAPPER_API
|
||||
ClapperEnhancerProxy * clapper_enhancer_proxy_list_get_proxy (ClapperEnhancerProxyList *list, guint index);
|
||||
|
||||
CLAPPER_API
|
||||
ClapperEnhancerProxy * clapper_enhancer_proxy_list_peek_proxy (ClapperEnhancerProxyList *list, guint index);
|
||||
|
||||
CLAPPER_API
|
||||
ClapperEnhancerProxy * clapper_enhancer_proxy_list_get_proxy_by_module (ClapperEnhancerProxyList *list, const gchar *module_name);
|
||||
|
||||
CLAPPER_API
|
||||
guint clapper_enhancer_proxy_list_get_n_proxies (ClapperEnhancerProxyList *list);
|
||||
|
||||
G_END_DECLS
|
47
src/lib/clapper/clapper-enhancer-proxy-private.h
Normal file
47
src/lib/clapper/clapper-enhancer-proxy-private.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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>
|
||||
|
||||
#include "clapper-enhancer-proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
ClapperEnhancerProxy * clapper_enhancer_proxy_new_global_take (GObject *peas_info); // Using parent type for building without libpeas
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
ClapperEnhancerProxy * clapper_enhancer_proxy_copy (ClapperEnhancerProxy *src_proxy, const gchar *copy_name);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
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
|
||||
GObject * clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *proxy);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancer_proxy_apply_current_config_to_enhancer (ClapperEnhancerProxy *proxy, GObject *enhancer);
|
||||
|
||||
G_END_DECLS
|
1035
src/lib/clapper/clapper-enhancer-proxy.c
Normal file
1035
src/lib/clapper/clapper-enhancer-proxy.c
Normal file
File diff suppressed because it is too large
Load Diff
80
src/lib/clapper/clapper-enhancer-proxy.h
Normal file
80
src/lib/clapper/clapper-enhancer-proxy.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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
|
||||
|
||||
#if !defined(__CLAPPER_INSIDE__) && !defined(CLAPPER_COMPILATION)
|
||||
#error "Only <clapper/clapper.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <clapper/clapper-visibility.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLAPPER_TYPE_ENHANCER_PROXY (clapper_enhancer_proxy_get_type())
|
||||
#define CLAPPER_ENHANCER_PROXY_CAST(obj) ((ClapperEnhancerProxy *)(obj))
|
||||
|
||||
CLAPPER_API
|
||||
G_DECLARE_FINAL_TYPE (ClapperEnhancerProxy, clapper_enhancer_proxy, CLAPPER, ENHANCER_PROXY, GstObject)
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_friendly_name (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_module_name (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_module_dir (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_description (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_version (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
const gchar * clapper_enhancer_proxy_get_extra_data (ClapperEnhancerProxy *proxy, const gchar *key);
|
||||
|
||||
CLAPPER_API
|
||||
gboolean clapper_enhancer_proxy_extra_data_lists_value (ClapperEnhancerProxy *proxy, const gchar *key, const gchar *value);
|
||||
|
||||
CLAPPER_API
|
||||
GType * clapper_enhancer_proxy_get_target_interfaces (ClapperEnhancerProxy *proxy, guint *n_interfaces);
|
||||
|
||||
CLAPPER_API
|
||||
gboolean clapper_enhancer_proxy_target_has_interface (ClapperEnhancerProxy *proxy, GType iface_type);
|
||||
|
||||
CLAPPER_API
|
||||
GParamSpec ** clapper_enhancer_proxy_get_target_properties (ClapperEnhancerProxy *proxy, guint *n_properties);
|
||||
|
||||
CLAPPER_API
|
||||
GSettings * clapper_enhancer_proxy_get_settings (ClapperEnhancerProxy *proxy);
|
||||
|
||||
CLAPPER_API
|
||||
void clapper_enhancer_proxy_set_locally (ClapperEnhancerProxy *proxy, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
CLAPPER_API
|
||||
void clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *proxy, GHashTable *table);
|
||||
|
||||
G_END_DECLS
|
@@ -22,21 +22,15 @@
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "clapper-enhancer-proxy-list.h"
|
||||
#include "clapper-enhancer-proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancers_loader_initialize (void);
|
||||
void clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean clapper_enhancers_loader_has_enhancers (GType iface_type);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gchar ** clapper_enhancers_loader_get_schemes (GType iface_type);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean clapper_enhancers_loader_check (GType iface_type, const gchar *scheme, const gchar *host, const gchar **name);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GObject * clapper_enhancers_loader_create_enhancer_for_uri (GType iface_type, GUri *uri);
|
||||
GObject * clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -28,11 +28,13 @@ static HMODULE _enhancers_dll_handle = NULL;
|
||||
#endif
|
||||
|
||||
#include "clapper-enhancers-loader-private.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "clapper-enhancer-proxy-private.h"
|
||||
|
||||
// Supported interfaces
|
||||
#include "clapper-extractable.h"
|
||||
|
||||
#define ENHANCER_INTERFACES "X-Interfaces"
|
||||
#define ENHANCER_SCHEMES "X-Schemes"
|
||||
#define ENHANCER_HOSTS "X-Hosts"
|
||||
#define ENHANCER_IFACE_NAME_FROM_TYPE(type) (g_type_name (type) + 7) // strip "Clapper" prefix
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_enhancers_loader_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
@@ -58,10 +60,11 @@ _import_enhancers (const gchar *enhancers_path)
|
||||
* Initializes #PeasEngine with directories that store enhancers.
|
||||
*/
|
||||
void
|
||||
clapper_enhancers_loader_initialize (void)
|
||||
clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
|
||||
{
|
||||
const gchar *enhancers_path;
|
||||
gchar *custom_path = NULL;
|
||||
guint i, n_items;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperenhancersloader", 0,
|
||||
"Clapper Enhancer Loader");
|
||||
@@ -104,321 +107,83 @@ clapper_enhancers_loader_initialize (void)
|
||||
_import_enhancers (enhancers_path);
|
||||
}
|
||||
|
||||
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_INFO) {
|
||||
GListModel *list = (GListModel *) _engine;
|
||||
guint i, n_items = g_list_model_get_n_items (list);
|
||||
n_items = g_list_model_get_n_items ((GListModel *) _engine);
|
||||
for (i = 0; i < n_items; ++i) {
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item ((GListModel *) _engine, i);
|
||||
ClapperEnhancerProxy *proxy;
|
||||
gboolean filled;
|
||||
|
||||
for (i = 0; i < n_items; ++i) {
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
|
||||
GST_INFO ("Found enhancer: %s (%s)", peas_plugin_info_get_name (info),
|
||||
peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES));
|
||||
g_object_unref (info);
|
||||
/* Clapper supports only 1 proxy per plugin. Each plugin can
|
||||
* ship 1 class, but it can implement more than 1 interface. */
|
||||
proxy = clapper_enhancer_proxy_new_global_take ((GObject *) info);
|
||||
|
||||
/* Try to fill missing data from cache (fast).
|
||||
* Otherwise make an instance and fill missing data from it (slow). */
|
||||
if (!(filled = clapper_enhancer_proxy_fill_from_cache (proxy))) {
|
||||
GObject *enhancer;
|
||||
GType main_types[1] = { CLAPPER_TYPE_EXTRACTABLE };
|
||||
guint j;
|
||||
|
||||
/* 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]))) {
|
||||
filled = clapper_enhancer_proxy_fill_from_instance (proxy, enhancer);
|
||||
g_object_unref (enhancer);
|
||||
|
||||
GST_FIXME_OBJECT (proxy, "Save enhancer proxy data to cache");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_INFO ("Clapper enhancers initialized, found: %u", n_items);
|
||||
if (G_LIKELY (filled)) {
|
||||
GST_INFO ("Found enhancer: %s (%s)", clapper_enhancer_proxy_get_friendly_name (proxy),
|
||||
clapper_enhancer_proxy_get_extra_data (proxy, ENHANCER_INTERFACES));
|
||||
clapper_enhancer_proxy_list_take_proxy (proxies, proxy);
|
||||
} else {
|
||||
GST_WARNING ("Enhancer \"%s\" init failed, skipping it",
|
||||
clapper_enhancer_proxy_get_friendly_name (proxy));
|
||||
gst_object_unref (proxy);
|
||||
}
|
||||
}
|
||||
|
||||
clapper_enhancer_proxy_list_sort (proxies);
|
||||
|
||||
GST_INFO ("Clapper enhancers initialized, found: %u",
|
||||
clapper_enhancer_proxy_list_get_n_proxies (proxies));
|
||||
|
||||
g_free (custom_path);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_is_name_listed (const gchar *name, const gchar *list_str)
|
||||
{
|
||||
gsize name_len = strlen (name);
|
||||
guint i = 0;
|
||||
|
||||
while (list_str[i] != '\0') {
|
||||
guint end = i;
|
||||
|
||||
while (list_str[end] != ';' && list_str[end] != '\0')
|
||||
++end;
|
||||
|
||||
/* Compare letters count until separator and prefix of whole string */
|
||||
if (end - i == name_len && g_str_has_prefix (list_str + i, name))
|
||||
return TRUE;
|
||||
|
||||
i = end;
|
||||
|
||||
/* Move to the next letter after ';' */
|
||||
if (list_str[i] != '\0')
|
||||
++i;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancers_loader_get_info:
|
||||
* @iface_type: an interface #GType
|
||||
* @scheme: an URI scheme
|
||||
* @host: (nullable): an URI host
|
||||
*
|
||||
* Returns: (transfer full) (nullable): available #PeasPluginInfo or %NULL.
|
||||
*/
|
||||
static PeasPluginInfo *
|
||||
clapper_enhancers_loader_get_info (GType iface_type, const gchar *scheme, const gchar *host)
|
||||
{
|
||||
GListModel *list = (GListModel *) _engine;
|
||||
PeasPluginInfo *found_info = NULL;
|
||||
guint i, n_plugins = g_list_model_get_n_items (list);
|
||||
const gchar *iface_name;
|
||||
gboolean is_https;
|
||||
|
||||
if (n_plugins == 0) {
|
||||
GST_INFO ("No Clapper enhancers found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
|
||||
|
||||
/* Strip common subdomains, so plugins do not
|
||||
* have to list all combinations */
|
||||
if (host) {
|
||||
if (g_str_has_prefix (host, "www."))
|
||||
host += 4;
|
||||
else if (g_str_has_prefix (host, "m."))
|
||||
host += 2;
|
||||
}
|
||||
|
||||
GST_INFO ("Enhancer check, iface: %s, scheme: %s, host: %s",
|
||||
iface_name, scheme, GST_STR_NULL (host));
|
||||
|
||||
is_https = (g_str_has_prefix (scheme, "http")
|
||||
&& (scheme[4] == '\0' || (scheme[4] == 's' && scheme[5] == '\0')));
|
||||
|
||||
if (!host && is_https)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < n_plugins; ++i) {
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
|
||||
const gchar *iface_names, *schemes, *hosts;
|
||||
|
||||
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
|
||||
GST_DEBUG ("Skipping enhancer without interfaces: %s", peas_plugin_info_get_name (info));
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!_is_name_listed (iface_name, iface_names)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!(schemes = peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES))) {
|
||||
GST_DEBUG ("Skipping enhancer without schemes: %s", peas_plugin_info_get_name (info));
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!_is_name_listed (scheme, schemes)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (is_https) {
|
||||
if (!(hosts = peas_plugin_info_get_external_data (info, ENHANCER_HOSTS))) {
|
||||
GST_DEBUG ("Skipping enhancer without hosts: %s", peas_plugin_info_get_name (info));
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!_is_name_listed (host, hosts)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
found_info = info;
|
||||
break;
|
||||
}
|
||||
|
||||
return found_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancers_loader_has_enhancers:
|
||||
* @iface_type: an interface #GType
|
||||
*
|
||||
* Check if any enhancer implementing given interface type is available.
|
||||
*
|
||||
* Returns: whether any valid enhancer was found.
|
||||
*/
|
||||
gboolean
|
||||
clapper_enhancers_loader_has_enhancers (GType iface_type)
|
||||
{
|
||||
GListModel *list = (GListModel *) _engine;
|
||||
const gchar *iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
|
||||
guint i, n_plugins;
|
||||
|
||||
GST_DEBUG ("Checking for any enhancers of type: \"%s\"", iface_name);
|
||||
|
||||
n_plugins = g_list_model_get_n_items (list);
|
||||
|
||||
for (i = 0; i < n_plugins; ++i) {
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
|
||||
const gchar *iface_names;
|
||||
|
||||
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!_is_name_listed (iface_name, iface_names)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Additional validation */
|
||||
if (!peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES)
|
||||
|| !peas_plugin_info_get_external_data (info, ENHANCER_HOSTS)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Found valid enhancers of type: \"%s\"", iface_name);
|
||||
g_object_unref (info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("No available enhancers of type: \"%s\"", iface_name);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancers_loader_get_schemes:
|
||||
* @iface_type: an interface #GType
|
||||
*
|
||||
* Get all supported schemes for a given interface type.
|
||||
* The returned array consists of unique strings (no duplicates).
|
||||
*
|
||||
* Returns: (transfer full): all supported schemes by enhancers of type.
|
||||
*/
|
||||
gchar **
|
||||
clapper_enhancers_loader_get_schemes (GType iface_type)
|
||||
{
|
||||
GListModel *list = (GListModel *) _engine;
|
||||
GSList *found_schemes = NULL, *fs;
|
||||
const gchar *iface_name = ENHANCER_IFACE_NAME_FROM_TYPE (iface_type);
|
||||
gchar **schemes_strv;
|
||||
guint i, n_plugins, n_schemes;
|
||||
|
||||
GST_DEBUG ("Checking supported URI schemes for \"%s\"", iface_name);
|
||||
|
||||
n_plugins = g_list_model_get_n_items (list);
|
||||
|
||||
for (i = 0; i < n_plugins; ++i) {
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) g_list_model_get_item (list, i);
|
||||
const gchar *iface_names, *schemes;
|
||||
gchar **tmp_strv;
|
||||
gint j;
|
||||
|
||||
if (!(iface_names = peas_plugin_info_get_external_data (info, ENHANCER_INTERFACES))) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!_is_name_listed (iface_name, iface_names)) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
if (!(schemes = peas_plugin_info_get_external_data (info, ENHANCER_SCHEMES))) {
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp_strv = g_strsplit (schemes, ";", 0);
|
||||
|
||||
for (j = 0; tmp_strv[j]; ++j) {
|
||||
const gchar *scheme = tmp_strv[j];
|
||||
|
||||
if (!found_schemes || !g_slist_find_custom (found_schemes,
|
||||
scheme, (GCompareFunc) strcmp)) {
|
||||
found_schemes = g_slist_append (found_schemes, g_strdup (scheme));
|
||||
GST_INFO ("Found supported URI scheme: %s", scheme);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (tmp_strv);
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
n_schemes = g_slist_length (found_schemes);
|
||||
schemes_strv = g_new0 (gchar *, n_schemes + 1);
|
||||
|
||||
fs = found_schemes;
|
||||
for (i = 0; i < n_schemes; ++i) {
|
||||
schemes_strv[i] = fs->data;
|
||||
fs = fs->next;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Total found URI schemes: %u", n_schemes);
|
||||
|
||||
/* Since string pointers were taken,
|
||||
* free list without content */
|
||||
g_slist_free (found_schemes);
|
||||
|
||||
return schemes_strv;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancers_loader_check:
|
||||
* clapper_enhancers_loader_create_enhancer:
|
||||
* @iface_type: a requested #GType
|
||||
* @scheme: an URI scheme
|
||||
* @host: (nullable): an URI host
|
||||
* @name: (out) (optional) (transfer none): return location for found enhancer name
|
||||
* @info: a #PeasPluginInfo
|
||||
*
|
||||
* Checks if any enhancer can handle @uri without initializing loader
|
||||
* or creating enhancer instance, thus this can be used freely from any thread.
|
||||
*
|
||||
* Returns: whether enhancer for given scheme and host is available.
|
||||
*/
|
||||
gboolean
|
||||
clapper_enhancers_loader_check (GType iface_type,
|
||||
const gchar *scheme, const gchar *host, const gchar **name)
|
||||
{
|
||||
PeasPluginInfo *info;
|
||||
|
||||
if ((info = clapper_enhancers_loader_get_info (iface_type, scheme, host))) {
|
||||
if (name)
|
||||
*name = peas_plugin_info_get_name (info);
|
||||
|
||||
g_object_unref (info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancers_loader_create_enhancer_for_uri:
|
||||
* @iface_type: a requested #GType
|
||||
* @uri: a #GUri
|
||||
*
|
||||
* Creates a new enhancer object for given URI.
|
||||
* Creates a new enhancer object using @info.
|
||||
*
|
||||
* Enhancer should only be created and used within single thread.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a new enhancer instance.
|
||||
*/
|
||||
GObject *
|
||||
clapper_enhancers_loader_create_enhancer_for_uri (GType iface_type, GUri *uri)
|
||||
clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type)
|
||||
{
|
||||
GObject *enhancer = NULL;
|
||||
PeasPluginInfo *info;
|
||||
const gchar *scheme = g_uri_get_scheme (uri);
|
||||
const gchar *host = g_uri_get_host (uri);
|
||||
PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy);
|
||||
|
||||
if ((info = clapper_enhancers_loader_get_info (iface_type, scheme, host))) {
|
||||
g_mutex_lock (&load_lock);
|
||||
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_name (info));
|
||||
} else if (!peas_engine_provides_extension (_engine, info, iface_type)) {
|
||||
GST_ERROR ("No \"%s\" enhancer in plugin: %s", ENHANCER_IFACE_NAME_FROM_TYPE (iface_type),
|
||||
peas_plugin_info_get_name (info));
|
||||
} else {
|
||||
enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&load_lock);
|
||||
g_object_unref (info);
|
||||
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;
|
||||
}
|
||||
|
@@ -127,4 +127,28 @@ typedef enum
|
||||
CLAPPER_DISCOVERER_DISCOVERY_NONCURRENT,
|
||||
} ClapperDiscovererDiscoveryMode;
|
||||
|
||||
/* NOTE: GStreamer uses param flags 8-16, so start with 17. */
|
||||
/**
|
||||
* ClapperEnhancerParamFlags:
|
||||
* @CLAPPER_ENHANCER_PARAM_GLOBAL: Use this flag for enhancer properties that should have global access scope.
|
||||
* Such are meant for application `USER` to configure.
|
||||
* @CLAPPER_ENHANCER_PARAM_LOCAL: Use this flag for enhancer properties that should have local access scope.
|
||||
* Such are meant for `APPLICATION` to configure.
|
||||
* @CLAPPER_ENHANCER_PARAM_FILEPATH: Use this flag for enhancer properties that store string with a file path.
|
||||
* Applications can use this as a hint to show file selection instead of a text entry.
|
||||
* @CLAPPER_ENHANCER_PARAM_DIRPATH: Use this flag for enhancer properties that store string with a directory path.
|
||||
* Applications can use this as a hint to show directory selection instead of a text entry.
|
||||
*
|
||||
* Additional [flags@GObject.ParamFlags] to be set in enhancer plugins implementations.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CLAPPER_ENHANCER_PARAM_GLOBAL = 1 << 17,
|
||||
CLAPPER_ENHANCER_PARAM_LOCAL = 1 << 18,
|
||||
CLAPPER_ENHANCER_PARAM_FILEPATH = 1 << 19,
|
||||
CLAPPER_ENHANCER_PARAM_DIRPATH = 1 << 20,
|
||||
} ClapperEnhancerParamFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -47,6 +47,8 @@ struct _ClapperPlayer
|
||||
ClapperFeaturesManager *features_manager;
|
||||
gint have_features; // atomic integer
|
||||
|
||||
ClapperEnhancerProxyList *enhancer_proxies;
|
||||
|
||||
/* This is different from queue current item as it is used/changed only
|
||||
* on player thread, so we can always update correct item without lock */
|
||||
ClapperMediaItem *played_item;
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include "clapper-video-stream-private.h"
|
||||
#include "clapper-audio-stream-private.h"
|
||||
#include "clapper-subtitle-stream-private.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "clapper-enums-private.h"
|
||||
#include "clapper-utils-private.h"
|
||||
#include "../shared/clapper-shared-utils-private.h"
|
||||
@@ -77,6 +78,7 @@ enum
|
||||
PROP_VIDEO_STREAMS,
|
||||
PROP_AUDIO_STREAMS,
|
||||
PROP_SUBTITLE_STREAMS,
|
||||
PROP_ENHANCER_PROXIES,
|
||||
PROP_AUTOPLAY,
|
||||
PROP_POSITION,
|
||||
PROP_SPEED,
|
||||
@@ -814,7 +816,11 @@ _element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self
|
||||
factory_name = g_intern_static_string (GST_OBJECT_NAME (factory));
|
||||
GST_INFO_OBJECT (self, "Element setup: %s", factory_name);
|
||||
|
||||
if (factory_name == g_intern_static_string ("downloadbuffer")) {
|
||||
if (factory_name == g_intern_static_string ("clapperenhancersrc")) {
|
||||
g_object_set (element,
|
||||
"enhancer-proxies", self->enhancer_proxies,
|
||||
NULL);
|
||||
} else if (factory_name == g_intern_static_string ("downloadbuffer")) {
|
||||
gchar *download_template;
|
||||
|
||||
/* Only set props if we have download template */
|
||||
@@ -1129,6 +1135,24 @@ clapper_player_get_subtitle_streams (ClapperPlayer *self)
|
||||
return self->subtitle_streams;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_player_get_enhancer_proxies:
|
||||
* @player: a #ClapperPlayer
|
||||
*
|
||||
* Get a list of available enhancers in the form of [class@Clapper.EnhancerProxy] objects.
|
||||
*
|
||||
* Returns: (transfer none): a #ClapperEnhancerProxyList of enhancer proxies.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
ClapperEnhancerProxyList *
|
||||
clapper_player_get_enhancer_proxies (ClapperPlayer *self)
|
||||
{
|
||||
g_return_val_if_fail (CLAPPER_IS_PLAYER (self), NULL);
|
||||
|
||||
return self->enhancer_proxies;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_player_set_autoplay:
|
||||
* @player: a #ClapperPlayer
|
||||
@@ -2297,6 +2321,11 @@ clapper_player_init (ClapperPlayer *self)
|
||||
self->subtitle_streams = clapper_stream_list_new ();
|
||||
gst_object_set_parent (GST_OBJECT_CAST (self->subtitle_streams), GST_OBJECT_CAST (self));
|
||||
|
||||
self->enhancer_proxies = clapper_enhancer_proxy_list_new_named (NULL);
|
||||
gst_object_set_parent (GST_OBJECT_CAST (self->enhancer_proxies), GST_OBJECT_CAST (self));
|
||||
|
||||
clapper_enhancer_proxy_list_fill_from_global_proxies (self->enhancer_proxies);
|
||||
|
||||
self->position_query = gst_query_new_position (GST_FORMAT_TIME);
|
||||
|
||||
self->current_state = GST_STATE_NULL;
|
||||
@@ -2363,6 +2392,9 @@ clapper_player_finalize (GObject *object)
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->subtitle_streams));
|
||||
gst_object_unref (self->subtitle_streams);
|
||||
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->enhancer_proxies));
|
||||
gst_object_unref (self->enhancer_proxies);
|
||||
|
||||
gst_query_unref (self->position_query);
|
||||
|
||||
gst_clear_object (&self->collection);
|
||||
@@ -2394,6 +2426,9 @@ clapper_player_get_property (GObject *object, guint prop_id,
|
||||
case PROP_SUBTITLE_STREAMS:
|
||||
g_value_set_object (value, clapper_player_get_subtitle_streams (self));
|
||||
break;
|
||||
case PROP_ENHANCER_PROXIES:
|
||||
g_value_set_object (value, clapper_player_get_enhancer_proxies (self));
|
||||
break;
|
||||
case PROP_AUTOPLAY:
|
||||
g_value_set_boolean (value, clapper_player_get_autoplay (self));
|
||||
break;
|
||||
@@ -2593,6 +2628,20 @@ clapper_player_class_init (ClapperPlayerClass *klass)
|
||||
NULL, NULL, CLAPPER_TYPE_STREAM_LIST,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* ClapperPlayer:enhancer-proxies:
|
||||
*
|
||||
* List of available enhancers in the form of [class@Clapper.EnhancerProxy] objects.
|
||||
*
|
||||
* Use these to inspect available enhancers on the system and configure
|
||||
* their properties on a per player instance basis.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
param_specs[PROP_ENHANCER_PROXIES] = g_param_spec_object ("enhancer-proxies",
|
||||
NULL, NULL, CLAPPER_TYPE_ENHANCER_PROXY_LIST,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* ClapperPlayer:autoplay:
|
||||
*
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include <clapper/clapper-threaded-object.h>
|
||||
#include <clapper/clapper-queue.h>
|
||||
#include <clapper/clapper-stream-list.h>
|
||||
#include <clapper/clapper-enhancer-proxy-list.h>
|
||||
#include <clapper/clapper-feature.h>
|
||||
#include <clapper/clapper-enums.h>
|
||||
|
||||
@@ -57,6 +58,9 @@ ClapperStreamList * clapper_player_get_audio_streams (ClapperPlayer *player);
|
||||
CLAPPER_API
|
||||
ClapperStreamList * clapper_player_get_subtitle_streams (ClapperPlayer *player);
|
||||
|
||||
CLAPPER_API
|
||||
ClapperEnhancerProxyList * clapper_player_get_enhancer_proxies (ClapperPlayer *player);
|
||||
|
||||
CLAPPER_API
|
||||
void clapper_player_set_autoplay (ClapperPlayer *player, gboolean enabled);
|
||||
|
||||
|
@@ -27,12 +27,14 @@
|
||||
#include "clapper-playbin-bus-private.h"
|
||||
#include "clapper-app-bus-private.h"
|
||||
#include "clapper-features-bus-private.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "gst/clapper-plugin-private.h"
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
#include "clapper-enhancers-loader-private.h"
|
||||
#endif
|
||||
|
||||
static ClapperEnhancerProxyList *_proxies = NULL;
|
||||
static gboolean is_initialized = FALSE;
|
||||
static GMutex init_lock;
|
||||
|
||||
@@ -51,8 +53,10 @@ clapper_init_check_internal (int *argc, char **argv[])
|
||||
clapper_app_bus_initialize ();
|
||||
clapper_features_bus_initialize ();
|
||||
|
||||
_proxies = clapper_enhancer_proxy_list_new_named ("global-proxy-list");
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
clapper_enhancers_loader_initialize ();
|
||||
clapper_enhancers_loader_initialize (_proxies);
|
||||
#endif
|
||||
|
||||
gst_plugin_register_static (
|
||||
@@ -149,18 +153,75 @@ clapper_init_check (int *argc, char **argv[])
|
||||
* Returns: whether a plausible enhancer was found.
|
||||
*
|
||||
* Since: 0.8
|
||||
*
|
||||
* Deprecated: 0.10: Use list of enhancer proxies from [func@Clapper.get_global_enhancer_proxies] or
|
||||
* [property@Clapper.Player:enhancer-proxies] and check if any proxy matches your search criteria.
|
||||
*/
|
||||
gboolean
|
||||
clapper_enhancer_check (GType iface_type, const gchar *scheme, const gchar *host, const gchar **name)
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
gboolean is_https;
|
||||
guint i, n_proxies;
|
||||
|
||||
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_type), FALSE);
|
||||
g_return_val_if_fail (scheme != NULL, FALSE);
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
success = clapper_enhancers_loader_check (iface_type, scheme, host, name);
|
||||
#endif
|
||||
if (host) {
|
||||
/* Strip common subdomains, so plugins do not
|
||||
* have to list all combinations */
|
||||
if (g_str_has_prefix (host, "www."))
|
||||
host += 4;
|
||||
else if (g_str_has_prefix (host, "m."))
|
||||
host += 2;
|
||||
}
|
||||
|
||||
return success;
|
||||
/* Whether "http(s)" scheme is used */
|
||||
is_https = (g_str_has_prefix (scheme, "http")
|
||||
&& (scheme[4] == '\0' || (scheme[4] == 's' && scheme[5] == '\0')));
|
||||
|
||||
if (!host && is_https)
|
||||
return FALSE;
|
||||
|
||||
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (_proxies);
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (_proxies, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, iface_type)
|
||||
&& clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Schemes", scheme)
|
||||
&& (!is_https || clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Hosts", host))) {
|
||||
if (name)
|
||||
*name = clapper_enhancer_proxy_get_friendly_name (proxy);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_get_global_enhancer_proxies:
|
||||
*
|
||||
* Get a list of available enhancers in the form of [class@Clapper.EnhancerProxy] objects.
|
||||
*
|
||||
* This returns a global list of enhancer proxy objects. You can use it to inspect
|
||||
* available enhancers without creating a new player instance.
|
||||
*
|
||||
* Remember to initialize Clapper library before using this function.
|
||||
*
|
||||
* Only enhancer properties with [flags@Clapper.EnhancerParamFlags.GLOBAL] flag can be
|
||||
* set on proxies in this list. These are meant to be set ONLY by users, not applications
|
||||
* as they carry over to all player instances (possibly including other apps). Applications
|
||||
* should instead be changing properties with [flags@Clapper.EnhancerParamFlags.LOCAL] flag
|
||||
* set from individual proxy lists from [property@Clapper.Player:enhancer-proxies] which
|
||||
* will affect only that single player instance given list belongs to.
|
||||
*
|
||||
* Returns: (transfer none): a global #ClapperEnhancerProxyList of enhancer proxies.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
ClapperEnhancerProxyList *
|
||||
clapper_get_global_enhancer_proxies (void)
|
||||
{
|
||||
return _proxies;
|
||||
}
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <clapper/clapper-version.h>
|
||||
|
||||
#include <clapper/clapper-audio-stream.h>
|
||||
#include <clapper/clapper-enhancer-proxy.h>
|
||||
#include <clapper/clapper-enhancer-proxy-list.h>
|
||||
#include <clapper/clapper-feature.h>
|
||||
#include <clapper/clapper-harvest.h>
|
||||
#include <clapper/clapper-marker.h>
|
||||
@@ -67,9 +69,12 @@ void clapper_init (int *argc, char **argv[]);
|
||||
CLAPPER_API
|
||||
gboolean clapper_init_check (int *argc, char **argv[]);
|
||||
|
||||
CLAPPER_API
|
||||
CLAPPER_DEPRECATED
|
||||
gboolean clapper_enhancer_check (GType iface_type, const gchar *scheme, const gchar *host, const gchar **name);
|
||||
|
||||
CLAPPER_API
|
||||
ClapperEnhancerProxyList * clapper_get_global_enhancer_proxies (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#undef __CLAPPER_INSIDE__
|
||||
|
@@ -38,6 +38,6 @@ G_GNUC_INTERNAL
|
||||
ClapperEnhancerDirector * clapper_enhancer_director_new (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
ClapperHarvest * clapper_enhancer_director_extract (ClapperEnhancerDirector *director, GUri *uri, GCancellable *cancellable, GError **error);
|
||||
ClapperHarvest * clapper_enhancer_director_extract (ClapperEnhancerDirector *director, GList *filtered_proxies, GUri *uri, GCancellable *cancellable, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -20,11 +20,17 @@
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "clapper-enhancer-director-private.h"
|
||||
#include "../clapper-enhancers-loader-private.h"
|
||||
#include "../clapper-enhancer-proxy-private.h"
|
||||
#include "../clapper-extractable-private.h"
|
||||
#include "../clapper-harvest-private.h"
|
||||
#include "../../shared/clapper-shared-utils-private.h"
|
||||
|
||||
#include "../clapper-functionalities-availability.h"
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
#include "../clapper-enhancers-loader-private.h"
|
||||
#endif
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_enhancer_director_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
@@ -38,6 +44,8 @@ G_DEFINE_TYPE (ClapperEnhancerDirector, clapper_enhancer_director, CLAPPER_TYPE_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ClapperEnhancerDirector *director;
|
||||
GList *filtered_proxies;
|
||||
GUri *uri;
|
||||
GCancellable *cancellable;
|
||||
GError **error;
|
||||
@@ -46,37 +54,61 @@ typedef struct
|
||||
static gpointer
|
||||
clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
|
||||
{
|
||||
ClapperExtractable *extractable = NULL;
|
||||
ClapperHarvest *harvest = clapper_harvest_new ();
|
||||
ClapperEnhancerDirector *self = data->director;
|
||||
GList *el;
|
||||
ClapperHarvest *harvest = NULL;
|
||||
gboolean success = FALSE, cached = FALSE;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Extraction start");
|
||||
|
||||
/* Cancelled during thread switching */
|
||||
if (g_cancellable_is_cancelled (data->cancellable))
|
||||
goto finish;
|
||||
return NULL;
|
||||
|
||||
/* TODO: Cache lookup */
|
||||
if (cached) {
|
||||
// success = fill harvest from cache
|
||||
goto finish;
|
||||
// if ((success = fill harvest from cache))
|
||||
// return harvest;
|
||||
}
|
||||
|
||||
extractable = CLAPPER_EXTRACTABLE_CAST (clapper_enhancers_loader_create_enhancer_for_uri (
|
||||
CLAPPER_TYPE_EXTRACTABLE, data->uri));
|
||||
GST_DEBUG_OBJECT (self, "Enhancer proxies for URI: %u",
|
||||
g_list_length (data->filtered_proxies));
|
||||
|
||||
/* Check just before extract */
|
||||
if (g_cancellable_is_cancelled (data->cancellable))
|
||||
goto finish;
|
||||
for (el = data->filtered_proxies; el; el = g_list_next (el)) {
|
||||
ClapperEnhancerProxy *proxy = CLAPPER_ENHANCER_PROXY_CAST (el->data);
|
||||
ClapperExtractable *extractable = NULL;
|
||||
|
||||
success = clapper_extractable_extract (extractable, data->uri,
|
||||
harvest, data->cancellable, data->error);
|
||||
/* Check just before extract */
|
||||
if (g_cancellable_is_cancelled (data->cancellable))
|
||||
break;
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
extractable = CLAPPER_EXTRACTABLE_CAST (
|
||||
clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_EXTRACTABLE));
|
||||
#endif
|
||||
|
||||
if (G_LIKELY (extractable != NULL)) {
|
||||
clapper_enhancer_proxy_apply_current_config_to_enhancer (proxy, (GObject *) extractable);
|
||||
|
||||
harvest = clapper_harvest_new (); // fresh harvest for each extractable
|
||||
|
||||
success = clapper_extractable_extract (extractable, data->uri,
|
||||
harvest, data->cancellable, data->error);
|
||||
gst_object_unref (extractable);
|
||||
|
||||
/* We are done with extractable, but keep its harvest */
|
||||
if (success)
|
||||
break;
|
||||
|
||||
/* Clear harvest and try again with next enhancer */
|
||||
g_clear_object (&harvest);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancelled during extract */
|
||||
if (g_cancellable_is_cancelled (data->cancellable)) {
|
||||
if (g_cancellable_is_cancelled (data->cancellable))
|
||||
success = FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (success) {
|
||||
if (!cached) {
|
||||
/* TODO: Store in cache */
|
||||
@@ -94,7 +126,7 @@ finish:
|
||||
}
|
||||
}
|
||||
|
||||
gst_clear_object (&extractable);
|
||||
GST_DEBUG_OBJECT (self, "Extraction finish");
|
||||
|
||||
return harvest;
|
||||
}
|
||||
@@ -116,11 +148,14 @@ clapper_enhancer_director_new (void)
|
||||
}
|
||||
|
||||
ClapperHarvest *
|
||||
clapper_enhancer_director_extract (ClapperEnhancerDirector *self, GUri *uri,
|
||||
clapper_enhancer_director_extract (ClapperEnhancerDirector *self,
|
||||
GList *filtered_proxies, GUri *uri,
|
||||
GCancellable *cancellable, GError **error)
|
||||
{
|
||||
ClapperEnhancerDirectorData *data = g_new (ClapperEnhancerDirectorData, 1);
|
||||
|
||||
data->director = self;
|
||||
data->filtered_proxies = filtered_proxies;
|
||||
data->uri = uri;
|
||||
data->cancellable = cancellable;
|
||||
data->error = error;
|
||||
|
@@ -22,13 +22,17 @@
|
||||
#include "clapper-enhancer-src-private.h"
|
||||
#include "clapper-enhancer-director-private.h"
|
||||
|
||||
#include "../clapper.h"
|
||||
#include "../clapper-enhancer-proxy-list-private.h"
|
||||
#include "../clapper-extractable-private.h"
|
||||
#include "../clapper-harvest-private.h"
|
||||
#include "../clapper-enhancers-loader-private.h"
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_enhancer_src_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
#define CHECK_SCHEME_IS_HTTPS(scheme) (g_str_has_prefix (scheme, "http") \
|
||||
&& (scheme[4] == '\0' || (scheme[4] == 's' && scheme[5] == '\0')))
|
||||
|
||||
struct _ClapperEnhancerSrc
|
||||
{
|
||||
GstPushSrc parent;
|
||||
@@ -40,12 +44,15 @@ struct _ClapperEnhancerSrc
|
||||
|
||||
gchar *uri;
|
||||
GUri *guri;
|
||||
|
||||
ClapperEnhancerProxyList *enhancer_proxies;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_URI,
|
||||
PROP_ENHANCER_PROXIES,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@@ -62,10 +69,172 @@ clapper_enhancer_src_uri_handler_get_type (GType type)
|
||||
return GST_URI_SRC;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_get_schemes_once (gpointer user_data G_GNUC_UNUSED)
|
||||
/*
|
||||
* _make_schemes:
|
||||
*
|
||||
* Make supported schemes array for a given interface type.
|
||||
* The returned array consists of unique strings (no duplicates).
|
||||
*
|
||||
* Returns: (transfer full): all supported schemes by enhancers of @iface_type.
|
||||
*/
|
||||
static gchar **
|
||||
_make_schemes (gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
return clapper_enhancers_loader_get_schemes (CLAPPER_TYPE_EXTRACTABLE);
|
||||
ClapperEnhancerProxyList *proxies = clapper_get_global_enhancer_proxies ();
|
||||
GSList *found_schemes = NULL, *fs;
|
||||
gchar **schemes_strv;
|
||||
guint i, n_schemes, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
|
||||
GST_DEBUG ("Checking for supported URI schemes");
|
||||
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
const gchar *schemes;
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_EXTRACTABLE)
|
||||
&& (schemes = clapper_enhancer_proxy_get_extra_data (proxy, "X-Schemes"))) {
|
||||
gchar **tmp_strv;
|
||||
gint j;
|
||||
|
||||
tmp_strv = g_strsplit (schemes, ";", 0);
|
||||
|
||||
for (j = 0; tmp_strv[j]; ++j) {
|
||||
const gchar *scheme = tmp_strv[j];
|
||||
|
||||
if (!found_schemes || !g_slist_find_custom (found_schemes,
|
||||
scheme, (GCompareFunc) strcmp)) {
|
||||
found_schemes = g_slist_append (found_schemes, g_strdup (scheme));
|
||||
GST_INFO ("Found supported URI scheme: \"%s\"", scheme);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (tmp_strv);
|
||||
}
|
||||
}
|
||||
|
||||
n_schemes = g_slist_length (found_schemes);
|
||||
schemes_strv = g_new0 (gchar *, n_schemes + 1);
|
||||
|
||||
fs = found_schemes;
|
||||
for (i = 0; i < n_schemes; ++i) {
|
||||
schemes_strv[i] = fs->data;
|
||||
fs = fs->next;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Total found URI schemes: %u", n_schemes);
|
||||
|
||||
/* Since string pointers were taken,
|
||||
* free list without content */
|
||||
g_slist_free (found_schemes);
|
||||
|
||||
return schemes_strv;
|
||||
}
|
||||
|
||||
static inline const gchar *
|
||||
_host_fixup (const gchar *host)
|
||||
{
|
||||
/* Strip common subdomains, so plugins do not
|
||||
* have to list all combinations */
|
||||
if (g_str_has_prefix (host, "www."))
|
||||
host += 4;
|
||||
else if (g_str_has_prefix (host, "m."))
|
||||
host += 2;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
/*
|
||||
* _enhancer_check_for_uri:
|
||||
* @self: a #ClapperEnhancerSrc
|
||||
* @uri: a #GUri
|
||||
*
|
||||
* Check whether there is at least one enhancer for @uri in global list.
|
||||
* This is used to reject URI early, thus making playbin choose different
|
||||
* source element. It uses global list, since at this stage element is not
|
||||
* yet placed within pipeline, so it cannot get proxies from player.
|
||||
*
|
||||
* Returns: whether at least one enhancer advertises support for given URI.
|
||||
*/
|
||||
static gboolean
|
||||
_enhancer_check_for_uri (ClapperEnhancerSrc *self, GUri *uri)
|
||||
{
|
||||
ClapperEnhancerProxyList *proxies = clapper_get_global_enhancer_proxies ();
|
||||
gboolean is_https;
|
||||
guint i, n_proxies;
|
||||
const gchar *scheme = g_uri_get_scheme (uri);
|
||||
const gchar *host = g_uri_get_host (uri);
|
||||
|
||||
if (host)
|
||||
host = _host_fixup (host);
|
||||
|
||||
GST_INFO_OBJECT (self, "Enhancer check, scheme: \"%s\", host: \"%s\"",
|
||||
scheme, GST_STR_NULL (host));
|
||||
|
||||
/* Whether "http(s)" scheme is used */
|
||||
is_https = CHECK_SCHEME_IS_HTTPS (scheme);
|
||||
|
||||
if (!host && is_https)
|
||||
return FALSE;
|
||||
|
||||
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_EXTRACTABLE)
|
||||
&& clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Schemes", scheme)
|
||||
&& (!is_https || clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Hosts", host)))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* _filter_enhancers_for_uri:
|
||||
* @self: a #ClapperEnhancerSrc
|
||||
* @proxies: a #ClapperEnhancerProxyList
|
||||
* @uri: a #GUri
|
||||
*
|
||||
* Finds all enhancer proxies of target implementing "Extractable"
|
||||
* interface, which advertise support for given @uri.
|
||||
*
|
||||
* Returns: (transfer full): A sublist in the form of #GList with proxies.
|
||||
*/
|
||||
static GList *
|
||||
_filter_enhancers_for_uri (ClapperEnhancerSrc *self,
|
||||
ClapperEnhancerProxyList *proxies, GUri *uri)
|
||||
{
|
||||
GList *sublist = NULL;
|
||||
guint i, n_proxies;
|
||||
gboolean is_https;
|
||||
const gchar *scheme = g_uri_get_scheme (uri);
|
||||
const gchar *host = g_uri_get_host (uri);
|
||||
|
||||
if (host)
|
||||
host = _host_fixup (host);
|
||||
|
||||
GST_INFO_OBJECT (self, "Enhancer filter, scheme: \"%s\", host: \"%s\"",
|
||||
scheme, GST_STR_NULL (host));
|
||||
|
||||
/* Whether "http(s)" scheme is used */
|
||||
is_https = CHECK_SCHEME_IS_HTTPS (scheme);
|
||||
|
||||
if (!host && is_https)
|
||||
return NULL;
|
||||
|
||||
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_EXTRACTABLE)
|
||||
&& clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Schemes", scheme)
|
||||
&& (!is_https || clapper_enhancer_proxy_extra_data_lists_value (proxy, "X-Hosts", host))) {
|
||||
sublist = g_list_append (sublist, gst_object_ref (proxy));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sublist;
|
||||
}
|
||||
|
||||
static const gchar *const *
|
||||
@@ -73,7 +242,7 @@ clapper_enhancer_src_uri_handler_get_protocols (GType type)
|
||||
{
|
||||
static GOnce schemes_once = G_ONCE_INIT;
|
||||
|
||||
g_once (&schemes_once, _get_schemes_once, NULL);
|
||||
g_once (&schemes_once, (GThreadFunc) _make_schemes, NULL);
|
||||
return (const gchar *const *) schemes_once.retval;
|
||||
}
|
||||
|
||||
@@ -130,8 +299,7 @@ clapper_enhancer_src_uri_handler_set_uri (GstURIHandler *handler,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!clapper_enhancers_loader_check (CLAPPER_TYPE_EXTRACTABLE,
|
||||
g_uri_get_scheme (guri), g_uri_get_host (guri), NULL)) {
|
||||
if (!_enhancer_check_for_uri (self, guri)) {
|
||||
g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
|
||||
"None of the available enhancers can handle this URI");
|
||||
g_uri_unref (guri);
|
||||
@@ -296,6 +464,8 @@ static GstFlowReturn
|
||||
clapper_enhancer_src_create (GstPushSrc *push_src, GstBuffer **outbuf)
|
||||
{
|
||||
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (push_src);
|
||||
ClapperEnhancerProxyList *proxies;
|
||||
GList *filtered_proxies;
|
||||
GUri *guri;
|
||||
GCancellable *cancellable;
|
||||
ClapperHarvest *harvest;
|
||||
@@ -316,12 +486,28 @@ clapper_enhancer_src_create (GstPushSrc *push_src, GstBuffer **outbuf)
|
||||
self->director = clapper_enhancer_director_new ();
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
if (G_LIKELY (self->enhancer_proxies != NULL)) {
|
||||
GST_INFO_OBJECT (self, "Using enhancer proxies: %" GST_PTR_FORMAT, self->enhancer_proxies);
|
||||
proxies = gst_object_ref (self->enhancer_proxies);
|
||||
} else {
|
||||
/* Compat for old ClapperDiscoverer feature that does not set this property */
|
||||
GST_WARNING_OBJECT (self, "Falling back to using global enhancer proxy list!");
|
||||
proxies = gst_object_ref (clapper_get_global_enhancer_proxies ());
|
||||
}
|
||||
|
||||
guri = g_uri_ref (self->guri);
|
||||
cancellable = g_object_ref (self->cancellable);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
harvest = clapper_enhancer_director_extract (self->director, guri, cancellable, &error);
|
||||
filtered_proxies = _filter_enhancers_for_uri (self, proxies, guri);
|
||||
gst_object_unref (proxies);
|
||||
|
||||
harvest = clapper_enhancer_director_extract (self->director,
|
||||
filtered_proxies, guri, cancellable, &error);
|
||||
|
||||
g_clear_list (&filtered_proxies, gst_object_unref);
|
||||
g_uri_unref (guri);
|
||||
g_object_unref (cancellable);
|
||||
|
||||
@@ -385,6 +571,16 @@ clapper_enhancer_src_query (GstBaseSrc *base_src, GstQuery *query)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_src_set_enhancer_proxies (ClapperEnhancerSrc *self,
|
||||
ClapperEnhancerProxyList *enhancer_proxies)
|
||||
{
|
||||
GST_OBJECT_LOCK (self);
|
||||
gst_object_replace ((GstObject **) &self->enhancer_proxies,
|
||||
GST_OBJECT_CAST (enhancer_proxies));
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_enhancer_src_init (ClapperEnhancerSrc *self)
|
||||
{
|
||||
@@ -413,6 +609,7 @@ clapper_enhancer_src_finalize (GObject *object)
|
||||
g_clear_object (&self->cancellable);
|
||||
g_free (self->uri);
|
||||
g_clear_pointer (&self->guri, g_uri_unref);
|
||||
gst_clear_object (&self->enhancer_proxies);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
@@ -433,6 +630,9 @@ clapper_enhancer_src_set_property (GObject *object, guint prop_id,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROP_ENHANCER_PROXIES:
|
||||
clapper_enhancer_src_set_enhancer_proxies (self, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -485,6 +685,10 @@ clapper_enhancer_src_class_init (ClapperEnhancerSrcClass *klass)
|
||||
"URI", "URI", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
param_specs[PROP_ENHANCER_PROXIES] = g_param_spec_object ("enhancer-proxies",
|
||||
NULL, NULL, CLAPPER_TYPE_ENHANCER_PROXY_LIST,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
|
||||
|
||||
gst_element_class_add_static_pad_template (gstelement_class, &src_template);
|
||||
|
@@ -21,31 +21,50 @@
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "clapper-plugin-private.h"
|
||||
#include "../clapper-functionalities-availability.h"
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
#include "../clapper.h"
|
||||
#include "clapper-enhancer-src-private.h"
|
||||
#include "../clapper-extractable-private.h"
|
||||
#include "../clapper-enhancers-loader-private.h"
|
||||
#endif
|
||||
|
||||
#include "clapper-plugin-private.h"
|
||||
#include "clapper-uri-list-demux-private.h"
|
||||
|
||||
/*
|
||||
* clapper_gst_plugin_has_enhancers:
|
||||
* @iface_type: an interface #GType
|
||||
*
|
||||
* Check if any enhancer implementing given interface type is available.
|
||||
*
|
||||
* Returns: whether any enhancer was found.
|
||||
*/
|
||||
static gboolean
|
||||
clapper_gst_plugin_has_enhancers (ClapperEnhancerProxyList *proxies, GType iface_type)
|
||||
{
|
||||
guint i, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, iface_type))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_gst_plugin_init (GstPlugin *plugin)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
ClapperEnhancerProxyList *global_proxies;
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
gst_plugin_add_dependency_simple (plugin,
|
||||
"CLAPPER_ENHANCERS_PATH", CLAPPER_ENHANCERS_PATH, NULL,
|
||||
GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY);
|
||||
|
||||
global_proxies = clapper_get_global_enhancer_proxies ();
|
||||
|
||||
/* Avoid registering an URI handler without schemes */
|
||||
if (clapper_enhancers_loader_has_enhancers (CLAPPER_TYPE_EXTRACTABLE))
|
||||
if (clapper_gst_plugin_has_enhancers (global_proxies, CLAPPER_TYPE_EXTRACTABLE))
|
||||
res |= GST_ELEMENT_REGISTER (clapperenhancersrc, plugin);
|
||||
#endif
|
||||
|
||||
res |= GST_ELEMENT_REGISTER (clapperurilistdemux, plugin);
|
||||
|
||||
|
@@ -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_ENHANCERS_ID', 'com.github.rafostar.Clapper.Enhancers')
|
||||
config_h.set_quoted('CLAPPER_ENHANCERS_PATH', clapper_enhancers_dir)
|
||||
|
||||
configure_file(
|
||||
@@ -109,6 +110,8 @@ clapper_headers = [
|
||||
'clapper.h',
|
||||
'clapper-enums.h',
|
||||
'clapper-audio-stream.h',
|
||||
'clapper-enhancer-proxy.h',
|
||||
'clapper-enhancer-proxy-list.h',
|
||||
'clapper-extractable.h',
|
||||
'clapper-feature.h',
|
||||
'clapper-harvest.h',
|
||||
@@ -130,6 +133,8 @@ clapper_sources = [
|
||||
'clapper.c',
|
||||
'clapper-app-bus.c',
|
||||
'clapper-audio-stream.c',
|
||||
'clapper-enhancer-proxy.c',
|
||||
'clapper-enhancer-proxy-list.c',
|
||||
'clapper-extractable.c',
|
||||
'clapper-feature.c',
|
||||
'clapper-features-bus.c',
|
||||
@@ -148,6 +153,8 @@ clapper_sources = [
|
||||
'clapper-utils.c',
|
||||
'clapper-video-stream.c',
|
||||
'gst/clapper-plugin.c',
|
||||
'gst/clapper-enhancer-src.c',
|
||||
'gst/clapper-enhancer-director.c',
|
||||
'gst/clapper-uri-list-demux.c',
|
||||
'../shared/clapper-shared-utils.c',
|
||||
]
|
||||
@@ -170,8 +177,6 @@ if clapper_with_enhancers_loader
|
||||
clapper_deps += peas_dep
|
||||
clapper_sources += [
|
||||
'clapper-enhancers-loader.c',
|
||||
'gst/clapper-enhancer-src.c',
|
||||
'gst/clapper-enhancer-director.c',
|
||||
]
|
||||
clapper_available_functionalities += 'enhancers-loader'
|
||||
endif
|
||||
|
Reference in New Issue
Block a user