ges: Implement a new GESDiscovererManager object

Allowing better control over the way discovery happens and allowing
us to expose a proper API.

This also adds the potential of implementing more multi-threaded
discovery in a clean way in the future.

This allows us to cleanly expose the new
GstDiscoverer::load-serialize-info signal.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3911>
This commit is contained in:
Thibault Saunier 2023-02-07 17:01:11 -03:00
parent 9e994ea616
commit 98e5c5e862
10 changed files with 596 additions and 83 deletions

View file

@ -3126,6 +3126,124 @@ if no track elements are created or an error occurred.</doc>
</parameter> </parameter>
</parameters> </parameters>
</function-macro> </function-macro>
<class name="DiscovererManager" c:symbol-prefix="discoverer_manager" c:type="GESDiscovererManager" version="1.24" parent="GObject.Object" glib:type-name="GESDiscovererManager" glib:get-type="ges_discoverer_manager_get_type" glib:type-struct="DiscovererManagerClass">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<function name="get_default" c:identifier="ges_discoverer_manager_get_default" version="1.24">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<return-value transfer-ownership="full">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The default #GESDiscovererManager</doc>
<type name="DiscovererManager" c:type="GESDiscovererManager*"/>
</return-value>
</function>
<method name="get_timeout" c:identifier="ges_discoverer_manager_get_timeout" version="1.24">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The timeout to use for the discoverer</doc>
<type name="Gst.ClockTime" c:type="GstClockTime"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GESDiscovererManager</doc>
<type name="DiscovererManager" c:type="GESDiscovererManager*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_use_cache" c:identifier="ges_discoverer_manager_get_use_cache" version="1.24">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">Whether to use the cache or not</doc>
<type name="gboolean" c:type="gboolean"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GESDiscovererManager</doc>
<type name="DiscovererManager" c:type="GESDiscovererManager*"/>
</instance-parameter>
</parameters>
</method>
<method name="set_timeout" c:identifier="ges_discoverer_manager_set_timeout" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">Sets the timeout to use for the discoverer</doc>
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GESDiscovererManager</doc>
<type name="DiscovererManager" c:type="GESDiscovererManager*"/>
</instance-parameter>
<parameter name="timeout" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The timeout to set</doc>
<type name="Gst.ClockTime" c:type="GstClockTime"/>
</parameter>
</parameters>
</method>
<method name="set_use_cache" c:identifier="ges_discoverer_manager_set_use_cache" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">Sets whether to use the cache or not</doc>
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GESDiscovererManager</doc>
<type name="DiscovererManager" c:type="GESDiscovererManager*"/>
</instance-parameter>
<parameter name="use_cache" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">Whether to use the cache</doc>
<type name="gboolean" c:type="gboolean"/>
</parameter>
</parameters>
</method>
<property name="timeout" version="1.24" writable="1" construct="1" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The timeout (in milliseconds) for the #GstDiscoverer operations</doc>
<type name="guint64" c:type="guint64"/>
</property>
<property name="use-cache" writable="1" construct="1" transfer-ownership="none">
<type name="gboolean" c:type="gboolean"/>
</property>
<glib:signal name="discovered" when="last" action="1" version="1.24">
<attribute name="doc.skip" value="true"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="info" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GstDiscovererInfo representing the discovered URI</doc>
<type name="GstPbutils.DiscovererInfo"/>
</parameter>
<parameter name="error" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GError that occurred, or %NULL</doc>
<type name="GLib.Error"/>
</parameter>
</parameters>
</glib:signal>
<glib:signal name="load-serialized-info" when="last" action="1" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">Retrieves information about a URI from and external source of information,
like a cache file. This is used by the discoverer to speed up the
discovery.</doc>
<return-value transfer-ownership="full" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The #GstDiscovererInfo representing
@uri, or %NULL if no information</doc>
<type name="GstPbutils.DiscovererInfo"/>
</return-value>
<parameters>
<parameter name="uri" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.c">The URI to load the serialized info for</doc>
<type name="utf8" c:type="gchar*"/>
</parameter>
</parameters>
</glib:signal>
</class>
<record name="DiscovererManagerClass" c:type="GESDiscovererManagerClass" glib:is-gtype-struct-for="DiscovererManager">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
<field name="parent_class">
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
</field>
</record>
<record name="DiscovererManagerPrivate" c:type="GESDiscovererManagerPrivate" disguised="1">
<source-position filename="../subprojects/gst-editing-services/ges/ges-discoverer-manager.h"/>
</record>
<function-macro name="EXTRACTABLE_GET_INTERFACE" c:identifier="GES_EXTRACTABLE_GET_INTERFACE" introspectable="0"> <function-macro name="EXTRACTABLE_GET_INTERFACE" c:identifier="GES_EXTRACTABLE_GET_INTERFACE" introspectable="0">
<source-position filename="../subprojects/gst-editing-services/ges/ges-extractable.h"/> <source-position filename="../subprojects/gst-editing-services/ges/ges-extractable.h"/>
<parameters> <parameters>
@ -14965,7 +15083,7 @@ ges_uri_clip_asset_new (uri, (GAsyncReadyCallback) filesource_asset_loaded_cb, u
</parameters> </parameters>
</function> </function>
<function name="request_sync" c:identifier="ges_uri_clip_asset_request_sync" throws="1"> <function name="request_sync" c:identifier="ges_uri_clip_asset_request_sync" throws="1">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-uri-asset.c">Creates a #GESUriClipAsset for @uri syncronously. You should avoid <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-uri-asset.c">Creates a #GESUriClipAsset for @uri synchonously. You should avoid
to use it in application, and rather create #GESUriClipAsset asynchronously</doc> to use it in application, and rather create #GESUriClipAsset asynchronously</doc>
<source-position filename="../subprojects/gst-editing-services/ges/ges-uri-asset.h"/> <source-position filename="../subprojects/gst-editing-services/ges/ges-uri-asset.h"/>
<return-value transfer-ownership="full"> <return-value transfer-ownership="full">
@ -15115,8 +15233,9 @@ are different as those can be extended 'infinitely'.</doc>
<type name="gpointer" c:type="gpointer"/> <type name="gpointer" c:type="gpointer"/>
</array> </array>
</field> </field>
<method name="set_timeout" c:identifier="ges_uri_clip_asset_class_set_timeout"> <method name="set_timeout" c:identifier="ges_uri_clip_asset_class_set_timeout" deprecated="1" deprecated-version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-uri-asset.c">Sets the timeout of #GESUriClipAsset loading</doc> <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-uri-asset.c">Sets the timeout of #GESUriClipAsset loading</doc>
<doc-deprecated xml:space="preserve">ges_discoverer_manager_set_timeout() should be used instead</doc-deprecated>
<source-position filename="../subprojects/gst-editing-services/ges/ges-uri-asset.h"/> <source-position filename="../subprojects/gst-editing-services/ges/ges-uri-asset.h"/>
<return-value transfer-ownership="none"> <return-value transfer-ownership="none">
<type name="none" c:type="void"/> <type name="none" c:type="void"/>

View file

@ -369,6 +369,24 @@ free it when no longer needed using g_error_free().</doc>
</instance-parameter> </instance-parameter>
</parameters> </parameters>
</virtual-method> </virtual-method>
<virtual-method name="load_serialize_info" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">Loads the serialized info from the given uri.</doc>
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h"/>
<return-value transfer-ownership="full">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the #GstDiscovererInfo or %NULL if it could not be loaded</doc>
<type name="DiscovererInfo" c:type="GstDiscovererInfo*"/>
</return-value>
<parameters>
<instance-parameter name="dc" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the #GstDiscoverer</doc>
<type name="Discoverer" c:type="GstDiscoverer*"/>
</instance-parameter>
<parameter name="uri" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the uri to load the info from</doc>
<type name="utf8" c:type="gchar*"/>
</parameter>
</parameters>
</virtual-method>
<virtual-method name="source_setup"> <virtual-method name="source_setup">
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h"/> <source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h"/>
<return-value transfer-ownership="none"> <return-value transfer-ownership="none">
@ -521,6 +539,22 @@ depending on the circumstances of the error.</doc>
<type name="none" c:type="void"/> <type name="none" c:type="void"/>
</return-value> </return-value>
</glib:signal> </glib:signal>
<glib:signal name="load-serialized-info" when="last" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.c">Retrieves information about a URI from and external source of information,
like a cache file. This is used by the discoverer to speed up the
discovery.</doc>
<return-value transfer-ownership="full" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.c">The #GstDiscovererInfo representing
@uri, or %NULL if no information</doc>
<type name="DiscovererInfo"/>
</return-value>
<parameters>
<parameter name="uri" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.c">THe URI to load the serialized info for</doc>
<type name="utf8" c:type="gchar*"/>
</parameter>
</parameters>
</glib:signal>
<glib:signal name="source-setup" when="last"> <glib:signal name="source-setup" when="last">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.c">This signal is emitted after the source element has been created for, so <doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.c">This signal is emitted after the source element has been created for, so
the URI being discovered, so it can be configured by setting additional the URI being discovered, so it can be configured by setting additional
@ -708,8 +742,27 @@ information.</doc>
</parameters> </parameters>
</callback> </callback>
</field> </field>
<field name="load_serialize_info">
<callback name="load_serialize_info">
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h"/>
<return-value transfer-ownership="full">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the #GstDiscovererInfo or %NULL if it could not be loaded</doc>
<type name="DiscovererInfo" c:type="GstDiscovererInfo*"/>
</return-value>
<parameters>
<parameter name="dc" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the #GstDiscoverer</doc>
<type name="Discoverer" c:type="GstDiscoverer*"/>
</parameter>
<parameter name="uri" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/pbutils/gstdiscoverer.h">the uri to load the info from</doc>
<type name="utf8" c:type="gchar*"/>
</parameter>
</parameters>
</callback>
</field>
<field name="_reserved"> <field name="_reserved">
<array zero-terminated="0" fixed-size="4"> <array zero-terminated="0" fixed-size="3">
<type name="gpointer" c:type="gpointer"/> <type name="gpointer" c:type="gpointer"/>
</array> </array>
</field> </field>

View file

@ -0,0 +1,353 @@
#include "ges-internal.h"
#include "ges-discoverer-manager.h"
/**
* GESDiscovererManager:
*
* Since: 1.24
*/
struct _GESDiscovererManager
{
GObject parent;
GHashTable *discoverers;
GMutex lock;
GstClockTime timeout;
gboolean use_cache;
};
G_DEFINE_TYPE (GESDiscovererManager, ges_discoverer_manager, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_TIMEOUT,
PROP_USE_CACHE,
N_PROPERTIES
};
enum
{
LOAD_SERIALIZED_INFO_SIGNAL,
DISCOVERER_SIGNAL,
N_SIGNALS
};
#define DEFAULT_USE_CACHE FALSE
#define DEFAULT_TIMEOUT (60 * GST_SECOND)
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static guint signals[N_SIGNALS] = { 0, };
G_LOCK_DEFINE_STATIC (singleton_lock);
static GESDiscovererManager *self = NULL;
static void
ges_discoverer_manager_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec)
{
GESDiscovererManager *self = GES_DISCOVERER_MANAGER (object);
switch (property_id) {
case PROP_TIMEOUT:
g_value_set_uint64 (value, ges_discoverer_manager_get_timeout (self));
break;
case PROP_USE_CACHE:
g_value_set_boolean (value, ges_discoverer_manager_get_use_cache (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
ges_discoverer_manager_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec)
{
GESDiscovererManager *self = GES_DISCOVERER_MANAGER (object);
switch (property_id) {
case PROP_TIMEOUT:
ges_discoverer_manager_set_timeout (self, g_value_get_uint64 (value));
break;
case PROP_USE_CACHE:
ges_discoverer_manager_set_use_cache (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
ges_discoverer_manager_finalize (GObject * object)
{
GESDiscovererManager *self = GES_DISCOVERER_MANAGER (object);
g_hash_table_unref (self->discoverers);
G_OBJECT_CLASS (ges_discoverer_manager_parent_class)->finalize (object);
}
static void
ges_discoverer_manager_class_init (GESDiscovererManagerClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ges_discoverer_manager_finalize;
object_class->set_property = ges_discoverer_manager_set_property;
object_class->get_property = ges_discoverer_manager_get_property;
/**
* GESDiscovererManager:timeout:
*
* The timeout (in milliseconds) for the #GstDiscoverer operations
*
* Since: 1.24
*/
properties[PROP_TIMEOUT] =
g_param_spec_uint64 ("timeout", "Timeout",
"The timeout for the discoverer", 0, GST_CLOCK_TIME_NONE, DEFAULT_TIMEOUT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
/**
* GESDiscovererManager::use-cache:
*
* Whether to use a serialized version of the discoverer info from our own
* cache if accessible. This allows the discovery to be much faster as when
* using this option, we do not need to create a #GstPipeline and run it, but
* instead, just reload the #GstDiscovererInfo in its serialized form.
*
* The cache files are saved in `$XDG_CACHE_DIR/gstreamer-1.0/discoverer/`.
*
* For more granularity or to use your own cache, using the
* #GESDiscovererManager::load-serialized-info signal is recommended.
*
* Since: 1.24
*/
properties[PROP_USE_CACHE] =
g_param_spec_boolean ("use-cache", "Use cache",
"Whether to use a serialized version of the discoverer info from our own cache if accessible",
DEFAULT_USE_CACHE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
/**
* GESDiscovererManager::load-serialized-info:
* @manager: the #GESDiscovererManager
* @uri: The URI to load the serialized info for
*
* Retrieves information about a URI from and external source of information,
* like a cache file. This is used by the discoverer to speed up the
* discovery.
*
* Returns: (nullable) (transfer full): The #GstDiscovererInfo representing
* @uri, or %NULL if no information
*
* Since: 1.24
*/
signals[LOAD_SERIALIZED_INFO_SIGNAL] =
g_signal_new ("load-serialized-info", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
0, NULL, NULL, NULL, GST_TYPE_DISCOVERER_INFO, 1, G_TYPE_STRING);
/**
* GESDiscovererManager::discovered: (attributes doc.skip=true)
* @manager: the #GESDiscovererManager
* @info: The #GstDiscovererInfo representing the discovered URI
* @error: The #GError that occurred, or %NULL
*
* Since: 1.24
*/
signals[DISCOVERER_SIGNAL] =
g_signal_new ("discovered", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
0, NULL, NULL, NULL, G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO,
G_TYPE_ERROR);
}
void
ges_discoverer_manager_init (GESDiscovererManager * self)
{
self->discoverers = g_hash_table_new_full (g_direct_hash, g_str_equal,
NULL, g_object_unref);
}
/**
* ges_discoverer_manager_get_default:
*
* Returns: (transfer full): The default #GESDiscovererManager
*
* Since: 1.24
*/
GESDiscovererManager *
ges_discoverer_manager_get_default (void)
{
G_LOCK (singleton_lock);
if (G_UNLIKELY (self == NULL)) {
self = g_object_new (GES_TYPE_DISCOVERER_MANAGER, NULL);
}
G_UNLOCK (singleton_lock);
return g_object_ref (self);
}
/**
* ges_discoverer_manager_get_use_cache:
* @self: The #GESDiscovererManager
*
* Returns: Whether to use the cache or not
*
* Since: 1.24
*/
gboolean
ges_discoverer_manager_get_use_cache (GESDiscovererManager * self)
{
g_return_val_if_fail (GES_IS_DISCOVERER_MANAGER (self), FALSE);
return self->use_cache;
}
/**
* ges_discoverer_manager_set_use_cache:
* @self: The #GESDiscovererManager
* @use_cache: Whether to use the cache
*
* Sets whether to use the cache or not
*
* Since: 1.24
*/
void
ges_discoverer_manager_set_use_cache (GESDiscovererManager * self,
gboolean use_cache)
{
g_return_if_fail (GES_IS_DISCOVERER_MANAGER (self));
self->use_cache = use_cache;
}
/**
* ges_discoverer_manager_get_timeout:
* @self: The #GESDiscovererManager
*
* Returns: The timeout to use for the discoverer
*
* Since: 1.24
*/
GstClockTime
ges_discoverer_manager_get_timeout (GESDiscovererManager * self)
{
g_return_val_if_fail (GES_IS_DISCOVERER_MANAGER (self), 0);
return self->timeout;
}
/**
* ges_discoverer_manager_set_timeout:
* @self: The #GESDiscovererManager
* @timeout: The timeout to set
*
* Sets the timeout to use for the discoverer
*
* Since: 1.24
*/
void
ges_discoverer_manager_set_timeout (GESDiscovererManager * self,
GstClockTime timeout)
{
GHashTableIter iter;
GstDiscoverer *discoverer;
g_return_if_fail (GES_IS_DISCOVERER_MANAGER (self));
self->timeout = timeout;
g_mutex_lock (&self->lock);
g_hash_table_iter_init (&iter, self->discoverers);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) & discoverer))
g_object_set (discoverer, "timeout", timeout, NULL);
g_mutex_unlock (&self->lock);
}
static GstDiscovererInfo *
proxy_load_serialized_info_cb (GESDiscovererManager * self, const gchar * uri)
{
GstDiscovererInfo *info;
g_signal_emit (self, signals[LOAD_SERIALIZED_INFO_SIGNAL], 0, uri, &info);
return info;
}
static void
proxy_discovered_cb (GESDiscovererManager * self,
GstDiscovererInfo * info, GError * err, gpointer user_data)
{
g_signal_emit (self, signals[DISCOVERER_SIGNAL], 0, info, err);
}
static GstDiscoverer *
create_discoverer (GESDiscovererManager * self)
{
GstDiscoverer *discoverer;
discoverer = gst_discoverer_new (self->timeout, NULL);
g_signal_connect_swapped (discoverer, "load-serialized-info",
G_CALLBACK (proxy_load_serialized_info_cb), self);
g_signal_connect_swapped (discoverer, "discovered",
G_CALLBACK (proxy_discovered_cb), self);
g_object_set (discoverer, "use-cache", self->use_cache, NULL);
gst_discoverer_start (discoverer);
return discoverer;
}
static GstDiscoverer *
ges_discoverer_manager_get_discoverer (GESDiscovererManager * self)
{
GstDiscoverer *ret;
g_return_val_if_fail (GES_IS_DISCOVERER_MANAGER (self), NULL);
g_mutex_lock (&self->lock);
ret = g_hash_table_lookup (self->discoverers, g_thread_self ());
if (!ret) {
ret = create_discoverer (self);
g_hash_table_insert (self->discoverers, g_thread_self (), ret);
}
g_mutex_unlock (&self->lock);
return gst_object_ref (ret);
}
gboolean
ges_discoverer_manager_start_discovery (GESDiscovererManager * self,
const gchar * uri)
{
GstDiscoverer *discoverer;
g_return_val_if_fail (uri != NULL, FALSE);
discoverer = ges_discoverer_manager_get_discoverer (self);
gboolean res = gst_discoverer_discover_uri_async (discoverer, uri);
gst_object_unref (discoverer);
return res;
}
void
ges_discoverer_manager_cleanup (void)
{
G_LOCK (singleton_lock);
gst_clear_object (&self);
G_UNLOCK (singleton_lock);
}

View file

@ -0,0 +1,32 @@
#pragma once
#include <ges/ges-types.h>
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>
#include <glib-object.h>
G_BEGIN_DECLS
/**
* GES_TYPE_DISCOVERER_MANAGER:
*
* Since: 1.24
*/
#define GES_TYPE_DISCOVERER_MANAGER ges_discoverer_manager_get_type ()
struct _GESDiscovererManagerClass
{
GObjectClass parent_class;
};
GES_DECLARE_TYPE(DiscovererManager, discoverer_manager, DISCOVERER_MANAGER);
GES_API GstClockTime ges_discoverer_manager_get_timeout (GESDiscovererManager * self);
GES_API void ges_discoverer_manager_set_timeout (GESDiscovererManager * self,
GstClockTime timeout);
GES_API GESDiscovererManager * ges_discoverer_manager_get_default (void);
GES_API void ges_discoverer_manager_set_use_cache (GESDiscovererManager *self,
gboolean use_cache);
GES_API gboolean ges_discoverer_manager_get_use_cache (GESDiscovererManager *self);
G_END_DECLS

View file

@ -594,6 +594,14 @@ G_GNUC_INTERNAL GESMarker * ges_marker_list_get_closest (GESMarkerList *list, Gs
G_GNUC_INTERNAL gchar * ges_marker_list_serialize (const GValue * v); G_GNUC_INTERNAL gchar * ges_marker_list_serialize (const GValue * v);
G_GNUC_INTERNAL gboolean ges_marker_list_deserialize (GValue *dest, const gchar *s); G_GNUC_INTERNAL gboolean ges_marker_list_deserialize (GValue *dest, const gchar *s);
/*******************************
* GESDiscovererManager *
*******************************/
G_GNUC_INTERNAL void ges_discoverer_manager_cleanup (void);
G_GNUC_INTERNAL gboolean ges_discoverer_manager_start_discovery (GESDiscovererManager *self,
const gchar *uri);
G_GNUC_INTERNAL void ges_discoverer_manager_recreate_discoverer (GESDiscovererManager *self);
/******************** /********************
* Gnonlin helpers * * Gnonlin helpers *
********************/ ********************/

View file

@ -233,6 +233,9 @@ typedef struct _GESEffectAsset GESEffectAsset;
typedef struct _GESXmlFormatterClass GESXmlFormatterClass; typedef struct _GESXmlFormatterClass GESXmlFormatterClass;
typedef struct _GESXmlFormatter GESXmlFormatter; typedef struct _GESXmlFormatter GESXmlFormatter;
typedef struct _GESDiscovererManager GESDiscovererManager;
typedef struct _GESDiscovererManagerClass GESDiscovererManagerClass;
/** /**
* GES_DECLARE_TYPE: (attributes doc.skip=true) * GES_DECLARE_TYPE: (attributes doc.skip=true)
*/ */

View file

@ -28,6 +28,7 @@
* let you get information about the medias. Also, the tags found in the media file are * let you get information about the medias. Also, the tags found in the media file are
* set as Metadata of the Asset. * set as Metadata of the Asset.
*/ */
#include "ges-discoverer-manager.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
@ -42,44 +43,9 @@
static GHashTable *parent_newparent_table = NULL; static GHashTable *parent_newparent_table = NULL;
G_LOCK_DEFINE_STATIC (discoverers_lock);
static GstClockTime discovering_timeout = DEFAULT_DISCOVERY_TIMEOUT;
static GHashTable *discoverers = NULL; /* Thread ID -> GstDiscoverer */
static void discoverer_discovered_cb (GstDiscoverer * discoverer, static void discoverer_discovered_cb (GstDiscoverer * discoverer,
GstDiscovererInfo * info, GError * err, gpointer user_data); GstDiscovererInfo * info, GError * err, gpointer user_data);
/* WITH discoverers_lock */
static GstDiscoverer *
create_discoverer (void)
{
GstDiscoverer *disco = gst_discoverer_new (discovering_timeout, NULL);
g_signal_connect (disco, "discovered", G_CALLBACK (discoverer_discovered_cb),
NULL);
GST_INFO_OBJECT (disco, "Creating new discoverer");
g_hash_table_insert (discoverers, g_thread_self (), disco);
gst_discoverer_start (disco);
return disco;
}
static GstDiscoverer *
get_discoverer (void)
{
GstDiscoverer *disco;
G_LOCK (discoverers_lock);
g_assert (discoverers);
disco = g_hash_table_lookup (discoverers, g_thread_self ());
if (!disco) {
disco = create_discoverer ();
}
disco = gst_object_ref (disco);
G_UNLOCK (discoverers_lock);
return disco;
}
static void static void
initable_iface_init (GInitableIface * initable_iface) initable_iface_init (GInitableIface * initable_iface)
{ {
@ -167,13 +133,13 @@ _start_loading (GESAsset * asset, GError ** error)
{ {
gboolean ret; gboolean ret;
const gchar *uri; const gchar *uri;
GstDiscoverer *discoverer = get_discoverer (); GESDiscovererManager *manager = ges_discoverer_manager_get_default ();
uri = ges_asset_get_id (asset); uri = ges_asset_get_id (asset);
GST_DEBUG_OBJECT (discoverer, "Started loading %s", uri); GST_DEBUG_OBJECT (manager, "Started loading %s", uri);
ret = gst_discoverer_discover_uri_async (discoverer, uri); ret = ges_discoverer_manager_start_discovery (manager, uri);
gst_object_unref (discoverer); gst_object_unref (manager);
if (ret) if (ret)
return GES_ASSET_LOADING_ASYNC; return GES_ASSET_LOADING_ASYNC;
@ -314,7 +280,6 @@ ges_uri_clip_asset_class_init (GESUriClipAssetClass * klass)
klass->discovered = discoverer_discovered_cb; klass->discovered = discoverer_discovered_cb;
/** /**
* GESUriClipAsset:duration: * GESUriClipAsset:duration:
* *
@ -491,7 +456,7 @@ _set_meta_foreach (const GstTagList * tags, const gchar * tag,
} }
static void static void
discoverer_discovered_cb (GstDiscoverer * discoverer, discoverer_discovered_cb (GstDiscoverer * _object,
GstDiscovererInfo * info, GError * err, gpointer user_data) GstDiscovererInfo * info, GError * err, gpointer user_data)
{ {
GError *error = NULL; GError *error = NULL;
@ -697,7 +662,7 @@ ges_uri_clip_asset_finish (GAsyncResult * res, GError ** error)
* You can also use multi file uris for #GESMultiFileSource. * You can also use multi file uris for #GESMultiFileSource.
* @error: An error to be set in case something wrong happens or %NULL * @error: An error to be set in case something wrong happens or %NULL
* *
* Creates a #GESUriClipAsset for @uri syncronously. You should avoid * Creates a #GESUriClipAsset for @uri synchonously. You should avoid
* to use it in application, and rather create #GESUriClipAsset asynchronously * to use it in application, and rather create #GESUriClipAsset asynchronously
* *
* Returns: (transfer full): A reference to the requested asset or %NULL if * Returns: (transfer full): A reference to the requested asset or %NULL if
@ -709,7 +674,6 @@ ges_uri_clip_asset_request_sync (const gchar * uri, GError ** error)
GError *lerror = NULL; GError *lerror = NULL;
GESUriClipAsset *asset; GESUriClipAsset *asset;
RequestSyncData data = { 0, }; RequestSyncData data = { 0, };
GstDiscoverer *previous_discoverer;
asset = GES_URI_CLIP_ASSET (ges_asset_request (GES_TYPE_URI_CLIP, uri, asset = GES_URI_CLIP_ASSET (ges_asset_request (GES_TYPE_URI_CLIP, uri,
&lerror)); &lerror));
@ -718,18 +682,12 @@ ges_uri_clip_asset_request_sync (const gchar * uri, GError ** error)
return asset; return asset;
data.ml = g_main_loop_new (NULL, TRUE); data.ml = g_main_loop_new (NULL, TRUE);
previous_discoverer = get_discoverer ();
create_discoverer ();
ges_asset_request_async (GES_TYPE_URI_CLIP, uri, NULL, ges_asset_request_async (GES_TYPE_URI_CLIP, uri, NULL,
(GAsyncReadyCallback) asset_ready_cb, &data); (GAsyncReadyCallback) asset_ready_cb, &data);
g_main_loop_run (data.ml); g_main_loop_run (data.ml);
g_main_loop_unref (data.ml); g_main_loop_unref (data.ml);
G_LOCK (discoverers_lock);
g_hash_table_insert (discoverers, g_thread_self (), previous_discoverer);
G_UNLOCK (discoverers_lock);
if (data.error) { if (data.error) {
GST_ERROR ("Got an error requesting asset: %s", data.error->message); GST_ERROR ("Got an error requesting asset: %s", data.error->message);
if (error != NULL) if (error != NULL)
@ -747,23 +705,17 @@ ges_uri_clip_asset_request_sync (const gchar * uri, GError ** error)
* @timeout: The timeout to set * @timeout: The timeout to set
* *
* Sets the timeout of #GESUriClipAsset loading * Sets the timeout of #GESUriClipAsset loading
*
* Deprecated: 1.24: ges_discoverer_manager_set_timeout() should be used instead
*/ */
void void
ges_uri_clip_asset_class_set_timeout (GESUriClipAssetClass * klass, ges_uri_clip_asset_class_set_timeout (GESUriClipAssetClass * klass,
GstClockTime timeout) GstClockTime timeout)
{ {
GHashTableIter iter;
gpointer value;
g_return_if_fail (GES_IS_URI_CLIP_ASSET_CLASS (klass)); g_return_if_fail (GES_IS_URI_CLIP_ASSET_CLASS (klass));
discovering_timeout = timeout; ges_discoverer_manager_set_timeout (ges_discoverer_manager_get_default (),
timeout);
G_LOCK (discoverers_lock);
g_hash_table_iter_init (&iter, discoverers);
while (g_hash_table_iter_next (&iter, NULL, &value))
g_object_set (value, "timeout", timeout, NULL);
G_UNLOCK (discoverers_lock);
} }
/** /**
@ -931,14 +883,9 @@ _ges_uri_asset_cleanup (void)
parent_newparent_table = NULL; parent_newparent_table = NULL;
} }
G_LOCK (discoverers_lock);
if (discoverers) {
g_hash_table_destroy (discoverers);
discoverers = NULL;
}
gst_clear_object (&GES_URI_CLIP_ASSET_CLASS (g_type_class_peek gst_clear_object (&GES_URI_CLIP_ASSET_CLASS (g_type_class_peek
(GES_TYPE_URI_CLIP_ASSET))->discoverer); (GES_TYPE_URI_CLIP_ASSET))->discoverer);
G_UNLOCK (discoverers_lock); ges_discoverer_manager_cleanup ();
} }
gboolean gboolean
@ -965,18 +912,23 @@ _ges_uri_asset_ensure_setup (gpointer uriasset_class)
if (errno) if (errno)
timeout = DEFAULT_DISCOVERY_TIMEOUT; timeout = DEFAULT_DISCOVERY_TIMEOUT;
/* The class structure keeps weak pointers on the discoverers so they
* can be properly cleaned up in _ges_uri_asset_cleanup(). */
if (!klass->discoverer) { if (!klass->discoverer) {
GESDiscovererManager *manager = ges_discoverer_manager_get_default ();
ges_discoverer_manager_set_timeout (manager, timeout);
g_signal_connect (manager, "discovered",
G_CALLBACK (discoverer_discovered_cb), NULL);
discoverer = gst_discoverer_new (timeout, &err); discoverer = gst_discoverer_new (timeout, &err);
if (!discoverer) { if (!discoverer) {
GST_ERROR ("Could not create discoverer: %s", err->message); GST_ERROR ("Could not create discoverer: %s", err->message);
g_error_free (err); g_error_free (err);
return FALSE; return FALSE;
} }
}
/* The class structure keeps weak pointers on the discoverers so they /* Keep legacy handling of discoverer, even if not used */
* can be properly cleaned up in _ges_uri_asset_cleanup(). */
if (!klass->discoverer) {
klass->discoverer = klass->sync_discoverer = discoverer; klass->discoverer = klass->sync_discoverer = discoverer;
g_object_add_weak_pointer (G_OBJECT (discoverer), g_object_add_weak_pointer (G_OBJECT (discoverer),
(gpointer *) & klass->discoverer); (gpointer *) & klass->discoverer);
@ -988,13 +940,6 @@ _ges_uri_asset_ensure_setup (gpointer uriasset_class)
gst_discoverer_start (klass->discoverer); gst_discoverer_start (klass->discoverer);
} }
G_LOCK (discoverers_lock);
if (discoverers == NULL) {
discoverers = g_hash_table_new_full (g_direct_hash,
(GEqualFunc) g_direct_equal, NULL, g_object_unref);
}
G_UNLOCK (discoverers_lock);
/* We just start the discoverer and let it live */ /* We just start the discoverer and let it live */
if (parent_newparent_table == NULL) { if (parent_newparent_table == NULL) {
parent_newparent_table = g_hash_table_new_full (g_file_hash, parent_newparent_table = g_hash_table_new_full (g_file_hash,

View file

@ -118,5 +118,4 @@ GES_API
const GESUriClipAsset *ges_uri_source_asset_get_filesource_asset (GESUriSourceAsset *asset); const GESUriClipAsset *ges_uri_source_asset_get_filesource_asset (GESUriSourceAsset *asset);
GES_API GES_API
gboolean ges_uri_source_asset_is_image (GESUriSourceAsset *asset); gboolean ges_uri_source_asset_is_image (GESUriSourceAsset *asset);
G_END_DECLS G_END_DECLS

View file

@ -445,7 +445,6 @@ ges_extractable_interface_init (GESExtractableInterface * iface)
iface->check_id = (GESExtractableCheckId) extractable_check_id; iface->check_id = (GESExtractableCheckId) extractable_check_id;
iface->get_parameters_from_id = extractable_get_parameters_from_id; iface->get_parameters_from_id = extractable_get_parameters_from_id;
iface->get_id = extractable_get_id; iface->get_id = extractable_get_id;
iface->get_id = extractable_get_id;
iface->can_update_asset = TRUE; iface->can_update_asset = TRUE;
iface->set_asset_full = extractable_set_asset; iface->set_asset_full = extractable_set_asset;
} }

View file

@ -65,6 +65,7 @@ ges_sources = files([
'ges-structured-interface.c', 'ges-structured-interface.c',
'ges-structure-parser.c', 'ges-structure-parser.c',
'ges-marker-list.c', 'ges-marker-list.c',
'ges-discoverer-manager.c',
'gstframepositioner.c' 'gstframepositioner.c'
]) ])
@ -129,7 +130,8 @@ ges_headers = files([
'ges-effect-asset.h', 'ges-effect-asset.h',
'ges-utils.h', 'ges-utils.h',
'ges-group.h', 'ges-group.h',
'ges-marker-list.h' 'ges-marker-list.h',
'ges-discoverer-manager.h',
]) ])
if libxml_dep.found() if libxml_dep.found()