From f579a6a95ca47f1925c633e02254397c8d82e1cd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Mar 2013 18:35:34 -0300 Subject: [PATCH] container: Add a ges_container_group method + Add some basic unit tests API: GESContainer:group vmethod ges_container_group --- docs/libs/ges-sections.txt | 2 + ges/ges-clip.c | 156 +++++++++++++++++++++++++++++++++++++ ges/ges-container.c | 49 +++++++++++- ges/ges-container.h | 3 + tests/check/ges/clip.c | 43 +++++++++- 5 files changed, 248 insertions(+), 5 deletions(-) diff --git a/docs/libs/ges-sections.txt b/docs/libs/ges-sections.txt index 4e02f0ed25..b31d5063e6 100644 --- a/docs/libs/ges-sections.txt +++ b/docs/libs/ges-sections.txt @@ -364,6 +364,8 @@ GES_CONTAINER_HEIGHT ges_container_get_children ges_container_add ges_container_remove +ges_container_ungroup +ges_container_group GESContainerPrivate ges_container_get_type diff --git a/ges/ges-clip.c b/ges/ges-clip.c index 816c4011a3..076897f061 100644 --- a/ges/ges-clip.c +++ b/ges/ges-clip.c @@ -68,6 +68,12 @@ struct _GESClipPrivate GESTrackType supportedformats; }; +typedef struct _CheckTrack +{ + GESTrack *track; + GESTrackElement *source; +} CheckTrack; + enum { PROP_0, @@ -221,6 +227,155 @@ _ungroup (GESContainer * container, gboolean recursive) return ret; } +static GESContainer * +_group (GList * containers) +{ + CheckTrack *tracks = NULL; + GESTimeline *timeline = NULL; + GESTrackType supported_formats; + GESTimelineLayer *layer = NULL; + GList *tmp, *tmpclip, *tmpelement; + GstClockTime start, inpoint, duration; + + GESAsset *asset = NULL; + GESContainer *ret = NULL; + guint nb_tracks = 0, i = 0; + + start = inpoint = duration = GST_CLOCK_TIME_NONE; + + /* First check if all the containers are clips, if they + * all have the same start/inpoint/duration and are in the same + * layer. + * + * We also need to make sure that all source have been created by the + * same asset, keep the information */ + for (tmp = containers; tmp; tmp = tmp->next) { + GESClip *clip; + GESTimeline *tmptimeline; + GESContainer *tmpcontainer; + GESTimelineElement *element; + + tmpcontainer = GES_CONTAINER (tmp->data); + element = GES_TIMELINE_ELEMENT (tmp->data); + if (GES_IS_CLIP (element) == FALSE) { + GST_DEBUG ("Can only work with clips"); + goto done; + } + clip = GES_CLIP (tmp->data); + tmptimeline = ges_timeline_element_get_timeline (element); + if (!timeline) { + GList *tmptrack; + + start = _START (tmpcontainer); + inpoint = _INPOINT (tmpcontainer); + duration = _DURATION (tmpcontainer); + timeline = tmptimeline; + layer = clip->priv->layer; + nb_tracks = g_list_length (GES_TIMELINE_GET_TRACKS (timeline)); + tracks = g_new0 (CheckTrack, nb_tracks); + + for (tmptrack = GES_TIMELINE_GET_TRACKS (timeline); tmptrack; + tmptrack = tmptrack->next) { + tracks[i].track = tmptrack->data; + i++; + } + } else { + if (start != _START (tmpcontainer) || + inpoint != _INPOINT (tmpcontainer) || + duration != _DURATION (tmpcontainer) || clip->priv->layer != layer) { + GST_INFO ("All children must have the same start, inpoint, duration " + " and be in the same layer"); + + goto done; + } else { + GList *tmp2; + + for (tmp2 = GES_CONTAINER_CHILDREN (tmp->data); tmp2; tmp2 = tmp2->next) { + GESTrackElement *track_element = GES_TRACK_ELEMENT (tmp2->data); + + if (GES_IS_SOURCE (track_element)) { + guint i; + + for (i = 0; i < nb_tracks; i++) { + if (tracks[i].track == + ges_track_element_get_track (track_element)) { + if (tracks[i].source) { + GST_INFO ("Can not link clips with various source for a " + "same track"); + + goto done; + } + tracks[i].source = track_element; + break; + } + } + } + } + } + } + } + + + /* Then check that all sources have been created by the same asset, + * otherwise we can not group */ + for (i = 0; i < nb_tracks; i++) { + if (tracks[i].source == NULL) { + GST_FIXME ("Check what to do here as we might end up having a mess"); + + continue; + } + + /* FIXME Check what to do if we have source that have no assets */ + if (!asset) { + asset = + ges_extractable_get_asset (GES_EXTRACTABLE + (ges_timeline_element_get_parent (GES_TIMELINE_ELEMENT (tracks + [i].source)))); + continue; + } + if (asset != + ges_extractable_get_asset (GES_EXTRACTABLE + (ges_timeline_element_get_parent (GES_TIMELINE_ELEMENT (tracks + [i].source))))) { + GST_INFO ("Can not link clips with source coming from different assets"); + + goto done; + } + } + + /* And now pass all TrackElements to the first clip, + * and remove others from the layer (updating the supported formats) */ + ret = containers->data; + supported_formats = GES_CLIP (ret)->priv->supportedformats; + for (tmpclip = containers->next; tmpclip; tmpclip = tmpclip->next) { + GESClip *cclip = tmpclip->data; + + for (tmpelement = GES_CONTAINER_CHILDREN (cclip); tmpelement; + tmpelement = tmpelement->next) { + GESTimelineElement *celement = GES_TIMELINE_ELEMENT (tmpelement->data); + + ges_container_remove (GES_CONTAINER (cclip), celement); + ges_container_add (ret, celement); + + supported_formats = supported_formats | + ges_track_element_get_track_type (GES_TRACK_ELEMENT (celement)); + } + + ges_timeline_layer_remove_clip (layer, tmpclip->data); + } + + ges_clip_set_supported_formats (GES_CLIP (ret), supported_formats); + +done: + if (tracks) + g_free (tracks); + + + return ret; + +} + + /**************************************************** * * * GObject virtual methods implementation * @@ -310,6 +465,7 @@ ges_clip_class_init (GESClipClass * klass) container_class->add_child = _add_child; container_class->remove_child = _remove_child; container_class->ungroup = _ungroup; + container_class->group = _group; klass->need_fill_track = TRUE; } diff --git a/ges/ges-container.c b/ges/ges-container.c index ba235c5097..fbae769af3 100644 --- a/ges/ges-container.c +++ b/ges/ges-container.c @@ -390,6 +390,7 @@ ges_container_class_init (GESContainerClass * klass) klass->remove_child = NULL; klass->add_child = NULL; klass->ungroup = NULL; + klass->group = NULL; } static void @@ -672,13 +673,13 @@ ges_container_get_children (GESContainer * container) } /** - * ges_container_ungroup + * 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. + * apropriately. * * Returns: (transfer container) (element-type GESContainer): The list of * #GESContainer resulting from the ungrouping operation @@ -703,3 +704,47 @@ ges_container_ungroup (GESContainer * container, gboolean recursive) return klass->ungroup (container, recursive); } + +/** + * ges_container_group: + * @containers: (transfer none)(element-type GESContainer): The + * #GESContainer to group, they must all be in a same #GESTimeline + * + * Groups the #GESContainer-s provided in @containers. It creates a subclass + * of #GESContainer, depending on the containers provided in @containers. + * Basically, if all the containers in @containers should be contained in a same + * clip (all the #GESTrackElement they contain have the exact same + * start/inpoint/duration and are in the same layer), it will create a #GESClip + * otherwise a #GESGroup will be created + * + * Returns: (transfer none): The #GESContainer (subclass) resulting of the + * grouping + */ +GESContainer * +ges_container_group (GList * containers) +{ + GList *tmp; + GESContainer *ret; + GESTimeline *timeline; + GESTimelineElement *element; + GObjectClass *clip_class; + + g_return_val_if_fail (containers, NULL); + element = GES_TIMELINE_ELEMENT (containers->data); + timeline = ges_timeline_element_get_timeline (element); + g_return_val_if_fail (timeline, NULL); + + if (g_list_length (containers) == 1) + return containers->data; + + for (tmp = containers; tmp; tmp = tmp->next) { + g_return_val_if_fail (GES_IS_CONTAINER (tmp->data), NULL); + g_return_val_if_fail (ges_timeline_element_get_timeline + (GES_TIMELINE_ELEMENT (tmp->data)) == timeline, NULL); + } + + clip_class = g_type_class_peek (GES_TYPE_CLIP); + ret = GES_CONTAINER_CLASS (clip_class)->group (containers); + + return ret; +} diff --git a/ges/ges-container.h b/ges/ges-container.h index a44d6ad9f7..bfd5760e72 100644 --- a/ges/ges-container.h +++ b/ges/ges-container.h @@ -90,6 +90,7 @@ struct _GESContainer * @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 + * @group: Groups the #GESContainers together * #GESContainer containing those #GESTimelineElement apropriately. */ struct _GESContainerClass @@ -105,6 +106,7 @@ struct _GESContainerClass 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); + GESContainer * (*group) (GList *containers); /*< private >*/ @@ -119,6 +121,7 @@ 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); +GESContainer *ges_container_group (GList *containers); G_END_DECLS #endif /* _GES_CONTAINER */ diff --git a/tests/check/ges/clip.c b/tests/check/ges/clip.c index a5447576a0..d471030567 100644 --- a/tests/check/ges/clip.c +++ b/tests/check/ges/clip.c @@ -177,13 +177,14 @@ GST_START_TEST (test_split_object) GST_END_TEST; -GST_START_TEST (test_clip_ungroup) +GST_START_TEST (test_clip_group_ungroup) { GESAsset *asset; GESTimeline *timeline; GESClip *clip, *clip2; GList *containers, *tmp; GESTimelineLayer *layer; + GESContainer *regrouped_clip; GESTrack *audio_track, *video_track; ges_init (); @@ -224,7 +225,6 @@ GST_START_TEST (test_clip_ungroup) 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); @@ -255,6 +255,43 @@ GST_START_TEST (test_clip_ungroup) assert_equals_uint64 (_INPOINT (clip2), 0); assert_equals_uint64 (_DURATION (clip2), 10); + regrouped_clip = ges_container_group (containers); + fail_unless (regrouped_clip == NULL); + + ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (clip), 0); + regrouped_clip = ges_container_group (containers); + assert_is_type (regrouped_clip, GES_TYPE_CLIP); + assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (regrouped_clip)), + 2); + assert_equals_int (ges_clip_get_supported_formats (GES_CLIP (regrouped_clip)), + GES_TRACK_TYPE_VIDEO | GES_TRACK_TYPE_AUDIO); + g_list_free_full (containers, gst_object_unref); + + GST_DEBUG ("Check clips in the layer"); + tmp = ges_timeline_layer_get_clips (layer); + assert_equals_int (g_list_length (tmp), 1); + g_list_free_full (tmp, gst_object_unref); + + GST_DEBUG ("Check TrackElement in audio track"); + tmp = ges_track_get_elements (audio_track); + assert_equals_int (g_list_length (tmp), 1); + assert_equals_int (ges_track_element_get_track_type (tmp->data), + GES_TRACK_TYPE_AUDIO); + fail_unless (GES_CONTAINER (ges_timeline_element_get_parent (tmp->data)) == + regrouped_clip); + g_list_free_full (tmp, gst_object_unref); + + GST_DEBUG ("Check TrackElement in video track"); + 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); + fail_unless (GES_CONTAINER (ges_timeline_element_get_parent (tmp->data)) == + regrouped_clip); + g_list_free_full (tmp, gst_object_unref); + gst_object_unref (timeline); } @@ -270,7 +307,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); + tcase_add_test (tc_chain, test_clip_group_ungroup); return s; }