mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-10 17:35:59 +00:00
uri-asset: Use the same code path for sync discovery as the async one
And start handling relocated assets. Also expose the discoverer callback as a vmethod so that we can overridde the discoverer when necessary (to handle discovering of timeline through gesdemux for example)
This commit is contained in:
parent
c596f80c63
commit
bad64296d9
6 changed files with 107 additions and 89 deletions
|
@ -219,6 +219,7 @@ G_GNUC_INTERNAL gchar * ges_project_try_updating_id (GESProject *s
|
|||
G_GNUC_INTERNAL void ges_project_add_loading_asset (GESProject *project,
|
||||
GType extractable_type,
|
||||
const gchar *id);
|
||||
G_GNUC_INTERNAL gchar* ges_uri_asset_try_update_id (GError *error, GESAsset *wrong_asset);
|
||||
/************************************************
|
||||
* *
|
||||
* GESBaseXmlFormatter internal methods *
|
||||
|
|
|
@ -353,6 +353,12 @@ ges_missing_uri_default (GESProject * self, GError * error,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
gchar *
|
||||
ges_uri_asset_try_update_id (GError * error, GESAsset * wrong_asset)
|
||||
{
|
||||
return ges_missing_uri_default (NULL, error, wrong_asset);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_uri_assets_validate_uri (const gchar * nid)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* The #GESUriClipAsset is a special #GESAsset that lets you handle
|
||||
* the media file to use inside the GStreamer Editing Services. It has APIs that
|
||||
* let you get information about the medias. Also, the tags found in the media file are
|
||||
* set as Metadatas of the Asser.
|
||||
* set as Metadata of the Asset.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
|
@ -43,7 +43,6 @@
|
|||
static GHashTable *parent_newparent_table = NULL;
|
||||
|
||||
static GstDiscoverer *discoverer = NULL;
|
||||
static GstDiscoverer *sync_discoverer = NULL;
|
||||
|
||||
static void
|
||||
initable_iface_init (GInitableIface * initable_iface)
|
||||
|
@ -75,6 +74,13 @@ struct _GESUriClipAssetPrivate
|
|||
GList *asset_trackfilesources;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *ml;
|
||||
GESAsset *asset;
|
||||
GError *error;
|
||||
} RequestSyncData;
|
||||
|
||||
struct _GESUriSourceAssetPrivate
|
||||
{
|
||||
GstDiscovererStreamInfo *sinfo;
|
||||
|
@ -216,6 +222,8 @@ ges_uri_clip_asset_class_init (GESUriClipAssetClass * klass)
|
|||
GES_ASSET_CLASS (klass)->request_id_update = _request_id_update;
|
||||
GES_ASSET_CLASS (klass)->inform_proxy = _asset_proxied;
|
||||
|
||||
klass->discovered = discoverer_discovered_cb;
|
||||
|
||||
|
||||
/**
|
||||
* GESUriClipAsset:duration:
|
||||
|
@ -402,6 +410,26 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
|||
g_error_free (error);
|
||||
}
|
||||
|
||||
static void
|
||||
asset_ready_cb (GESAsset * source, GAsyncResult * res, RequestSyncData * data)
|
||||
{
|
||||
data->asset = ges_asset_request_finish (res, &data->error);
|
||||
|
||||
if (data->error) {
|
||||
gchar *possible_uri = ges_uri_asset_try_update_id (data->error, source);
|
||||
|
||||
if (possible_uri) {
|
||||
g_clear_error (&data->error);
|
||||
ges_asset_request_async (GES_TYPE_URI_CLIP, possible_uri, NULL,
|
||||
(GAsyncReadyCallback) asset_ready_cb, data);
|
||||
g_free (possible_uri);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_main_loop_quit (data->ml);
|
||||
}
|
||||
|
||||
/* API implementation */
|
||||
/**
|
||||
* ges_uri_clip_asset_get_info:
|
||||
|
@ -496,7 +524,6 @@ ges_uri_clip_asset_new (const gchar * uri, GCancellable * cancellable,
|
|||
callback, user_data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ges_uri_clip_asset_finish:
|
||||
* @res: The #GAsyncResult from which to get the newly created #GESUriClipAsset
|
||||
|
@ -537,10 +564,8 @@ GESUriClipAsset *
|
|||
ges_uri_clip_asset_request_sync (const gchar * uri, GError ** error)
|
||||
{
|
||||
GError *lerror = NULL;
|
||||
GstDiscovererInfo *info;
|
||||
GstDiscoverer *discoverer;
|
||||
GESUriClipAsset *asset;
|
||||
gchar *first_file, *first_file_uri;
|
||||
RequestSyncData data = { 0, };
|
||||
|
||||
asset = GES_URI_CLIP_ASSET (ges_asset_request (GES_TYPE_URI_CLIP, uri,
|
||||
&lerror));
|
||||
|
@ -548,61 +573,21 @@ ges_uri_clip_asset_request_sync (const gchar * uri, GError ** error)
|
|||
if (asset)
|
||||
return asset;
|
||||
|
||||
if (lerror && lerror->domain == GES_ERROR &&
|
||||
lerror->code == GES_ERROR_ASSET_WRONG_ID) {
|
||||
g_propagate_error (error, lerror);
|
||||
data.ml = g_main_loop_new (NULL, TRUE);
|
||||
ges_asset_request_async (GES_TYPE_URI_CLIP, uri, NULL,
|
||||
(GAsyncReadyCallback) asset_ready_cb, &data);
|
||||
g_main_loop_run (data.ml);
|
||||
g_main_loop_unref (data.ml);
|
||||
|
||||
if (data.error) {
|
||||
GST_ERROR ("Got an error requesting asset: %s", data.error->message);
|
||||
if (error != NULL)
|
||||
g_propagate_error (error, data.error);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asset = g_object_new (GES_TYPE_URI_CLIP_ASSET, "id", uri,
|
||||
"extractable-type", GES_TYPE_URI_CLIP, NULL);
|
||||
discoverer = GES_URI_CLIP_ASSET_GET_CLASS (asset)->sync_discoverer;
|
||||
|
||||
if (g_str_has_prefix (uri, GES_MULTI_FILE_URI_PREFIX)) {
|
||||
GESMultiFileURI *uri_data;
|
||||
|
||||
uri_data = ges_multi_file_uri_new (uri);
|
||||
first_file = g_strdup_printf (uri_data->location, uri_data->start);
|
||||
first_file_uri = gst_filename_to_uri (first_file, &lerror);
|
||||
info = gst_discoverer_discover_uri (discoverer, first_file_uri, &lerror);
|
||||
GST_DEBUG ("Got multifile uri. Discovering first file %s", first_file_uri);
|
||||
g_free (uri_data);
|
||||
g_free (first_file_uri);
|
||||
g_free (first_file);
|
||||
} else {
|
||||
info = gst_discoverer_discover_uri (discoverer, uri, &lerror);
|
||||
}
|
||||
|
||||
/* We might get a discoverer info but it might have a non-OK result. We
|
||||
* should consider that an error */
|
||||
if (!lerror && info
|
||||
&& gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) {
|
||||
lerror =
|
||||
g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Stream %s discovering failed (error code: %d)", uri,
|
||||
gst_discoverer_info_get_result (info));
|
||||
}
|
||||
|
||||
_set_meta_file_size (uri, asset);
|
||||
|
||||
ges_asset_cache_put (gst_object_ref (asset), NULL);
|
||||
ges_uri_clip_asset_set_info (asset, info);
|
||||
ges_asset_cache_set_loaded (GES_TYPE_URI_CLIP, uri, lerror);
|
||||
|
||||
if (info == NULL || lerror != NULL) {
|
||||
gst_object_unref (asset);
|
||||
if (info)
|
||||
gst_discoverer_info_unref (info);
|
||||
if (lerror)
|
||||
g_propagate_error (error, lerror);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gst_discoverer_info_unref (info);
|
||||
|
||||
return asset;
|
||||
return GES_URI_CLIP_ASSET (data.asset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -619,7 +604,6 @@ ges_uri_clip_asset_class_set_timeout (GESUriClipAssetClass * klass,
|
|||
g_return_if_fail (GES_IS_URI_CLIP_ASSET_CLASS (klass));
|
||||
|
||||
g_object_set (klass->discoverer, "timeout", timeout, NULL);
|
||||
g_object_set (klass->sync_discoverer, "timeout", timeout, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -756,7 +740,6 @@ void
|
|||
_ges_uri_asset_cleanup (void)
|
||||
{
|
||||
g_clear_object (&discoverer);
|
||||
g_clear_object (&sync_discoverer);
|
||||
if (parent_newparent_table) {
|
||||
g_hash_table_destroy (parent_newparent_table);
|
||||
parent_newparent_table = NULL;
|
||||
|
@ -798,28 +781,14 @@ _ges_uri_asset_ensure_setup (gpointer uriasset_class)
|
|||
/* The class structure keeps weak pointers on the discoverers so they
|
||||
* can be properly cleaned up in _ges_uri_asset_cleanup(). */
|
||||
if (!klass->discoverer) {
|
||||
klass->discoverer = discoverer;
|
||||
klass->discoverer = klass->sync_discoverer = discoverer;
|
||||
g_object_add_weak_pointer (G_OBJECT (discoverer),
|
||||
(gpointer *) & klass->discoverer);
|
||||
g_object_add_weak_pointer (G_OBJECT (discoverer),
|
||||
(gpointer *) & klass->sync_discoverer);
|
||||
|
||||
g_signal_connect (klass->discoverer, "discovered",
|
||||
G_CALLBACK (discoverer_discovered_cb), NULL);
|
||||
}
|
||||
|
||||
if (!sync_discoverer) {
|
||||
sync_discoverer = gst_discoverer_new (timeout, &err);
|
||||
|
||||
if (!sync_discoverer) {
|
||||
GST_ERROR ("Could not create discoverer: %s", err->message);
|
||||
g_error_free (err);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!klass->sync_discoverer) {
|
||||
klass->sync_discoverer = sync_discoverer;
|
||||
g_object_add_weak_pointer (G_OBJECT (sync_discoverer),
|
||||
(gpointer *) & klass->sync_discoverer);
|
||||
G_CALLBACK (klass->discovered), NULL);
|
||||
}
|
||||
|
||||
/* We just start the discoverer and let it live */
|
||||
|
|
|
@ -65,7 +65,10 @@ struct _GESUriClipAssetClass
|
|||
GstDiscoverer *discoverer;
|
||||
GstDiscoverer *sync_discoverer;
|
||||
|
||||
gpointer _ges_reserved[GES_PADDING];
|
||||
void (*discovered) (GstDiscoverer * discoverer, GstDiscovererInfo * info,
|
||||
GError * err, gpointer user_data);
|
||||
|
||||
gpointer _ges_reserved[GES_PADDING -1];
|
||||
};
|
||||
|
||||
GES_API
|
||||
|
|
11
ges/ges.c
11
ges/ges.c
|
@ -84,17 +84,6 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
if (!uriasset_klass || !uriasset_klass->discoverer) {
|
||||
GST_ERROR ("missing uri asset class %p or discoverer %p", uriasset_klass,
|
||||
uriasset_klass ? uriasset_klass->discoverer : NULL);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!uriasset_klass->sync_discoverer) {
|
||||
GST_ERROR ("missing sync discoverer");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
nlecomposition_factory = gst_element_factory_find ("nlecomposition");
|
||||
if (!nlecomposition_factory) {
|
||||
GST_ERROR ("The `nlecomposition` object was not found.");
|
||||
|
|
50
tests/check/python/test_assets.py
Normal file
50
tests/check/python/test_assets.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2019 Thibault Saunier <tsaunier@igalia.com>
|
||||
#
|
||||
# This program 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 program 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 program; if not, write to the
|
||||
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
from . import overrides_hack
|
||||
|
||||
import os
|
||||
import gi
|
||||
|
||||
gi.require_version("Gst", "1.0")
|
||||
gi.require_version("GES", "1.0")
|
||||
|
||||
from gi.repository import Gst # noqa
|
||||
from gi.repository import GLib # noqa
|
||||
from gi.repository import GES # noqa
|
||||
import unittest # noqa
|
||||
from unittest import mock
|
||||
|
||||
from .common import GESSimpleTimelineTest # noqa
|
||||
|
||||
Gst.init(None)
|
||||
GES.init()
|
||||
|
||||
|
||||
class TestTimeline(unittest.TestCase):
|
||||
|
||||
def test_request_relocated_assets_sync(self):
|
||||
path = os.path.join(__file__, "../../../", "png.png")
|
||||
with self.assertRaises(GLib.Error):
|
||||
GES.UriClipAsset.request_sync(Gst.filename_to_uri(path))
|
||||
|
||||
GES.add_missing_uri_relocation_uri(Gst.filename_to_uri(os.path.join(__file__, "../../assets")), False)
|
||||
path = os.path.join(__file__, "../../", "png.png")
|
||||
self.assertEqual(GES.UriClipAsset.request_sync(Gst.filename_to_uri(path)).props.id,
|
||||
Gst.filename_to_uri(os.path.join(__file__, "../../assets/png.png")))
|
Loading…
Reference in a new issue