uri-asset: Use the same code path for sync discovery as the async one
authorThibault Saunier <tsaunier@igalia.com>
Fri, 18 Jan 2019 18:45:39 +0000 (15:45 -0300)
committerMathieu Duponchelle <mduponchelle1@gmail.com>
Tue, 29 Jan 2019 00:06:32 +0000 (00:06 +0000)
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)

ges/ges-internal.h
ges/ges-project.c
ges/ges-uri-asset.c
ges/ges-uri-asset.h
ges/ges.c
tests/check/python/test_assets.py [new file with mode: 0644]

index eeb1bb10d1135fabd0841fd247caeddb8cde8b0c..730fb8ec5b31307b93fac1ce3a08b2ea4d5a1185 100644 (file)
@@ -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       *
index 4ad62817f45093215419f4c2581a7b394b31eccc..3cd5e637241eba453123baf1413b5155c81c753f 100644 (file)
@@ -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)
 {
index 915b1bf96051ec2a69036d3ed0accc14c55c2a62..5605d86a444ee16dc44ebb18eacdf42776f7018c 100644 (file)
@@ -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);
-
-    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);
+  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);
 
-  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);
+  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;
   }
 
-  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 */
index abed2da11b5d7a20ed401d7e768ec5cd9150cad9..5bb5587e12325e80f1bae4f45b33b17858ce01b6 100644 (file)
@@ -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
index 41d231a4d29660aa9b69d17e8a92f26e3bde3fc7..a18213e5a5929e82249aa05d9ff03a2be5b47617 100644 (file)
--- a/ges/ges.c
+++ b/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.");
diff --git a/tests/check/python/test_assets.py b/tests/check/python/test_assets.py
new file mode 100644 (file)
index 0000000..afe1590
--- /dev/null
@@ -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")))
\ No newline at end of file