mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
group: let timeline-tree handle layer priority
Since a group can only have its priority set whilst it is part of a timeline, we can simply let the timeline-tree handle the move, which it can already do, whilst checking that the move would be legal (not break the timeline configuration). All the group has to do now if update its priority value if the priority of any of its children changes. It doesn't even need to keep track of the layer priority offsets. Also, added a check to ensure added children belong to the same timeline. Also moved the sigids from the GObject data to a g_hash_table, which is clearer. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/169>
This commit is contained in:
parent
aefc992ef1
commit
fba267926f
1 changed files with 84 additions and 199 deletions
283
ges/ges-group.c
283
ges/ges-group.c
|
@ -69,8 +69,6 @@
|
|||
#include <string.h>
|
||||
|
||||
#define parent_class ges_group_parent_class
|
||||
#define GES_CHILDREN_INIBIT_SIGNAL_EMISSION (GES_CHILDREN_LAST + 1)
|
||||
#define GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT "ges-group-signals-ids-%p"
|
||||
|
||||
struct _GESGroupPrivate
|
||||
{
|
||||
|
@ -82,6 +80,7 @@ struct _GESGroupPrivate
|
|||
/* This is used while were are setting ourselve a proper timing value,
|
||||
* in this case the value should always be kept */
|
||||
gboolean setting_value;
|
||||
GHashTable *child_sigids;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -117,12 +116,12 @@ _update_our_values (GESGroup * group)
|
|||
GESContainer *container = GES_CONTAINER (group);
|
||||
guint32 min_layer_prio = G_MAXINT32, max_layer_prio = 0;
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
for (tmp = container->children; tmp; tmp = tmp->next) {
|
||||
GESContainer *child = tmp->data;
|
||||
|
||||
if (GES_IS_CLIP (child)) {
|
||||
GESLayer *layer = ges_clip_get_layer (GES_CLIP (child));
|
||||
gint32 prio;
|
||||
guint32 prio;
|
||||
|
||||
if (!layer)
|
||||
continue;
|
||||
|
@ -133,7 +132,7 @@ _update_our_values (GESGroup * group)
|
|||
max_layer_prio = MAX (prio, max_layer_prio);
|
||||
gst_object_unref (layer);
|
||||
} else if (GES_IS_GROUP (child)) {
|
||||
gint32 prio = _PRIORITY (child), height = GES_CONTAINER_HEIGHT (child);
|
||||
guint32 prio = _PRIORITY (child), height = GES_CONTAINER_HEIGHT (child);
|
||||
|
||||
min_layer_prio = MIN (prio, min_layer_prio);
|
||||
max_layer_prio = MAX ((prio + height - 1), max_layer_prio);
|
||||
|
@ -144,14 +143,6 @@ _update_our_values (GESGroup * group)
|
|||
group->priv->updating_priority = TRUE;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), min_layer_prio);
|
||||
group->priv->updating_priority = FALSE;
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
guint32 child_prio = GES_IS_CLIP (child) ?
|
||||
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (child) : _PRIORITY (child);
|
||||
|
||||
_ges_container_set_priority_offset (container,
|
||||
child, min_layer_prio - child_prio);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: max_layer_prio not used elsewhere
|
||||
|
@ -159,8 +150,7 @@ _update_our_values (GESGroup * group)
|
|||
* changed (which we don't currently do, to allow it to change its
|
||||
* height) */
|
||||
group->priv->max_layer_prio = max_layer_prio;
|
||||
_ges_container_set_height (GES_CONTAINER (group),
|
||||
max_layer_prio - min_layer_prio + 1);
|
||||
_ges_container_set_height (container, max_layer_prio - min_layer_prio + 1);
|
||||
}
|
||||
|
||||
/* layer changed its priority in the timeline */
|
||||
|
@ -172,121 +162,38 @@ _child_priority_changed_cb (GESLayer * layer,
|
|||
}
|
||||
|
||||
static void
|
||||
_child_clip_changed_layer_cb (GESTimelineElement * clip,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
|
||||
_child_clip_changed_layer_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED,
|
||||
GESGroup * group)
|
||||
{
|
||||
ChildSignalIds *sigids;
|
||||
gchar *signals_ids_key;
|
||||
GESLayer *old_layer, *new_layer;
|
||||
gint offset, layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (clip);
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
|
||||
offset = _ges_container_get_priority_offset (container, clip);
|
||||
signals_ids_key =
|
||||
g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, clip);
|
||||
sigids = g_object_get_data (G_OBJECT (group), signals_ids_key);
|
||||
g_free (signals_ids_key);
|
||||
old_layer = sigids->layer;
|
||||
sigids = g_hash_table_lookup (group->priv->child_sigids, clip);
|
||||
|
||||
new_layer = ges_clip_get_layer (GES_CLIP (clip));
|
||||
g_assert (sigids);
|
||||
|
||||
if (sigids->child_priority_changed_sid) {
|
||||
g_signal_handler_disconnect (old_layer, sigids->child_priority_changed_sid);
|
||||
if (sigids->layer) {
|
||||
g_signal_handler_disconnect (sigids->layer,
|
||||
sigids->child_priority_changed_sid);
|
||||
sigids->child_priority_changed_sid = 0;
|
||||
gst_object_unref (sigids->layer);
|
||||
}
|
||||
|
||||
if (new_layer) {
|
||||
sigids->layer = ges_clip_get_layer (GES_CLIP (clip));
|
||||
|
||||
if (sigids->layer) {
|
||||
sigids->child_priority_changed_sid =
|
||||
g_signal_connect (new_layer, "notify::priority",
|
||||
g_signal_connect (sigids->layer, "notify::priority",
|
||||
(GCallback) _child_priority_changed_cb, clip);
|
||||
}
|
||||
/* sigids takes ownership of new_layer, we take ownership of old_layer */
|
||||
sigids->layer = new_layer;
|
||||
|
||||
if (GES_TIMELINE_ELEMENT_BEING_EDITED (clip)) {
|
||||
GST_DEBUG_OBJECT (container, "Not moving with change in priority of "
|
||||
"clip child %" GES_FORMAT, GES_ARGS (clip));
|
||||
_update_our_values (GES_GROUP (clip->parent));
|
||||
return;
|
||||
}
|
||||
|
||||
if (container->children_control_mode != GES_CHILDREN_UPDATE) {
|
||||
if (container->children_control_mode == GES_CHILDREN_INIBIT_SIGNAL_EMISSION) {
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
g_signal_stop_emission_by_name (clip, "notify::layer");
|
||||
}
|
||||
gst_clear_object (&old_layer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_layer && old_layer && (layer_prio + offset < 0 ||
|
||||
(GES_TIMELINE_ELEMENT_TIMELINE (group) &&
|
||||
layer_prio + offset + GES_CONTAINER_HEIGHT (group) - 1 >
|
||||
g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers)))) {
|
||||
|
||||
GST_INFO_OBJECT (container,
|
||||
"Trying to move to a layer %" GST_PTR_FORMAT " outside of"
|
||||
"the timeline layers, moving back to old layer (prio %i)", new_layer,
|
||||
_PRIORITY (group) - offset);
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_INIBIT_SIGNAL_EMISSION;
|
||||
ges_clip_move_to_layer (GES_CLIP (clip), old_layer);
|
||||
g_signal_stop_emission_by_name (clip, "notify::layer");
|
||||
|
||||
gst_clear_object (&old_layer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!new_layer || !old_layer) {
|
||||
_update_our_values (group);
|
||||
gst_clear_object (&old_layer);
|
||||
return;
|
||||
}
|
||||
|
||||
container->initiated_move = clip;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), layer_prio + offset);
|
||||
container->initiated_move = NULL;
|
||||
gst_clear_object (&old_layer);
|
||||
_update_our_values (group);
|
||||
}
|
||||
|
||||
static void
|
||||
_child_group_priority_changed (GESTimelineElement * child,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
|
||||
{
|
||||
gint offset;
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
GESGroup *child_group = GES_GROUP (child);
|
||||
|
||||
if (container->children_control_mode != GES_CHILDREN_UPDATE) {
|
||||
GST_DEBUG_OBJECT (group, "Ignoring updated");
|
||||
return;
|
||||
}
|
||||
/* if a child group is simply updating its values we will do the same */
|
||||
if (child_group->priv->updating_priority ||
|
||||
GES_TIMELINE_ELEMENT_BEING_EDITED (child)) {
|
||||
GST_DEBUG_OBJECT (container, "Not moving with change in priority of "
|
||||
"group child %" GES_FORMAT " because it is not moving itself",
|
||||
GES_ARGS (child_group));
|
||||
_update_our_values (group);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = _ges_container_get_priority_offset (container, child);
|
||||
|
||||
if (_PRIORITY (group) < offset ||
|
||||
(GES_TIMELINE_ELEMENT_TIMELINE (group) &&
|
||||
_PRIORITY (group) + offset + GES_CONTAINER_HEIGHT (group) >
|
||||
g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers))) {
|
||||
|
||||
GST_WARNING_OBJECT (container, "Trying to move to a layer outside of"
|
||||
"the timeline layers");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
container->initiated_move = child;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), _PRIORITY (child) + offset);
|
||||
container->initiated_move = NULL;
|
||||
_update_our_values (group);
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
|
@ -296,61 +203,26 @@ _child_group_priority_changed (GESTimelineElement * child,
|
|||
static gboolean
|
||||
_set_priority (GESTimelineElement * element, guint32 priority)
|
||||
{
|
||||
GList *tmp, *layers;
|
||||
gint diff = priority - _PRIORITY (element);
|
||||
GESContainer *container = GES_CONTAINER (element);
|
||||
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (element);
|
||||
GList *layers;
|
||||
GESTimeline *timeline = element->timeline;
|
||||
|
||||
if (GES_GROUP (element)->priv->updating_priority == TRUE)
|
||||
if (GES_GROUP (element)->priv->updating_priority == TRUE
|
||||
|| GES_TIMELINE_ELEMENT_BEING_EDITED (element))
|
||||
return TRUE;
|
||||
|
||||
layers = GES_TIMELINE_ELEMENT_TIMELINE (element) ?
|
||||
GES_TIMELINE_ELEMENT_TIMELINE (element)->layers : NULL;
|
||||
layers = timeline ? timeline->layers : NULL;
|
||||
if (layers == NULL) {
|
||||
GST_WARNING_OBJECT (element, "Not any layer in the timeline, not doing"
|
||||
"anything, timeline: %" GST_PTR_FORMAT,
|
||||
GES_TIMELINE_ELEMENT_TIMELINE (element));
|
||||
"anything, timeline: %" GST_PTR_FORMAT, timeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* FIXME: why are we not shifting ->max_layer_prio? */
|
||||
|
||||
if (GES_TIMELINE_ELEMENT_BEING_EDITED (element))
|
||||
return TRUE;
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
|
||||
if (child != container->initiated_move) {
|
||||
if (GES_IS_CLIP (child)) {
|
||||
guint32 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (child) + diff;
|
||||
GESLayer *layer =
|
||||
g_list_nth_data (GES_TIMELINE_GET_LAYERS (timeline), layer_prio);
|
||||
|
||||
if (layer == NULL) {
|
||||
do {
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
} while (ges_layer_get_priority (layer) < layer_prio);
|
||||
}
|
||||
|
||||
GST_DEBUG ("%" GES_FORMAT "moving from layer: %i to %i",
|
||||
GES_ARGS (child), GES_TIMELINE_ELEMENT_LAYER_PRIORITY (child),
|
||||
layer_prio);
|
||||
ges_clip_move_to_layer (GES_CLIP (child), g_list_nth_data (layers,
|
||||
layer_prio));
|
||||
} else if (GES_IS_GROUP (child)) {
|
||||
GST_DEBUG_OBJECT (child, "moving from %i to %i",
|
||||
_PRIORITY (child), diff + _PRIORITY (child));
|
||||
ges_timeline_element_set_priority (child, diff + _PRIORITY (child));
|
||||
}
|
||||
}
|
||||
}
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
return TRUE;
|
||||
return timeline_tree_move (timeline_get_tree (timeline),
|
||||
element, (gint64) (element->priority) - (gint64) priority, 0,
|
||||
GES_EDGE_NONE, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -454,53 +326,51 @@ _set_duration (GESTimelineElement * element, GstClockTime duration)
|
|||
static gboolean
|
||||
_add_child (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (group);
|
||||
g_return_val_if_fail (GES_IS_CONTAINER (child), FALSE);
|
||||
|
||||
if (timeline && child->timeline != timeline) {
|
||||
GST_WARNING_OBJECT (group, "Cannot add child %" GES_FORMAT
|
||||
" because it belongs to timeline %" GST_PTR_FORMAT
|
||||
" rather than the group's timeline %" GST_PTR_FORMAT,
|
||||
GES_ARGS (child), child->timeline, timeline);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_child_added (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
gchar *signals_ids_key;
|
||||
ChildSignalIds *signals_ids;
|
||||
GESGroup *self = GES_GROUP (group);
|
||||
ChildSignalIds *sigids;
|
||||
|
||||
/* NOTE: notifies are currently frozen by ges_container_add */
|
||||
if (!GES_TIMELINE_ELEMENT_TIMELINE (group)
|
||||
&& GES_TIMELINE_ELEMENT_TIMELINE (child)) {
|
||||
timeline_add_group (GES_TIMELINE_ELEMENT_TIMELINE (child),
|
||||
GES_GROUP (group));
|
||||
timeline_emit_group_added (GES_TIMELINE_ELEMENT_TIMELINE (child),
|
||||
GES_GROUP (group));
|
||||
if (!GES_TIMELINE_ELEMENT_TIMELINE (group) && child->timeline) {
|
||||
timeline_add_group (child->timeline, self);
|
||||
timeline_emit_group_added (child->timeline, self);
|
||||
}
|
||||
/* FIXME: we should otherwise check that the child is part of the same
|
||||
* timeline */
|
||||
|
||||
_update_our_values (GES_GROUP (group));
|
||||
_update_our_values (self);
|
||||
|
||||
sigids = g_new0 (ChildSignalIds, 1);
|
||||
/* doesn't take a ref to child since no data */
|
||||
g_hash_table_insert (self->priv->child_sigids, child, sigids);
|
||||
|
||||
signals_ids_key =
|
||||
g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, child);
|
||||
signals_ids = g_malloc0 (sizeof (ChildSignalIds));
|
||||
g_object_set_data_full (G_OBJECT (group), signals_ids_key,
|
||||
signals_ids, g_free);
|
||||
g_free (signals_ids_key);
|
||||
if (GES_IS_CLIP (child)) {
|
||||
GESLayer *layer = ges_clip_get_layer (GES_CLIP (child));
|
||||
sigids->layer = ges_clip_get_layer (GES_CLIP (child));
|
||||
|
||||
signals_ids->child_clip_changed_layer_sid =
|
||||
g_signal_connect (child, "notify::layer",
|
||||
(GCallback) _child_clip_changed_layer_cb, group);
|
||||
sigids->child_clip_changed_layer_sid = g_signal_connect (child,
|
||||
"notify::layer", (GCallback) _child_clip_changed_layer_cb, group);
|
||||
|
||||
if (layer) {
|
||||
signals_ids->child_priority_changed_sid = g_signal_connect (layer,
|
||||
if (sigids->layer) {
|
||||
sigids->child_priority_changed_sid = g_signal_connect (sigids->layer,
|
||||
"notify::priority", (GCallback) _child_priority_changed_cb, child);
|
||||
}
|
||||
signals_ids->layer = layer;
|
||||
|
||||
} else if (GES_IS_GROUP (child), group) {
|
||||
signals_ids->child_group_priority_changed_sid =
|
||||
g_signal_connect (child, "notify::priority",
|
||||
(GCallback) _child_group_priority_changed, group);
|
||||
} else if (GES_IS_GROUP (child)) {
|
||||
sigids->child_group_priority_changed_sid = g_signal_connect (child,
|
||||
"notify::priority", (GCallback) _child_group_priority_changed, group);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,32 +394,27 @@ _disconnect_signals (GESGroup * group, GESTimelineElement * child,
|
|||
sigids->child_priority_changed_sid);
|
||||
sigids->child_priority_changed_sid = 0;
|
||||
}
|
||||
gst_clear_object (&(sigids->layer));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_child_removed (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
GList *children;
|
||||
gchar *signals_ids_key;
|
||||
GESGroup *self = GES_GROUP (group);
|
||||
ChildSignalIds *sigids;
|
||||
|
||||
/* NOTE: notifies are currently frozen by ges_container_add */
|
||||
_ges_container_sort_children (group);
|
||||
|
||||
children = GES_CONTAINER_CHILDREN (group);
|
||||
sigids = g_hash_table_lookup (self->priv->child_sigids, child);
|
||||
|
||||
signals_ids_key =
|
||||
g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, child);
|
||||
sigids = g_object_get_data (G_OBJECT (group), signals_ids_key);
|
||||
_disconnect_signals (GES_GROUP (group), child, sigids);
|
||||
g_free (signals_ids_key);
|
||||
if (children == NULL) {
|
||||
g_assert (sigids);
|
||||
_disconnect_signals (self, child, sigids);
|
||||
g_hash_table_remove (self->priv->child_sigids, child);
|
||||
|
||||
if (group->children == NULL) {
|
||||
GST_FIXME_OBJECT (group, "Auto destroy myself?");
|
||||
if (GES_TIMELINE_ELEMENT_TIMELINE (group))
|
||||
timeline_remove_group (GES_TIMELINE_ELEMENT_TIMELINE (group),
|
||||
GES_GROUP (group));
|
||||
timeline_remove_group (GES_TIMELINE_ELEMENT_TIMELINE (group), self);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -679,6 +544,16 @@ ges_group_set_property (GObject * object, guint property_id,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_dispose (GObject * object)
|
||||
{
|
||||
GESGroup *self = GES_GROUP (object);
|
||||
|
||||
g_clear_pointer (&self->priv->child_sigids, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_class_init (GESGroupClass * klass)
|
||||
{
|
||||
|
@ -688,6 +563,7 @@ ges_group_class_init (GESGroupClass * klass)
|
|||
|
||||
object_class->get_property = ges_group_get_property;
|
||||
object_class->set_property = ges_group_set_property;
|
||||
object_class->dispose = ges_group_dispose;
|
||||
|
||||
element_class->set_duration = _set_duration;
|
||||
element_class->set_inpoint = _set_inpoint;
|
||||
|
@ -765,12 +641,21 @@ ges_group_class_init (GESGroupClass * klass)
|
|||
container_class->grouping_priority = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_free_sigid (gpointer mem)
|
||||
{
|
||||
ChildSignalIds *sigids = mem;
|
||||
gst_clear_object (&sigids->layer);
|
||||
g_free (mem);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_init (GESGroup * self)
|
||||
{
|
||||
self->priv = ges_group_get_instance_private (self);
|
||||
|
||||
self->priv->setting_value = FALSE;
|
||||
self->priv->child_sigids =
|
||||
g_hash_table_new_full (NULL, NULL, NULL, _free_sigid);
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
|
|
Loading…
Reference in a new issue