The in-point of a clip is kept in sync with its core children, unless they
have no has-internal-source.
The max-duration is defined as the minimum max-duration amongst the
clip's core children. If it is set to a new value, this sets the
max-duration of its core children to the same value if they have
has-internal-source set as TRUE.
Non-core children (such as effects on a source clip) do not influence
these values.
As part of this, we no longer track in-point in GESContainer. Unlike start
and duration, the in-point of a timeline element does not refer to its
extent in the timeline. As such, it has little meaning for most
collections of timeline-elements, in particular GESGroups. As such, there
is no generic way to relate the in-point of a container to its children.
As such, they only emit a signal if their value changes, either through
their _set_inpoint or _set_max_duration methods, or through
g_object_set, etc.
Also, we now require the ->set_max_duration method to be implemented.
This was added to GESGroup, which will only allow the max-duration to be
set to GST_CLOCK_TIME_NONE.
Unless this property is set to TRUE, the in-point must be 0 and the
max-duration must be GST_CLOCK_TIME_NONE.
Also added EXPLICIT_NOTIFY flags to the active and track-type
properties such that their notifies are emitted only if the property
changes, even when the g_object_set, etc, methods are used.
Also added a missing notify signal to the set_active method.
Previously the control bindings were not properly copied into the pasted
clip. Also changed the order so that elements are added to the clip
before the clip is added to the timeline.
Add the child-property-added and child-property-removed signals to
GESTimelineElement.
GESContainer is able to use this to keep their child properties in sync
with their children: if they are added or removed from the child, they
are also added or removed from the container.
Hold the notify signals for the container and the children until after
the child has been fully added or removed.
After the previous commit, this was used to ensure that the
notify::priority signal was sent for children of a clip *after* the
child-removed signal. This stopped being the case when the code in
->child_removed was moved to ->remove_child (the latter is called before
the child-removed signal is emitted, whilst the former is called
afterwards). Rather than undo this move of code, which was necessary to
ensure that ->add_child was always reversed, the notify::priority signal
is now simply delayed until after removing the child has completed. This
was done for all notify signals, as well as in the add method, to ensure
consistency.
This allows the test_clips.py test_signal_order_when_removing_effect to
pass.
Also make subclasses take a copy of the list of the children before
setting the start and duration, since this can potentially re-order the
children (if they have the SET_SIMPLE flag set).
Previously, we relied on ->child_removed to reverse the priority changes
that occured in ->add_child. However, ->child_removed is not always
called (the signal child-removed is not always emitted) when a
->add_child needs to be removed. However, ->remove_child is always
called to reverse ->add_child, so the code was moved here. Otherwise, we
risk that the priorities of the clip will contain gaps, which will cause
problems when another child is added to the clip.
Handle the child priorities in a way that keeps the container children
list sorted by priority at all times. Also, no longer rely on the
control_mode of the container, since we have less control over its value,
compared to private variables.
Also fixed the changing of priorities in set_top_effect_index:
previously *all* children whose priority was above or below the new
priority were shifted, when we should have been only shifting priorities
for the children whose priority lied *between* the old and the new
priority of the effect. E.g.
effect: A B C D E F
index: 0 1 2 3 4 5
After moving effect E to index 1, previously, we would get
effect: A B C D E F
index: 0 2 3 4 1 6
(this would have also shifted the priority for the core children as
well!). Whereas now, we have the correct:
effect: A B C D E F
index: 0 2 3 4 1 5
Only allow elements that were created by ges_clip_create_track_elements
(or copied from such an element) to be added to a clip. This prevents
users from adding arbitrary elements to a clip.
As an exception, a user can add GESBaseEffects to clips whose class
supports it, i.e. to a GESSourceClip and a GESBaseEffectClip.
This change also introduces a distinction between the core elements of a
clip (created by ges_clip_create_track_elements) and non-core elements
(currently, only GESBaseEffects, for some classes). In particular,
GESBaseEffectClip will now distinguish between its core elements and
effects added by the user. This means that the core elements will always
have the lowest priority, and will not be listed as top effects. This is
desirable because it brings the behaviour of GESBaseEffectClip in line
with other clip types.
We were implementing the logic for moving/trimming elements specific
to SourceClip but this was not correct ass the new timeline tree allows
us to handle that for all element types in a generic and nice way.
This make us need to have groups trimming properly implemented in the
timeline tree, leading to some fixes in the group tests.
This adds tests for the various cases known to not be handled properly
by the previous code.
Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/92
Unless the pipeline is in certain modes, we do not want to try and link
every track. The previous debug message implied this, but the method did
not actually end early.
Also, we always end early if we receive a track that is neither video
nor audio.
Previous usage of the property proxy-target seemed to alternate between
the two definitions:
+ The asset we are the default proxy of
+ The asset we are in the proxy list of
Now, the latter definition is used, which seems more useful to a user
since knowing the latter can easily allow you to find out the former.
The previous behaviour of ges_asset_set_proxy (asset, NULL) was not very
clear. It is now defined so that it clears all the proxies for 'asset'.
This means that after this call, the GESAsset:proxy property will indeed
be NULL.
Also fixed:
+ We can call ges_asset_set_proxy (asset, proxy) when 'proxy' is already
in the proxy list of 'asset'.
+ Handling of removing the default proxy in ges_asset_unproxy. This was
sending out the wrong notifies.
+ Prohibiting circular proxying. Before we could only prevent one case,
we should now be able to prevent all cases. This will prevent a hang
in ges_asset_request.
Fix the ownership in ges_asset_request. This should be transfer-full,
but for proxies it would fail to add a reference. Also,
ges_asset_cache_put was leaking memory if the asset already existed.
We should not be accepting ges_asset_set_proxy (NULL, proxy) as part of
the API! This behaviour was used internally in combination with
ges_asset_try_proxy, which is called on a still loading asset, so it was
moved to ges_asset_finish_proxy.
Previously, we tested that the given priority was `>0`, when it seems
that `>=0` was intended. A priority of `-1` means leave the priority
unchanged, whilst a priority of 0, or more, means move to this layer
priority.
Stop overwriting the ->list_children_properties virtual method in
subclasses because the timeline element class handles everything itself
anyway.
Note that containers already automatically add the children properties of
their child elements in ges_container_add.
Previously, we were setting the inpoint_offset using the start offset in
the duration callback!
Also added a notify for when the duration is changed in the child start
callback.
Previously, either the track or track_type arguments had to be specified
in order to find **any** track elements. Now, you can specify neither,
which will match any track element, of the specified type.
If a clip is already part of a layer, then adding it to another layer
should fail. Previously, in this case, `ges_layer_add_clip` was adding a
reference to the clip instead, without subsequently giving up ownership.
This meant that the clip would be left with an unowned reference.
This has now been corrected by also calling `unref` after the
`ref_sink`.
Note that, since `clip` is already part of `current_layer`, it should
already be non-floating, so the `ref_sink`-`unref` should do nothing
overall. But we keep both to make the ownership (transfer floating/none)
explicit.
The method steals ownership of `copied_from`, so should be responsible
for unreffing it. Also make sure we fail when `layer != -1`, since this
functionality is not supported.
We try to do our best to have the video frames scaled the best way
to fill most space on the final frames, keeping aspect ratio. The user
can later on rescale or move the sources as usual but it makes the
default behaviour a better and more natural especially now that we
set default restriction caps to the video tracks.
And fix the unit test to take that change into account
This way the user can easily know how the clip would look like
if no scaling was applied to the clip, this is useful to be able
to properly position the clips with the framepositionner element.
We used to always call the `->set_child_property` virtual method
of the object that `ges_timeline_element_set_child_property` was called
from, but that means that, in the case of referencing GESContainer
children properties from its children, the children wouldn't know
what child property have been set, and the children override wouldn't
be takent into account, in turns, it means that the behaviour could be
different in the setter depending on parent the method was called,
which is totally unexpected.
We now make sure that the vmethod from the element that introduced the
child property is called whatever parent method is called, making the
behaviour more uniform.
Fix the python override to make sure that new behaviour is respected.
By default, video track output full HD@30fps, this makes the behaviour
of clip position much more understandable and guarantess that we
always have a framerate.
The user can modify the values whenever he wants
Basically we were advertising that the source size would be the
size of the track if it hadn't been defined by end user, but since
we started to let scaling happen in the compositor, this is not true
as the source size is now the natural size of the underlying video
stream.
Remove the unit test and reimplemented using a validate scenario which
make the test much simpler to read :=)
Basically we know that if we are using mixing, compositor will be
able to do video conversion and scaling for us, so avoid adding those
usless elements.
This optimizes a lot caps negotiation for deeply nested timelines.
In general, brought the behaviour of the `start`, `duration` and
`inpoint` setters in line with each other. In particular:
1. fixed return value the GESSourceClip `duration` setter
2. changed the GESClip `start` setter
3. fixed the inpoint callback for GESContainer
4. changed the type of `res` in GESTimelineElement to be gint to
emphasise that the GES library is using the hack that a return of -1
from klass->set_duration means no notify signal should be sent out.
Also added a new test for clips to ensure that the setters work for
clips within and outside of timelines, and that the `start`, `inpoint`
and `duration` of a clip will match its children.
By passing NULL to `g_signal_new` instead of a marshaller, GLib will
actually internally optimize the signal (if the marshaller is available
in GLib itself) by also setting the valist marshaller. This makes the
signal emission a bit more performant than the regular marshalling,
which still needs to box into `GValue` and call libffi in case of a
generic marshaller.
Note that for custom marshallers, one would use
`g_signal_set_va_marshaller()` with the valist marshaller instead.
We clearly uniquely identify assets by both their IDs and their
extractable type, and we should make sure that you can have a
TrackElement and a Clip with the same ID.
There is one exception in our implementation which is GESFormatter
because we treat their subclasses as 1 type with different IDs.
Corrected typo that attached project_loaded_cb, rather than error_loading_asset_cb, to ::error-loading-asset, which meant data.error would be left unset if an error occurred in loading.
ges-xml-formatter.c: In function ‘_parse_asset’:
ges-xml-formatter.c:357:7: error: ‘gst_uri_construct’ is deprecated: Use 'gst_uri_new' instead [-Werror=deprecated-declarations]
357 | id = gst_uri_construct ("file", subproj_data->filename);
| ^~
ges-uri-asset.c: In function ‘create_discoverer’:
ges-uri-asset.c:53:1: error: old-style function definition [-Werror=old-style-definition]
53 | create_discoverer ()
| ^~~~~~~~~~~~~~~~~
ges-uri-asset.c: In function ‘get_discoverer’:
ges-uri-asset.c:67:1: error: old-style function definition [-Werror=old-style-definition]
67 | get_discoverer ()
| ^~~~~~~~~~~~~~
CC libges_1.0_la-ges-auto-transition.lo
ges-asset.c: In function ‘_get_type_entries’:
ges-asset.c:489:1: error: old-style function definition [-Werror=old-style-definition]
489 | _get_type_entries ()
| ^~~~~~~~~~~~~~~~~
Implement lazy loading asset cache so gesdemux use the formatters
assets while GES hasn't been initialized.
And set extensions to temporary files as some formatters require
the information (otio)
Uses the file extension as hint falling back to the default formatter
if none is found
Make use of that function in when saving a project and not formatter
is specified.
This method is useful when implementing a formatter outside
GES that end up converting to xges and uses the default formatter
to finally load the timeline.
Adding a property to let the application know
Also make sure that the duration of nested timeline assets is reported
as CLOCK_TIME_NONE as those are extended as necessary.
And make a difference between asset duration and their max duration
As nested timelines can be extended 'infinitely' those max duration
is GST_CLOCK_TIME_NONE, but their duration is the real duration of
the timeline.
When we have nested timelines, we need to make sure the underlying
formatted file is reloaded when commiting the main composition to
take into account the new timeline.
In other to make the implementation as simple as possible we make
sure that whenever the toplevel composition is commited, the decodebin
holding the gesdemux is torn down so that a new demuxer is created
with the new content of the timeline.
To do that a we do a NleCompositionQueryNeedsTearDown query to which
gesdemux answers leading to a full nlecomposition stack
deactivation/activation cycle.
It was making no sense to consider it an empty timeline when the user
had passed the project URI when requesting the asset. Usually user
use `ges_project_new` with the URI but it is also valid to use
`ges_asset_request` with the uri as ID so let's handle that properly.
Subprojects simply consist of adding the GESProject
to the main project asset list. Then those are recursively
serialized in the main project in the <asset> not, when deserializing,
temporary files are created and those will be used in clips
as necessary
Making sure to have 1 GstDiscoverer per thread.
Use that new feature in gesdemux by loading the timeline directly from
the streaming thread. Modifying the timeline is not supported allowed
anyway.
In the case of nested timeline in the toplevel timeline we ended up
with CompositionUpdate for seeks sent by our own composition to
granchildren composition. This was not causing essential issues
if all tracks where containing nested timelines but in cases
where one of the tracks only had a nested timelines, then we
were waiting forever for a `CompositionUpdateDone`.
CompositionUpdate translated into ASYNC_START/ASYNC_DONE should
be kept inside the GESTimeline and not travel up (possibly to some
parent GESTimeline).
For smptealph element to work as expected the following compositing
element should mix with the default "over" operator, as described
in its documentation.
Setters return values should return %FALSE **only** when the value
could not be set, not when unchanged or when the subclass handled
it itself!
This patches makes it so the return value is meaningul by allowing
subclasses return anything different than `TRUE` or `FALSE` (convention
is -1) to let the subclass now that it took care of everything and
no signal should be emited.
Now that the notion of layer has been moved down to #GESTimelineElement
(through the new #ges_timeline_element_get_layer_priority method), this
method make much more sense directly in the base class.
ges_container_add removes the child being added if the call to
ges_timeline_element_set_parent fails. In this case, subclasses should
be given the chance to revert the effects of the add_child vmethod which
has just been called.
These are showing up in performance profile of 1000+ clips looped addition.
All this is done at commit time as well, so let that do only one update and
sorting.
Discoverer maintain a referernce on the discoverer object while
the async timeout callback is alive to prevent a potential crash
if the object is freed while the callback is pending.
But if g_main_context is released before calling the timeout callback,
the discoverer pointer which was weak referenced from GESUriClipAssetClass
will not be disposed because the discoverer object is not finalized.
And handle the fact that adding to a layer can fail.
Also plug some leaks in the dispose method (and use the dispose
vmethod instead of finalize as appropriate).
Basically if we do not emit a "duration" change of the clip being
splitted first when executing the 'reverse' operations would lead
to fully overallaping clips.
This is implemented on top of a Tree that represents the whole timeline.
SourceClips can not fully overlap anymore and the tests have been
updated to take that into account. Some new tests were added to verify
that behaviour in greater details
Each timeline element is in a layer (potentially spanning
over several), it is very often useful to retrieve an element
layer priority (from an app perspective more than the element
priority itself as that is a bit of an implementation detail
in the end).
Port tests to it