diff --git a/girs/GES-1.0.gir b/girs/GES-1.0.gir
index 8e403664f7..9e4a497255 100644
--- a/girs/GES-1.0.gir
+++ b/girs/GES-1.0.gir
@@ -7138,18 +7138,18 @@ is really not in good shape and is deprecated.
#GESAsset with `GES_TYPE_TIMELINE` as @extractable_type itself. That
means that you can extract #GESTimeline from a project as followed:
-|[
- GESProject *project;
- GESTimeline *timeline;
+```c
+GESProject *project;
+GESTimeline *timeline;
- project = ges_project_new ("file:///path/to/a/valid/project/uri");
+project = ges_project_new ("file:///path/to/a/valid/project/uri");
- // Here you can connect to the various signal to get more infos about
- // what is happening and recover from errors if possible
- ...
+// Here you can connect to the various signal to get more infos about
+// what is happening and recover from errors if possible
+...
- timeline = ges_asset_extract (GES_ASSET (project));
-]|
+timeline = ges_asset_extract (GES_ASSET (project));
+```
The #GESProject class offers a higher level API to handle #GESAsset-s.
It lets you request new asset, and it informs you about new assets through
@@ -7185,7 +7185,9 @@ other locations, it will never be updated again and the first valid URI is
the URI it will keep refering to.
- A newly created #GESProject
+ A newly created #GESProject
+
+MT safe.
@@ -7310,7 +7312,9 @@ the URI it will keep refering to.
%TRUE if the asset could be added %FALSE it was already
-in the project
+in the project.
+
+MT safe.
@@ -7326,11 +7330,13 @@ in the project
Adds @profile to the project. It lets you save in what format
-the project has been renders and keep a reference to those formats.
-Also, those formats will be saves to the project file when possible.
+the project will be rendered and keep a reference to those formats.
+Also, those formats will be saved to the project file when possible.
- %TRUE if @profile could be added, %FALSE otherwize
+ %TRUE if @profile could be added, %FALSE otherwise
+
+MT safe.
@@ -7340,13 +7346,16 @@ Also, those formats will be saves to the project file when possible.
A #GstEncodingProfile to add to the project. If a profile with
-the same name already exists, it will be replaced
+the same name already exists, it will be replaced.
- Adds a formatter as used to load @project
+ Adds a formatter to be used to load @project
+
+
+MT safe.
@@ -7368,8 +7377,10 @@ the same name already exists, it will be replaced
@project
- %TRUE if the asset started to be added %FALSE it was already
-in the project
+ %TRUE if the asset was added and started loading, %FALSE it was
+already in the project.
+
+MT safe.
@@ -7393,7 +7404,9 @@ in the project
@project
- The newly created #GESAsset or %NULL.
+ The newly created #GESAsset or %NULL.
+
+MT safe.
@@ -7415,7 +7428,9 @@ in the project
The #GESAsset with
-@id or %NULL if no asset with @id as an ID
+@id or %NULL if no asset with @id as an ID
+
+MT safe.
@@ -7440,7 +7455,9 @@ to retrieve from @object
A set of loading asset
that will be added to @project. Note that those Asset are *not* loaded yet,
-and thus can not be used
+and thus can not be used.
+
+MT safe.
@@ -7456,7 +7473,9 @@ and thus can not be used
Retrieve the uri that is currently set on @project
- a newly allocated string representing uri.
+ a newly allocated string representing uri.
+
+MT safe.
@@ -7473,7 +7492,9 @@ in time.
The list of
-#GESAsset the object contains
+#GESAsset the object contains
+
+MT safe.
@@ -7512,7 +7533,9 @@ list of #GstEncodingProfile used in @project
Loads @project into @timeline
- %TRUE if the project could be loaded %FALSE otherwize.
+ %TRUE if the project could be loaded %FALSE otherwise.
+
+MT safe.
@@ -7527,10 +7550,12 @@ list of #GstEncodingProfile used in @project
- remove a @asset to from @project.
+ Remove @asset from @project.
- %TRUE if the asset could be removed %FALSE otherwise
+ %TRUE if the asset could be removed %FALSE otherwise
+
+MT safe.
@@ -7550,7 +7575,9 @@ is one of the timelines that have been extracted from @project
(using ges_asset_extract (@project);)
- %TRUE if the project could be save, %FALSE otherwize
+ %TRUE if the project could be save, %FALSE otherwise
+
+MT safe.
@@ -7687,7 +7714,7 @@ failed loading
- |[
+ ```c
static gchar
source_moved_cb (GESProject *project, GError *error, GESAsset *asset_with_error)
{
@@ -7703,7 +7730,7 @@ main (int argc, gchar ** argv)
g_signal_connect (project, "missing-uri", source_moved_cb, NULL);
timeline = ges_asset_extract (GES_ASSET (project));
}
-]|
+```
The new URI of @wrong_asset
diff --git a/subprojects/gst-editing-services/ges/ges-internal.h b/subprojects/gst-editing-services/ges/ges-internal.h
index cdb1495faf..fe3759da6e 100644
--- a/subprojects/gst-editing-services/ges/ges-internal.h
+++ b/subprojects/gst-editing-services/ges/ges-internal.h
@@ -191,6 +191,9 @@ ges_timeline_get_smart_rendering (GESTimeline *timeline);
G_GNUC_INTERNAL GstStreamCollection*
ges_timeline_get_stream_collection (GESTimeline *timeline);
+G_GNUC_INTERNAL gboolean
+ges_timeline_in_current_thread (GESTimeline *timeline);
+
G_GNUC_INTERNAL void
ges_auto_transition_set_source (GESAutoTransition * self, GESTrackElement * source, GESEdge edge);
diff --git a/subprojects/gst-editing-services/ges/ges-project.c b/subprojects/gst-editing-services/ges/ges-project.c
index 48e7d0ceb7..477fb9de74 100644
--- a/subprojects/gst-editing-services/ges/ges-project.c
+++ b/subprojects/gst-editing-services/ges/ges-project.c
@@ -26,18 +26,18 @@
* #GESAsset with `GES_TYPE_TIMELINE` as @extractable_type itself. That
* means that you can extract #GESTimeline from a project as followed:
*
- * |[
- * GESProject *project;
- * GESTimeline *timeline;
+ * ```c
+ * GESProject *project;
+ * GESTimeline *timeline;
*
- * project = ges_project_new ("file:///path/to/a/valid/project/uri");
+ * project = ges_project_new ("file:///path/to/a/valid/project/uri");
*
- * // Here you can connect to the various signal to get more infos about
- * // what is happening and recover from errors if possible
- * ...
+ * // Here you can connect to the various signal to get more infos about
+ * // what is happening and recover from errors if possible
+ * ...
*
- * timeline = ges_asset_extract (GES_ASSET (project));
- * ]|
+ * timeline = ges_asset_extract (GES_ASSET (project));
+ * ```
*
* The #GESProject class offers a higher level API to handle #GESAsset-s.
* It lets you request new asset, and it informs you about new assets through
@@ -72,6 +72,10 @@
static GPtrArray *new_paths = NULL;
static GHashTable *tried_uris = NULL;
+#define GES_PROJECT_LOCK(project) (g_mutex_lock (&project->priv->lock))
+#define GES_PROJECT_UNLOCK(project) (g_mutex_unlock (&project->priv->lock))
+
+/* Fields are protected by GES_PROJECT_LOCK */
struct _GESProjectPrivate
{
GHashTable *assets;
@@ -85,6 +89,8 @@ struct _GESProjectPrivate
gchar *uri;
GList *encoding_profiles;
+
+ GMutex lock;
};
typedef struct EmitLoadedInIdle
@@ -150,9 +156,11 @@ _emit_loaded_in_idle (EmitLoadedInIdle * data)
* @project: The project to add a formatter to
* @formatter: A formatter used by @project
*
- * Adds a formatter as used to load @project
+ * Adds a formatter to be used to load @project
*
* Since: 1.18
+ *
+ * MT safe.
*/
void
ges_project_add_formatter (GESProject * project, GESFormatter * formatter)
@@ -160,27 +168,35 @@ ges_project_add_formatter (GESProject * project, GESFormatter * formatter)
GESProjectPrivate *priv = GES_PROJECT (project)->priv;
ges_formatter_set_project (formatter, project);
+ GES_PROJECT_LOCK (project);
priv->formatters = g_list_append (priv->formatters, formatter);
+ GES_PROJECT_UNLOCK (project);
gst_object_ref_sink (formatter);
}
+/* Internally takes project mutex */
static void
ges_project_remove_formatter (GESProject * project, GESFormatter * formatter)
{
GList *tmp;
GESProjectPrivate *priv = GES_PROJECT (project)->priv;
+ GES_PROJECT_LOCK (project);
for (tmp = priv->formatters; tmp; tmp = tmp->next) {
if (tmp->data == formatter) {
gst_object_unref (formatter);
priv->formatters = g_list_delete_link (priv->formatters, tmp);
- return;
+ goto done;
}
}
+
+done:
+ GES_PROJECT_UNLOCK (project);
}
+/* Internally takes project mutex */
static void
ges_project_set_uri (GESProject * project, const gchar * uri)
{
@@ -188,17 +204,19 @@ ges_project_set_uri (GESProject * project, const gchar * uri)
g_return_if_fail (GES_IS_PROJECT (project));
+ GES_PROJECT_LOCK (project);
+
priv = project->priv;
if (priv->uri) {
if (g_strcmp0 (priv->uri, uri))
GST_WARNING_OBJECT (project, "Trying to reset URI, this is prohibited");
- return;
+ goto done;
}
if (uri == NULL) {
GST_LOG_OBJECT (project, "Uri should not be NULL");
- return;
+ goto done;
}
priv->uri = g_strdup (uri);
@@ -206,20 +224,29 @@ ges_project_set_uri (GESProject * project, const gchar * uri)
/* We use that URI as ID */
ges_asset_set_id (GES_ASSET (project), uri);
- return;
+done:
+ GES_PROJECT_UNLOCK (project);
}
+/* Internally takes project mutex */
static gboolean
_load_project (GESProject * project, GESTimeline * timeline, GError ** error)
{
GError *lerr = NULL;
GESProjectPrivate *priv;
GESFormatter *formatter;
+ gboolean has_uri = FALSE;
+ gchar *uri = NULL;
priv = GES_PROJECT (project)->priv;
g_signal_emit (project, _signals[LOADING_SIGNAL], 0, timeline);
- if (priv->uri == NULL) {
+
+ GES_PROJECT_LOCK (project);
+ has_uri = priv->uri != NULL;
+ GES_PROJECT_UNLOCK (project);
+
+ if (!has_uri) {
const gchar *id = ges_asset_get_id (GES_ASSET (project));
if (id && gst_uri_is_valid (id)) {
@@ -241,6 +268,8 @@ _load_project (GESProject * project, GESTimeline * timeline, GError ** error)
}
}
+ GES_PROJECT_LOCK (project);
+
if (priv->formatter_asset == NULL)
priv->formatter_asset = _find_formatter_asset_for_id (priv->uri);
@@ -257,17 +286,29 @@ _load_project (GESProject * project, GESTimeline * timeline, GError ** error)
goto failed;
}
+ uri = g_strdup (priv->uri);
+
+ GES_PROJECT_UNLOCK (project);
ges_project_add_formatter (GES_PROJECT (project), formatter);
- ges_formatter_load_from_uri (formatter, timeline, priv->uri, &lerr);
+ /* ges_formatter_load_from_uri() might indirectly lead to a
+ ges_project_add_asset() call, so do the loading unlocked. */
+ ges_formatter_load_from_uri (formatter, timeline, uri, &lerr);
+ GES_PROJECT_LOCK (project);
+
+ g_free (uri);
+
if (lerr) {
GST_WARNING_OBJECT (project, "Could not load the timeline,"
" returning: %s", lerr->message);
goto failed;
}
+ GES_PROJECT_UNLOCK (project);
return TRUE;
failed:
+ GES_PROJECT_UNLOCK (project);
+
if (lerr)
g_propagate_error (error, lerr);
return FALSE;
@@ -454,7 +495,9 @@ _get_property (GESProject * project, guint property_id,
switch (property_id) {
case PROP_URI:
+ GES_PROJECT_LOCK (project);
g_value_set_string (value, priv->uri);
+ GES_PROJECT_UNLOCK (project);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (project, property_id, pspec);
@@ -467,7 +510,9 @@ _set_property (GESProject * project, guint property_id,
{
switch (property_id) {
case PROP_URI:
+ GES_PROJECT_LOCK (project);
project->priv->uri = g_value_dup_string (value);
+ GES_PROJECT_UNLOCK (project);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (project, property_id, pspec);
@@ -557,7 +602,7 @@ ges_project_class_init (GESProjectClass * klass)
* @wrong_asset: The asset with the wrong ID, you should us it and its content
* only to find out what the new location is.
*
- * |[
+ * ```c
* static gchar
* source_moved_cb (GESProject *project, GError *error, GESAsset *asset_with_error)
* {
@@ -573,7 +618,7 @@ ges_project_class_init (GESProjectClass * klass)
* g_signal_connect (project, "missing-uri", source_moved_cb, NULL);
* timeline = ges_asset_extract (GES_ASSET (project));
* }
- * ]|
+ * ```
*
* Returns: (transfer full) (nullable): The new URI of @wrong_asset
*/
@@ -654,6 +699,7 @@ ges_project_internal_asset_id (GESAsset * asset)
(asset), ges_asset_get_id (asset));
}
+/* Internally takes project mutex */
static void
_send_error_loading_asset (GESProject * project, GESAsset * asset,
GError * error)
@@ -662,12 +708,15 @@ _send_error_loading_asset (GESProject * project, GESAsset * asset,
const gchar *id = ges_asset_get_id (asset);
GST_DEBUG_OBJECT (project, "Sending error loading asset for %s", id);
+ GES_PROJECT_LOCK (project);
g_hash_table_remove (project->priv->loading_assets, internal_id);
g_hash_table_add (project->priv->loaded_with_error, internal_id);
+ GES_PROJECT_UNLOCK (project);
g_signal_emit (project, _signals[ERROR_LOADING_ASSET], 0, error,
id, ges_asset_get_extractable_type (asset));
}
+/* Internally takes project mutex */
gchar *
ges_project_try_updating_id (GESProject * project, GESAsset * asset,
GError * error)
@@ -707,7 +756,9 @@ ges_project_try_updating_id (GESProject * project, GESAsset * asset,
}
internal_id = ges_project_internal_asset_id (asset);
+ GES_PROJECT_LOCK (project);
g_hash_table_remove (project->priv->loading_assets, internal_id);
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
if (new_id == NULL)
@@ -752,7 +803,7 @@ new_asset_cb (GESAsset * source, GAsyncResult * res, GESProject * project)
* Emits the "loaded" signal. This method should be called by sublasses when
* the project is fully loaded.
*
- * Returns: %TRUE if the signale could be emitted %FALSE otherwize
+ * Returns: %TRUE if the signale could be emitted %FALSE otherwise
*/
gboolean
ges_project_set_loaded (GESProject * project, GESFormatter * formatter,
@@ -764,13 +815,16 @@ ges_project_set_loaded (GESProject * project, GESFormatter * formatter,
error);
}
- GST_INFO_OBJECT (project, "Emit project loaded");
- if (GST_STATE (formatter->timeline) < GST_STATE_PAUSED) {
+ if (!ges_timeline_in_current_thread (formatter->timeline)) {
+ GST_INFO_OBJECT (project, "Loaded in a different thread, "
+ "not committing timeline");
+ } else if (GST_STATE (formatter->timeline) < GST_STATE_PAUSED) {
timeline_fill_gaps (formatter->timeline);
} else {
ges_timeline_commit (formatter->timeline);
}
+ GST_INFO_OBJECT (project, "Emit project loaded");
g_signal_emit (project, _signals[LOADED_SIGNAL], 0, formatter->timeline);
/* We are now done with that formatter */
@@ -778,6 +832,7 @@ ges_project_set_loaded (GESProject * project, GESFormatter * formatter,
return TRUE;
}
+/* Internally takes project mutex */
void
ges_project_add_loading_asset (GESProject * project, GType extractable_type,
const gchar * id)
@@ -785,9 +840,14 @@ ges_project_add_loading_asset (GESProject * project, GType extractable_type,
GESAsset *asset;
if ((asset = ges_asset_cache_lookup (extractable_type, id))) {
+ GES_PROJECT_LOCK (project);
if (g_hash_table_insert (project->priv->loading_assets,
- ges_project_internal_asset_id (asset), gst_object_ref (asset)))
+ ges_project_internal_asset_id (asset), gst_object_ref (asset))) {
+ GES_PROJECT_UNLOCK (project);
g_signal_emit (project, _signals[ASSET_LOADING_SIGNAL], 0, asset);
+ } else {
+ GES_PROJECT_UNLOCK (project);
+ }
}
}
@@ -807,8 +867,10 @@ ges_project_add_loading_asset (GESProject * project, GType extractable_type,
* "asset-added" signal to get the asset when it finally gets added to
* @project
*
- * Returns: %TRUE if the asset started to be added %FALSE it was already
- * in the project
+ * Returns: %TRUE if the asset was added and started loading, %FALSE it was
+ * already in the project.
+ *
+ * MT safe.
*/
gboolean
ges_project_create_asset (GESProject * project, const gchar * id,
@@ -823,13 +885,16 @@ ges_project_create_asset (GESProject * project, const gchar * id,
id = g_type_name (extractable_type);
internal_id = ges_project_internal_extractable_type_id (extractable_type, id);
+ GES_PROJECT_LOCK (project);
if (g_hash_table_lookup (project->priv->assets, internal_id) ||
g_hash_table_lookup (project->priv->loading_assets, internal_id) ||
g_hash_table_lookup (project->priv->loaded_with_error, internal_id)) {
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
return FALSE;
}
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
/* TODO Add a GCancellable somewhere in our API */
@@ -852,6 +917,8 @@ ges_project_create_asset (GESProject * project, const gchar * id,
* @project
*
* Returns: (transfer full) (nullable): The newly created #GESAsset or %NULL.
+ *
+ * MT safe.
*/
GESAsset *
ges_project_create_asset_sync (GESProject * project, const gchar * id,
@@ -869,16 +936,20 @@ ges_project_create_asset_sync (GESProject * project, const gchar * id,
id = g_type_name (extractable_type);
internal_id = ges_project_internal_extractable_type_id (extractable_type, id);
+ GES_PROJECT_LOCK (project);
if ((asset = g_hash_table_lookup (project->priv->assets, internal_id))) {
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
return gst_object_ref (asset);
} else if (g_hash_table_lookup (project->priv->loading_assets, internal_id) ||
g_hash_table_lookup (project->priv->loaded_with_error, internal_id)) {
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
return NULL;
}
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
/* TODO Add a GCancellable somewhere in our API */
@@ -894,8 +965,14 @@ ges_project_create_asset_sync (GESProject * project, const gchar * id,
retry = FALSE;
internal_id =
ges_project_internal_extractable_type_id (extractable_type, id);
- if ((!g_hash_table_lookup (project->priv->assets, internal_id)))
+ GES_PROJECT_LOCK (project);
+ if ((!g_hash_table_lookup (project->priv->assets, internal_id))) {
+ GES_PROJECT_UNLOCK (project);
g_signal_emit (project, _signals[ASSET_LOADING_SIGNAL], 0, asset);
+ } else {
+ GES_PROJECT_UNLOCK (project);
+ }
+
g_free (internal_id);
if (possible_id) {
@@ -941,7 +1018,9 @@ ges_project_create_asset_sync (GESProject * project, const gchar * id,
* @asset.
*
* Returns: %TRUE if the asset could be added %FALSE it was already
- * in the project
+ * in the project.
+ *
+ * MT safe.
*/
gboolean
ges_project_add_asset (GESProject * project, GESAsset * asset)
@@ -949,15 +1028,18 @@ ges_project_add_asset (GESProject * project, GESAsset * asset)
gchar *internal_id;
g_return_val_if_fail (GES_IS_PROJECT (project), FALSE);
+ GES_PROJECT_LOCK (project);
internal_id = ges_project_internal_asset_id (asset);
if (g_hash_table_lookup (project->priv->assets, internal_id)) {
g_free (internal_id);
+ GES_PROJECT_UNLOCK (project);
return TRUE;
}
g_hash_table_insert (project->priv->assets, internal_id,
gst_object_ref (asset));
g_hash_table_remove (project->priv->loading_assets, internal_id);
+ GES_PROJECT_UNLOCK (project);
GST_DEBUG_OBJECT (project, "Asset added: %s", ges_asset_get_id (asset));
g_signal_emit (project, _signals[ASSET_ADDED_SIGNAL], 0, asset);
@@ -969,9 +1051,11 @@ ges_project_add_asset (GESProject * project, GESAsset * asset)
* @project: A #GESProject
* @asset: (transfer none): A #GESAsset to remove from @project
*
- * remove a @asset to from @project.
+ * Remove @asset from @project.
*
* Returns: %TRUE if the asset could be removed %FALSE otherwise
+ *
+ * MT safe.
*/
gboolean
ges_project_remove_asset (GESProject * project, GESAsset * asset)
@@ -982,7 +1066,9 @@ ges_project_remove_asset (GESProject * project, GESAsset * asset)
g_return_val_if_fail (GES_IS_PROJECT (project), FALSE);
internal_id = ges_project_internal_asset_id (asset);
+ GES_PROJECT_LOCK (project);
ret = g_hash_table_remove (project->priv->assets, internal_id);
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
g_signal_emit (project, _signals[ASSET_REMOVED_SIGNAL], 0, asset);
@@ -998,6 +1084,8 @@ ges_project_remove_asset (GESProject * project, GESAsset * asset)
*
* Returns: (transfer full) (nullable): The #GESAsset with
* @id or %NULL if no asset with @id as an ID
+ *
+ * MT safe.
*/
GESAsset *
ges_project_get_asset (GESProject * project, const gchar * id,
@@ -1011,7 +1099,9 @@ ges_project_get_asset (GESProject * project, const gchar * id,
NULL);
internal_id = ges_project_internal_extractable_type_id (extractable_type, id);
+ GES_PROJECT_LOCK (project);
asset = g_hash_table_lookup (project->priv->assets, internal_id);
+ GES_PROJECT_UNLOCK (project);
g_free (internal_id);
if (asset)
@@ -1032,6 +1122,8 @@ ges_project_get_asset (GESProject * project, const gchar * id,
*
* Returns: (transfer full) (element-type GESAsset): The list of
* #GESAsset the object contains
+ *
+ * MT safe.
*/
GList *
ges_project_list_assets (GESProject * project, GType filter)
@@ -1044,12 +1136,14 @@ ges_project_list_assets (GESProject * project, GType filter)
g_return_val_if_fail (filter == G_TYPE_NONE
|| g_type_is_a (filter, GES_TYPE_EXTRACTABLE), NULL);
+ GES_PROJECT_LOCK (project);
g_hash_table_iter_init (&iter, project->priv->assets);
while (g_hash_table_iter_next (&iter, &key, &value)) {
if (g_type_is_a (ges_asset_get_extractable_type (GES_ASSET (value)),
filter))
ret = g_list_append (ret, gst_object_ref (value));
}
+ GES_PROJECT_UNLOCK (project);
return ret;
}
@@ -1070,7 +1164,9 @@ ges_project_list_assets (GESProject * project, GType filter)
* is one of the timelines that have been extracted from @project
* (using ges_asset_extract (@project);)
*
- * Returns: %TRUE if the project could be save, %FALSE otherwize
+ * Returns: %TRUE if the project could be save, %FALSE otherwise
+ *
+ * MT safe.
*/
gboolean
ges_project_save (GESProject * project, GESTimeline * timeline,
@@ -1087,6 +1183,8 @@ ges_project_save (GESProject * project, GESTimeline * timeline,
GES_TYPE_FORMATTER), FALSE);
g_return_val_if_fail ((error == NULL || *error == NULL), FALSE);
+ GES_PROJECT_LOCK (project);
+
tl_asset = ges_extractable_get_asset (GES_EXTRACTABLE (timeline));
if (tl_asset == NULL && project->priv->uri == NULL) {
GESAsset *asset = ges_asset_cache_lookup (GES_TYPE_PROJECT, uri);
@@ -1123,12 +1221,17 @@ ges_project_save (GESProject * project, GESTimeline * timeline,
goto out;
}
+ GES_PROJECT_UNLOCK (project);
ges_project_add_formatter (project, formatter);
ret = ges_formatter_save_to_uri (formatter, timeline, uri, overwrite, error);
if (ret && project->priv->uri == NULL)
ges_project_set_uri (project, uri);
+ GES_PROJECT_LOCK (project);
+
out:
+ GES_PROJECT_UNLOCK (project);
+
if (formatter_asset)
gst_object_unref (formatter_asset);
ges_project_remove_formatter (project, formatter);
@@ -1147,6 +1250,8 @@ out:
* the URI it will keep refering to.
*
* Returns: A newly created #GESProject
+ *
+ * MT safe.
*/
GESProject *
ges_project_new (const gchar * uri)
@@ -1176,7 +1281,9 @@ ges_project_new (const gchar * uri)
*
* Loads @project into @timeline
*
- * Returns: %TRUE if the project could be loaded %FALSE otherwize.
+ * Returns: %TRUE if the project could be loaded %FALSE otherwise.
+ *
+ * MT safe.
*/
gboolean
ges_project_load (GESProject * project, GESTimeline * timeline, GError ** error)
@@ -1201,31 +1308,37 @@ ges_project_load (GESProject * project, GESTimeline * timeline, GError ** error)
* Retrieve the uri that is currently set on @project
*
* Returns: (transfer full) (nullable): a newly allocated string representing uri.
+ *
+ * MT safe.
*/
gchar *
ges_project_get_uri (GESProject * project)
{
- GESProjectPrivate *priv;
+ gchar *uri = NULL;
g_return_val_if_fail (GES_IS_PROJECT (project), FALSE);
- priv = project->priv;
- if (priv->uri)
- return g_strdup (priv->uri);
- return NULL;
+ GES_PROJECT_LOCK (project);
+ if (project->priv->uri)
+ uri = g_strdup (project->priv->uri);
+ GES_PROJECT_UNLOCK (project);
+
+ return uri;
}
/**
* ges_project_add_encoding_profile:
* @project: A #GESProject
* @profile: A #GstEncodingProfile to add to the project. If a profile with
- * the same name already exists, it will be replaced
+ * the same name already exists, it will be replaced.
*
* Adds @profile to the project. It lets you save in what format
- * the project has been renders and keep a reference to those formats.
- * Also, those formats will be saves to the project file when possible.
+ * the project will be rendered and keep a reference to those formats.
+ * Also, those formats will be saved to the project file when possible.
*
- * Returns: %TRUE if @profile could be added, %FALSE otherwize
+ * Returns: %TRUE if @profile could be added, %FALSE otherwise
+ *
+ * MT safe.
*/
gboolean
ges_project_add_encoding_profile (GESProject * project,
@@ -1237,6 +1350,7 @@ ges_project_add_encoding_profile (GESProject * project,
g_return_val_if_fail (GES_IS_PROJECT (project), FALSE);
g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
+ GES_PROJECT_LOCK (project);
priv = project->priv;
for (tmp = priv->encoding_profiles; tmp; tmp = tmp->next) {
GstEncodingProfile *tmpprofile = GST_ENCODING_PROFILE (tmp->data);
@@ -1248,13 +1362,14 @@ ges_project_add_encoding_profile (GESProject * project,
gst_object_unref (tmp->data);
tmp->data = gst_object_ref (profile);
+ GES_PROJECT_UNLOCK (project);
return TRUE;
}
}
priv->encoding_profiles = g_list_prepend (priv->encoding_profiles,
gst_object_ref (profile));
-
+ GES_PROJECT_UNLOCK (project);
return TRUE;
}
@@ -1284,7 +1399,9 @@ ges_project_list_encoding_profiles (GESProject * project)
*
* Returns: (transfer full) (element-type GES.Asset): A set of loading asset
* that will be added to @project. Note that those Asset are *not* loaded yet,
- * and thus can not be used
+ * and thus can not be used.
+ *
+ * MT safe.
*/
GList *
ges_project_get_loading_assets (GESProject * project)
@@ -1296,9 +1413,11 @@ ges_project_get_loading_assets (GESProject * project)
g_return_val_if_fail (GES_IS_PROJECT (project), NULL);
+ GES_PROJECT_LOCK (project);
g_hash_table_iter_init (&iter, project->priv->loading_assets);
while (g_hash_table_iter_next (&iter, &key, &value))
ret = g_list_prepend (ret, gst_object_ref (value));
+ GES_PROJECT_UNLOCK (project);
return ret;
}
diff --git a/subprojects/gst-editing-services/ges/ges-timeline.c b/subprojects/gst-editing-services/ges/ges-timeline.c
index 971e4d7ac3..5d033d6e32 100644
--- a/subprojects/gst-editing-services/ges/ges-timeline.c
+++ b/subprojects/gst-editing-services/ges/ges-timeline.c
@@ -2165,6 +2165,12 @@ ges_timeline_get_stream_collection (GESTimeline * timeline)
return gst_object_ref (timeline->priv->stream_collection);
}
+gboolean
+ges_timeline_in_current_thread (GESTimeline * timeline)
+{
+ return timeline->priv->valid_thread == g_thread_self ();
+}
+
/**** API *****/
/**
* ges_timeline_new: