container: Add a way to ungroup a GESContainer into several GESContainers

+ Add simple unit test

API:
  GESContainerClass::ungroup vmethod
  ges_container_ungroup
This commit is contained in:
Thibault Saunier 2013-03-01 20:25:17 -03:00
parent c72c14b398
commit c73ced52f8
4 changed files with 191 additions and 0 deletions

View file

@ -158,6 +158,74 @@ _remove_child (GESContainer * container, GESTimelineElement * element)
return TRUE;
}
static void
add_tlobj_to_list (gpointer key, gpointer tlobj, GList ** list)
{
*list = g_list_prepend (*list, g_object_ref (tlobj));
}
static GList *
_ungroup (GESContainer * container, gboolean recursive)
{
GList *tmp, *ret = NULL;
GESClip *tmpclip;
GESTrackType track_type;
GESTrackElement *track_element;
gboolean first_obj = TRUE;
GESClip *clip = GES_CLIP (container);
GESTimelineElement *element = GES_TIMELINE_ELEMENT (container);
GESTimelineLayer *layer = clip->priv->layer;
GHashTable *_tracktype_clip = g_hash_table_new (g_int_hash, g_int_equal);
/* If there is no TrackElement, just return @container in a list */
if (GES_CONTAINER_CHILDREN (container) == NULL) {
GST_DEBUG ("No TrackElement, simply returning");
return g_list_prepend (ret, container);
}
/* We need a copy of the current list of tracks */
for (tmp = GES_CONTAINER_CHILDREN (container); tmp; tmp = tmp->next) {
track_element = GES_TRACK_ELEMENT (tmp->data);
track_type = ges_track_element_get_track_type (track_element);
tmpclip = g_hash_table_lookup (_tracktype_clip, &track_type);
if (tmpclip == NULL) {
if (G_UNLIKELY (first_obj == TRUE)) {
tmpclip = clip;
first_obj = FALSE;
} else {
tmpclip = GES_CLIP (ges_timeline_element_copy (element, FALSE));
if (layer) {
/* Add new container to the same layer as @container */
ges_clip_set_moving_from_layer (tmpclip, TRUE);
ges_timeline_layer_add_clip (layer, tmpclip);
ges_clip_set_moving_from_layer (tmpclip, FALSE);
}
}
g_hash_table_insert (_tracktype_clip, &track_type, tmpclip);
ges_clip_set_supported_formats (tmpclip, track_type);
}
/* Move trackelement to the container it is supposed to land into */
if (tmpclip != clip) {
ges_container_remove (container, GES_TIMELINE_ELEMENT (track_element));
ges_container_add (GES_CONTAINER (tmpclip),
GES_TIMELINE_ELEMENT (track_element));
}
}
g_hash_table_foreach (_tracktype_clip, (GHFunc) add_tlobj_to_list, &ret);
g_hash_table_unref (_tracktype_clip);
return ret;
}
/****************************************************
* *
* GObject virtual methods implementation *
* *
****************************************************/
static void
ges_clip_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
@ -241,6 +309,7 @@ ges_clip_class_init (GESClipClass * klass)
container_class->get_priorty_range = _get_priorty_range;
container_class->add_child = _add_child;
container_class->remove_child = _remove_child;
container_class->ungroup = _ungroup;
klass->need_fill_track = TRUE;
}

View file

@ -389,6 +389,7 @@ ges_container_class_init (GESContainerClass * klass)
/* No default implementations */
klass->remove_child = NULL;
klass->add_child = NULL;
klass->ungroup = NULL;
}
static void
@ -669,3 +670,36 @@ ges_container_get_children (GESContainer * container)
return g_list_copy_deep (container->children, (GCopyFunc) gst_object_ref,
NULL);
}
/**
* ges_container_ungroup
* @container: (transfer full): The #GESContainer to ungroup
* @recursive: Wether to recursively ungroup @container
*
* Ungroups the #GESTimelineElement contained in this GESContainer,
* creating new #GESContainer containing those #GESTimelineElement
* properly apropriately.
*
* Returns: (transfer container) (element-type GESContainer): The list of
* #GESContainer resulting from the ungrouping operation
* The user is responsible for unreffing the contained objects
* and freeing the list.
*/
GList *
ges_container_ungroup (GESContainer * container, gboolean recursive)
{
GESContainerClass *klass;
g_return_val_if_fail (GES_IS_CONTAINER (container), NULL);
GST_DEBUG_OBJECT (container, "Ungrouping container %s recursively",
recursive ? "" : "not");
klass = GES_CONTAINER_GET_CLASS (container);
if (klass->ungroup == NULL) {
GST_INFO_OBJECT (container, "No ungoup virtual method, doint nothing");
return NULL;
}
return klass->ungroup (container, recursive);
}

View file

@ -89,6 +89,8 @@ struct _GESContainer
* @remove_child: Virtual method to remove a child
* @add_child: Virtual method to add a child
* @get_priorty_range: Returns the range of possible priority in which the children can be in.
* @ungroup: Ungroups the #GESTimelineElement contained in this #GESContainer, creating new
* #GESContainer containing those #GESTimelineElement apropriately.
*/
struct _GESContainerClass
{
@ -102,6 +104,7 @@ struct _GESContainerClass
gboolean (*add_child) (GESContainer *container, GESTimelineElement *element);
gboolean (*remove_child) (GESContainer *container, GESTimelineElement *element);
void (*get_priorty_range) (GESContainer *container, guint32 *min_prio, guint32 *max_prio);
GList* (*ungroup) (GESContainer *container, gboolean recursive);
/*< private >*/
@ -115,6 +118,7 @@ GType ges_container_get_type (void);
GList* ges_container_get_children (GESContainer *container);
gboolean ges_container_add (GESContainer *container, GESTimelineElement *child);
gboolean ges_container_remove (GESContainer *container, GESTimelineElement *child);
GList * ges_container_ungroup (GESContainer * container, gboolean recursive);
G_END_DECLS
#endif /* _GES_CONTAINER */

View file

@ -177,6 +177,89 @@ GST_START_TEST (test_split_object)
GST_END_TEST;
GST_START_TEST (test_clip_ungroup)
{
GESAsset *asset;
GESTimeline *timeline;
GESClip *clip, *clip2;
GList *containers, *tmp;
GESTimelineLayer *layer;
GESTrack *audio_track, *video_track;
ges_init ();
timeline = ges_timeline_new ();
layer = ges_timeline_layer_new ();
audio_track = ges_track_audio_raw_new ();
video_track = ges_track_video_raw_new ();
fail_unless (ges_timeline_add_track (timeline, audio_track));
fail_unless (ges_timeline_add_track (timeline, video_track));
fail_unless (ges_timeline_add_layer (timeline, layer));
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
assert_is_type (asset, GES_TYPE_ASSET);
clip = ges_timeline_layer_add_asset (layer, asset, 0, 0, 10, 1,
GES_TRACK_TYPE_UNKNOWN);
ASSERT_OBJECT_REFCOUNT (clip, "1 layer", 1);
assert_equals_uint64 (_START (clip), 0);
assert_equals_uint64 (_INPOINT (clip), 0);
assert_equals_uint64 (_DURATION (clip), 10);
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (clip)), 2);
containers = ges_container_ungroup (GES_CONTAINER (clip), FALSE);
assert_equals_int (g_list_length (containers), 2);
fail_unless (clip == containers->data);
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (clip)), 1);
assert_equals_uint64 (_START (clip), 0);
assert_equals_uint64 (_INPOINT (clip), 0);
assert_equals_uint64 (_DURATION (clip), 10);
ASSERT_OBJECT_REFCOUNT (clip, "1 for the layer + 1 in containers list", 2);
clip2 = containers->next->data;
fail_if (clip2 == clip);
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (clip2)), 1);
assert_equals_uint64 (_START (clip2), 0);
assert_equals_uint64 (_INPOINT (clip2), 0);
assert_equals_uint64 (_DURATION (clip2), 10);
ASSERT_OBJECT_REFCOUNT (clip2, "1 for the layer + 1 in containers list", 2);
g_list_free_full (containers, gst_object_unref);
tmp = ges_track_get_elements (audio_track);
assert_equals_int (g_list_length (tmp), 1);
ASSERT_OBJECT_REFCOUNT (tmp->data, "1 for the track + 1 for the container "
"+ 1 for the timeline + 1 in tmp list", 4);
assert_equals_int (ges_track_element_get_track_type (tmp->data),
GES_TRACK_TYPE_AUDIO);
assert_equals_int (ges_clip_get_supported_formats (GES_CLIP
(ges_timeline_element_get_parent (tmp->data))), GES_TRACK_TYPE_AUDIO);
g_list_free_full (tmp, gst_object_unref);
tmp = ges_track_get_elements (video_track);
assert_equals_int (g_list_length (tmp), 1);
ASSERT_OBJECT_REFCOUNT (tmp->data, "1 for the track + 1 for the container "
"+ 1 for the timeline + 1 in tmp list", 4);
assert_equals_int (ges_track_element_get_track_type (tmp->data),
GES_TRACK_TYPE_VIDEO);
assert_equals_int (ges_clip_get_supported_formats (GES_CLIP
(ges_timeline_element_get_parent (tmp->data))), GES_TRACK_TYPE_VIDEO);
g_list_free_full (tmp, gst_object_unref);
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (clip), 10);
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (clip)), 1);
assert_equals_uint64 (_START (clip), 10);
assert_equals_uint64 (_INPOINT (clip), 0);
assert_equals_uint64 (_DURATION (clip), 10);
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (clip2)), 1);
assert_equals_uint64 (_START (clip2), 0);
assert_equals_uint64 (_INPOINT (clip2), 0);
assert_equals_uint64 (_DURATION (clip2), 10);
gst_object_unref (timeline);
}
GST_END_TEST;
static Suite *
ges_suite (void)
{
@ -187,6 +270,7 @@ ges_suite (void)
tcase_add_test (tc_chain, test_object_properties);
tcase_add_test (tc_chain, test_split_object);
tcase_add_test (tc_chain, test_clip_ungroup);
return s;
}