container: Add a ges_container_group method

+ Add some basic unit tests

API:
  GESContainer:group vmethod
  ges_container_group
This commit is contained in:
Thibault Saunier 2013-03-02 18:35:34 -03:00
parent ae80f08869
commit f579a6a95c
5 changed files with 248 additions and 5 deletions

View file

@ -364,6 +364,8 @@ GES_CONTAINER_HEIGHT
ges_container_get_children
ges_container_add
ges_container_remove
ges_container_ungroup
ges_container_group
<SUBSECTION Standard>
GESContainerPrivate
ges_container_get_type

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;
}