}
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)
{
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;
}
/* No default implementations */
klass->remove_child = NULL;
klass->add_child = NULL;
+ klass->ungroup = NULL;
}
static void
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);
+}
* @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
{
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 >*/
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 */
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)
{
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;
}