ges: Add API to disable timeline coherence checks

There are cases where user might want to be in full control of the
timeline and not be limited by the checks that are being done by GES
to go from one timeline layout to another, this should be doable as
it is a valid use case.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3501>
This commit is contained in:
Thibault Saunier 2022-10-25 23:12:00 -03:00 committed by GStreamer Marge Bot
parent ac6b3e9a45
commit 712bda84db
4 changed files with 98 additions and 1 deletions

View file

@ -929,6 +929,11 @@ timeline_tree_can_move_elements (GNode * root, GHashTable * moving,
GError ** error) GError ** error)
{ {
TreeIterationData data = tree_iteration_data_init; TreeIterationData data = tree_iteration_data_init;
if (ges_timeline_get_edit_apis_disabled (root->data)) {
return TRUE;
}
data.moving = moving; data.moving = moving;
data.root = root; data.root = root;
data.res = TRUE; data.res = TRUE;
@ -1703,6 +1708,10 @@ timeline_tree_can_move_element (GNode * root,
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
if (ges_timeline_get_edit_apis_disabled (root->data)) {
return TRUE;
}
if (layer_prio == GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY if (layer_prio == GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY
&& priority != layer_prio) { && priority != layer_prio) {
GST_INFO_OBJECT (element, "Cannot move to a layer when no layer " GST_INFO_OBJECT (element, "Cannot move to a layer when no layer "

View file

@ -115,6 +115,10 @@
* transition object will be kept, but with its timing and layer adjusted * transition object will be kept, but with its timing and layer adjusted
* accordingly. * accordingly.
* *
* NOTE: if you know what you are doing and want to be in full control of the
* timeline layout, you can disable the edit APIs with
* #ges_timeline_disable_edit_apis.
*
* ## Saving * ## Saving
* *
* To save/load a timeline, you can use the ges_timeline_load_from_uri() * To save/load a timeline, you can use the ges_timeline_load_from_uri()
@ -234,6 +238,7 @@ struct _GESTimelinePrivate
GstStreamCollection *stream_collection; GstStreamCollection *stream_collection;
gboolean rendering_smartly; gboolean rendering_smartly;
gboolean disable_edit_apis;
}; };
/* private structure to contain our track-related information */ /* private structure to contain our track-related information */
@ -2947,7 +2952,7 @@ ges_timeline_commit_sync (GESTimeline * timeline)
* Freezes the timeline from being committed. This is usually needed while the * 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 * 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 * taken into account during that moment. Once the rendering is done, you
* should call #ges_timeline_thaw_commit so that comiting becomes possible * should call #ges_timeline_thaw_commit so that committing becomes possible
* again and any call to `commit()` that happened during the rendering is * again and any call to `commit()` that happened during the rendering is
* actually taken into account. * actually taken into account.
* *
@ -3038,6 +3043,7 @@ ges_timeline_set_auto_transition (GESTimeline * timeline,
GESLayer *layer; GESLayer *layer;
g_return_if_fail (GES_IS_TIMELINE (timeline)); g_return_if_fail (GES_IS_TIMELINE (timeline));
g_return_if_fail (!timeline->priv->disable_edit_apis);
CHECK_THREAD (timeline); CHECK_THREAD (timeline);
timeline->priv->auto_transition = auto_transition; timeline->priv->auto_transition = auto_transition;
@ -3387,3 +3393,64 @@ ges_timeline_get_frame_at (GESTimeline * self, GstClockTime timestamp)
return gst_util_uint64_scale (timestamp, fps_n, fps_d * GST_SECOND); return gst_util_uint64_scale (timestamp, fps_n, fps_d * GST_SECOND);
} }
/**
* ges_timeline_disable_edit_apis:
* @self: A #GESTimeline
* @disable_edit_apis: %TRUE to disable all the edit APIs so the user is in full
* control of ensuring timeline state validity %FALSE otherwise.
*
* WARNING: When using that mode, GES won't guarantee the coherence of the
* timeline. You need to ensure that the rules described in the [Overlaps and
* auto transitions](#overlaps-and-autotransitions) section are respected any time
* the timeline is [commited](ges_timeline_commit) (otherwise playback will most
* probably fail in different ways).
*
* When disabling editing APIs, GES won't be able to enforce the rules that
* makes the timeline overall state to be valid but some feature won't be
* usable:
* * #GESTimeline:snapping-distance
* * #GESTimeline:auto-transition
*
* Since: 1.22
*/
void
ges_timeline_disable_edit_apis (GESTimeline * self, gboolean disable_edit_apis)
{
CHECK_THREAD (self);
g_return_if_fail (GES_IS_TIMELINE (self));
if (disable_edit_apis) {
if (self->priv->snapping_distance > 0) {
GST_INFO_OBJECT (self,
"Disabling snapping as we are disabling edit APIs");
ges_timeline_set_snapping_distance (self, 0);
}
if (self->priv->auto_transition || self->priv->auto_transitions) {
GST_INFO_OBJECT (self,
"Disabling auto transitions as we are disabling auto edit APIs");
ges_timeline_set_auto_transition (self, FALSE);
}
}
self->priv->disable_edit_apis = disable_edit_apis;
}
/**
* ges_timeline_get_edit_apis_disabled:
* @self: A #GESTimeline
*
* Returns: %TRUE if edit APIs are disabled, %FALSE otherwise.
*
* Since: 1.22
*/
gboolean
ges_timeline_get_edit_apis_disabled (GESTimeline * self)
{
CHECK_THREAD (self);
g_return_val_if_fail (GES_IS_TIMELINE (self), FALSE);
return self->priv->disable_edit_apis;
}

View file

@ -160,4 +160,9 @@ GES_API
GESFrameNumber ges_timeline_get_frame_at (GESTimeline *self, GESFrameNumber ges_timeline_get_frame_at (GESTimeline *self,
GstClockTime timestamp); GstClockTime timestamp);
GES_API
void ges_timeline_disable_edit_apis (GESTimeline * self, gboolean disable_edit_apis);
GES_API
gboolean ges_timeline_get_edit_apis_disabled (GESTimeline * self);
G_END_DECLS G_END_DECLS

View file

@ -3651,6 +3651,22 @@ class TestComplexEditing(common.GESTimelineConfigTest):
c0, 0, GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 10, 30, c0, 0, GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 10, 30,
[c0], [c1], {c0 : {"start": 27}}, [], []) [c0], [c1], {c0 : {"start": 27}}, [], [])
def test_disable_timeline_editing_apis(self):
track = self.add_video_track()
self.assertEqual(self.timeline.props.auto_transition, True)
self.timeline.disable_edit_apis(True)
self.assertEqual(self.timeline.props.auto_transition, False)
c0 = self.add_clip("c0", 0, [track], 0, 10)
# Without disabling edit API adding clip would fail
c1 = self.add_clip("c1", 0, [track], 0, 10)
self.assertTimelineConfig()
c1.set_start(1)
c1.set_duration(1)
self.assertEqual(c1.get_start(), 1)
self.assertEqual(c1.get_duration(), 1)
class TestTransitions(common.GESSimpleTimelineTest): class TestTransitions(common.GESSimpleTimelineTest):