mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
container: Add a ges_container_group method
+ Add some basic unit tests API: GESContainer:group vmethod ges_container_group
This commit is contained in:
parent
ae80f08869
commit
f579a6a95c
5 changed files with 248 additions and 5 deletions
|
@ -364,6 +364,8 @@ GES_CONTAINER_HEIGHT
|
||||||
ges_container_get_children
|
ges_container_get_children
|
||||||
ges_container_add
|
ges_container_add
|
||||||
ges_container_remove
|
ges_container_remove
|
||||||
|
ges_container_ungroup
|
||||||
|
ges_container_group
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GESContainerPrivate
|
GESContainerPrivate
|
||||||
ges_container_get_type
|
ges_container_get_type
|
||||||
|
|
156
ges/ges-clip.c
156
ges/ges-clip.c
|
@ -68,6 +68,12 @@ struct _GESClipPrivate
|
||||||
GESTrackType supportedformats;
|
GESTrackType supportedformats;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _CheckTrack
|
||||||
|
{
|
||||||
|
GESTrack *track;
|
||||||
|
GESTrackElement *source;
|
||||||
|
} CheckTrack;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -221,6 +227,155 @@ _ungroup (GESContainer * container, gboolean recursive)
|
||||||
return ret;
|
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 *
|
* GObject virtual methods implementation *
|
||||||
|
@ -310,6 +465,7 @@ ges_clip_class_init (GESClipClass * klass)
|
||||||
container_class->add_child = _add_child;
|
container_class->add_child = _add_child;
|
||||||
container_class->remove_child = _remove_child;
|
container_class->remove_child = _remove_child;
|
||||||
container_class->ungroup = _ungroup;
|
container_class->ungroup = _ungroup;
|
||||||
|
container_class->group = _group;
|
||||||
|
|
||||||
klass->need_fill_track = TRUE;
|
klass->need_fill_track = TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,7 @@ ges_container_class_init (GESContainerClass * klass)
|
||||||
klass->remove_child = NULL;
|
klass->remove_child = NULL;
|
||||||
klass->add_child = NULL;
|
klass->add_child = NULL;
|
||||||
klass->ungroup = NULL;
|
klass->ungroup = NULL;
|
||||||
|
klass->group = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
* @container: (transfer full): The #GESContainer to ungroup
|
||||||
* @recursive: Wether to recursively ungroup @container
|
* @recursive: Wether to recursively ungroup @container
|
||||||
*
|
*
|
||||||
* Ungroups the #GESTimelineElement contained in this GESContainer,
|
* Ungroups the #GESTimelineElement contained in this GESContainer,
|
||||||
* creating new #GESContainer containing those #GESTimelineElement
|
* creating new #GESContainer containing those #GESTimelineElement
|
||||||
* properly apropriately.
|
* apropriately.
|
||||||
*
|
*
|
||||||
* Returns: (transfer container) (element-type GESContainer): The list of
|
* Returns: (transfer container) (element-type GESContainer): The list of
|
||||||
* #GESContainer resulting from the ungrouping operation
|
* #GESContainer resulting from the ungrouping operation
|
||||||
|
@ -703,3 +704,47 @@ ges_container_ungroup (GESContainer * container, gboolean recursive)
|
||||||
|
|
||||||
return klass->ungroup (container, 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;
|
||||||
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ struct _GESContainer
|
||||||
* @add_child: Virtual method to add 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.
|
* @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
|
* @ungroup: Ungroups the #GESTimelineElement contained in this #GESContainer, creating new
|
||||||
|
* @group: Groups the #GESContainers together
|
||||||
* #GESContainer containing those #GESTimelineElement apropriately.
|
* #GESContainer containing those #GESTimelineElement apropriately.
|
||||||
*/
|
*/
|
||||||
struct _GESContainerClass
|
struct _GESContainerClass
|
||||||
|
@ -105,6 +106,7 @@ struct _GESContainerClass
|
||||||
gboolean (*remove_child) (GESContainer *container, GESTimelineElement *element);
|
gboolean (*remove_child) (GESContainer *container, GESTimelineElement *element);
|
||||||
void (*get_priorty_range) (GESContainer *container, guint32 *min_prio, guint32 *max_prio);
|
void (*get_priorty_range) (GESContainer *container, guint32 *min_prio, guint32 *max_prio);
|
||||||
GList* (*ungroup) (GESContainer *container, gboolean recursive);
|
GList* (*ungroup) (GESContainer *container, gboolean recursive);
|
||||||
|
GESContainer * (*group) (GList *containers);
|
||||||
|
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
@ -119,6 +121,7 @@ GList* ges_container_get_children (GESContainer *container);
|
||||||
gboolean ges_container_add (GESContainer *container, GESTimelineElement *child);
|
gboolean ges_container_add (GESContainer *container, GESTimelineElement *child);
|
||||||
gboolean ges_container_remove (GESContainer *container, GESTimelineElement *child);
|
gboolean ges_container_remove (GESContainer *container, GESTimelineElement *child);
|
||||||
GList * ges_container_ungroup (GESContainer * container, gboolean recursive);
|
GList * ges_container_ungroup (GESContainer * container, gboolean recursive);
|
||||||
|
GESContainer *ges_container_group (GList *containers);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* _GES_CONTAINER */
|
#endif /* _GES_CONTAINER */
|
||||||
|
|
|
@ -177,13 +177,14 @@ GST_START_TEST (test_split_object)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
GST_START_TEST (test_clip_ungroup)
|
GST_START_TEST (test_clip_group_ungroup)
|
||||||
{
|
{
|
||||||
GESAsset *asset;
|
GESAsset *asset;
|
||||||
GESTimeline *timeline;
|
GESTimeline *timeline;
|
||||||
GESClip *clip, *clip2;
|
GESClip *clip, *clip2;
|
||||||
GList *containers, *tmp;
|
GList *containers, *tmp;
|
||||||
GESTimelineLayer *layer;
|
GESTimelineLayer *layer;
|
||||||
|
GESContainer *regrouped_clip;
|
||||||
GESTrack *audio_track, *video_track;
|
GESTrack *audio_track, *video_track;
|
||||||
|
|
||||||
ges_init ();
|
ges_init ();
|
||||||
|
@ -224,7 +225,6 @@ GST_START_TEST (test_clip_ungroup)
|
||||||
assert_equals_uint64 (_INPOINT (clip2), 0);
|
assert_equals_uint64 (_INPOINT (clip2), 0);
|
||||||
assert_equals_uint64 (_DURATION (clip2), 10);
|
assert_equals_uint64 (_DURATION (clip2), 10);
|
||||||
ASSERT_OBJECT_REFCOUNT (clip2, "1 for the layer + 1 in containers list", 2);
|
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);
|
tmp = ges_track_get_elements (audio_track);
|
||||||
assert_equals_int (g_list_length (tmp), 1);
|
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 (_INPOINT (clip2), 0);
|
||||||
assert_equals_uint64 (_DURATION (clip2), 10);
|
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);
|
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_object_properties);
|
||||||
tcase_add_test (tc_chain, test_split_object);
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue