From 20c6668f5a7ce50eeae8b71230d0646ffdefedd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Tue, 3 Aug 2021 11:31:07 +0200 Subject: [PATCH] ges: freeze commit during render In render mode, do not commit the timeline as the position can be invalid and lead to missing frames. Fixes #136 Part-of: --- ges/ges-pipeline.c | 4 +++- ges/ges-timeline.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ ges/ges-timeline.h | 4 ++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/ges/ges-pipeline.c b/ges/ges-pipeline.c index 4988aec04f..9934059a78 100644 --- a/ges/ges-pipeline.c +++ b/ges/ges-pipeline.c @@ -1228,6 +1228,7 @@ ges_pipeline_set_mode (GESPipeline * pipeline, GESPipelineFlags mode) /* Disable render bin */ GST_DEBUG ("Disabling rendering bin"); + ges_timeline_thaw_commit (pipeline->priv->timeline); gst_object_ref (pipeline->priv->encodebin); gst_object_ref (pipeline->priv->urisink); gst_bin_remove_many (GST_BIN_CAST (pipeline), @@ -1249,7 +1250,8 @@ ges_pipeline_set_mode (GESPipeline * pipeline, GESPipelineFlags mode) (mode & (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER))) { /* Adding render bin */ GST_DEBUG ("Adding render bin"); - + /* in render mode the commit needs to be locked, see #136 */ + ges_timeline_freeze_commit (pipeline->priv->timeline); if (G_UNLIKELY (pipeline->priv->urisink == NULL)) { GST_ERROR_OBJECT (pipeline, "Output URI not set !"); return FALSE; diff --git a/ges/ges-timeline.c b/ges/ges-timeline.c index ac60f23e6e..6fe3f21af9 100644 --- a/ges/ges-timeline.c +++ b/ges/ges-timeline.c @@ -225,6 +225,8 @@ struct _GESTimelinePrivate /* For ges_timeline_commit_sync */ GMutex commited_lock; GCond commited_cond; + gboolean commit_frozen; + gboolean commit_delayed; GThread *valid_thread; gboolean disposed; @@ -2784,6 +2786,12 @@ ges_timeline_commit_unlocked (GESTimeline * timeline) GList *tmp; gboolean res = TRUE; + if (timeline->priv->commit_frozen) { + GST_DEBUG_OBJECT (timeline, "commit locked"); + timeline->priv->commit_delayed = TRUE; + return res; + } + GST_DEBUG_OBJECT (timeline, "commiting changes"); timeline_tree_create_transitions (timeline->priv->tree, @@ -2932,6 +2940,51 @@ ges_timeline_commit_sync (GESTimeline * timeline) return ret; } +/** + * ges_timeline_freeze_commit: + * @timeline: The #GESTimeline + * + * Freezes the timeline from being committed. This is usually needed while the + * timeline is being rendered to ensure that not change to the timeline are + * taken into account during that moment. Once the rendering is done, you + * should call #ges_timeline_thaw_commit so that comiting becomes possible + * again and any call to `commit()` that happened during the rendering is + * actually taken into account. + * + * Since: 1.20 + * + */ +void +ges_timeline_freeze_commit (GESTimeline * timeline) +{ + LOCK_DYN (timeline); + timeline->priv->commit_frozen = TRUE; + UNLOCK_DYN (timeline); +} + +/** + * ges_timeline_thaw_commit: + * @timeline: The #GESTimeline + * + * Thaw the timeline so that comiting becomes possible + * again and any call to `commit()` that happened during the rendering is + * actually taken into account. + * + * Since: 1.20 + * + */ +void +ges_timeline_thaw_commit (GESTimeline * timeline) +{ + LOCK_DYN (timeline); + timeline->priv->commit_frozen = FALSE; + UNLOCK_DYN (timeline); + if (timeline->priv->commit_delayed) { + ges_timeline_commit (timeline); + timeline->priv->commit_delayed = FALSE; + } +} + /** * ges_timeline_get_duration: * @timeline: The #GESTimeline diff --git a/ges/ges-timeline.h b/ges/ges-timeline.h index 16a800b2c0..00947d8ba6 100644 --- a/ges/ges-timeline.h +++ b/ges/ges-timeline.h @@ -126,6 +126,10 @@ GES_API gboolean ges_timeline_commit (GESTimeline * timeline); GES_API gboolean ges_timeline_commit_sync (GESTimeline * timeline); +GES_API +void ges_timeline_freeze_commit (GESTimeline * timeline); +GES_API +void ges_timeline_thaw_commit (GESTimeline * timeline); GES_API GstClockTime ges_timeline_get_duration (GESTimeline *timeline);