intermediary commit. Still need to fill in more blanks :(
[platform/upstream/gstreamer.git] / ges / ges-timeline.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gesmarshal.h"
21 #include "ges-timeline.h"
22 #include "ges-track.h"
23 #include "ges-timeline-layer.h"
24 #include "ges.h"
25
26 /**
27  * GESTimelinePipeline
28  *
29  * Top-level container for pipelines
30  * 
31  * Contains a list of TimelineLayer which users should use to arrange the
32  * various timeline objects.
33  *
34  */
35
36 G_DEFINE_TYPE (GESTimeline, ges_timeline, GST_TYPE_BIN);
37
38 #define GET_PRIVATE(o) \
39   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GES_TYPE_TIMELINE, GESTimelinePrivate));
40
41 typedef struct _GESTimelinePrivate GESTimelinePrivate;
42
43 struct _GESTimelinePrivate
44 {
45
46 };
47
48 enum
49 {
50   TRACK_ADDED,
51   TRACK_REMOVED,
52   LAYER_ADDED,
53   LAYER_REMOVED,
54   LAST_SIGNAL
55 };
56
57 static guint ges_timeline_signals[LAST_SIGNAL] = { 0 };
58
59 static void
60 ges_timeline_get_property (GObject * object, guint property_id,
61     GValue * value, GParamSpec * pspec)
62 {
63   switch (property_id) {
64     default:
65       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
66   }
67 }
68
69 static void
70 ges_timeline_set_property (GObject * object, guint property_id,
71     const GValue * value, GParamSpec * pspec)
72 {
73   switch (property_id) {
74     default:
75       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76   }
77 }
78
79 static void
80 ges_timeline_dispose (GObject * object)
81 {
82   G_OBJECT_CLASS (ges_timeline_parent_class)->dispose (object);
83 }
84
85 static void
86 ges_timeline_finalize (GObject * object)
87 {
88   G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object);
89 }
90
91 static void
92 ges_timeline_class_init (GESTimelineClass * klass)
93 {
94   GObjectClass *object_class = G_OBJECT_CLASS (klass);
95
96   g_type_class_add_private (klass, sizeof (GESTimelinePrivate));
97
98   object_class->get_property = ges_timeline_get_property;
99   object_class->set_property = ges_timeline_set_property;
100   object_class->dispose = ges_timeline_dispose;
101   object_class->finalize = ges_timeline_finalize;
102
103   /* Signals
104    * 'track-added'
105    * 'track-removed'
106    * 'layer-added'
107    * 'layer-removed'
108    */
109
110   ges_timeline_signals[TRACK_ADDED] =
111       g_signal_new ("track-added", G_TYPE_FROM_CLASS (klass),
112       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, track_added), NULL,
113       NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GES_TYPE_TRACK);
114
115   ges_timeline_signals[TRACK_REMOVED] =
116       g_signal_new ("track-removed", G_TYPE_FROM_CLASS (klass),
117       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, track_removed),
118       NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GES_TYPE_TRACK);
119
120   ges_timeline_signals[LAYER_ADDED] =
121       g_signal_new ("layer-added", G_TYPE_FROM_CLASS (klass),
122       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, layer_added), NULL,
123       NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GES_TYPE_TIMELINE_LAYER);
124
125   ges_timeline_signals[LAYER_REMOVED] =
126       g_signal_new ("layer-removed", G_TYPE_FROM_CLASS (klass),
127       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, layer_removed),
128       NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
129       GES_TYPE_TIMELINE_LAYER);
130 }
131
132 static void
133 ges_timeline_init (GESTimeline * self)
134 {
135   self->layers = NULL;
136   self->tracks = NULL;
137 }
138
139 GESTimeline *
140 ges_timeline_new (void)
141 {
142   return g_object_new (GES_TYPE_TIMELINE, NULL);
143 }
144
145 GESTimeline *
146 ges_timeline_load_from_uri (gchar * uri)
147 {
148   /* FIXME : IMPLEMENT */
149   return NULL;
150 }
151
152 gboolean
153 ges_timeline_save (GESTimeline * timeline, gchar * uri)
154 {
155   /* FIXME : IMPLEMENT */
156   return FALSE;
157 }
158
159 static void
160 layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
161     GESTimeline * timeline)
162 {
163   GList *tmp;
164
165   GST_DEBUG ("New TimelineObject %p added to layer %p", object, layer);
166
167   for (tmp = timeline->tracks; tmp; tmp = g_list_next (tmp)) {
168     GESTrack *track = (GESTrack *) track;
169     GESTrackObject *trobj;
170
171     GST_LOG ("Trying with track %p", track);
172
173     if (G_UNLIKELY (!(trobj =
174                 ges_timeline_object_create_track_object (object, track)))) {
175       GST_WARNING ("Couldn't create TrackObject for TimelineObject");
176       continue;
177     }
178
179     GST_LOG ("Got new TrackObject %p, adding it to track", trobj);
180     ges_track_add_object (track, trobj);
181   }
182
183   GST_DEBUG ("done");
184 }
185
186
187 static void
188 layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
189     GESTimeline * timeline)
190 {
191   /* FIXME : IMPLEMENT */
192 }
193
194
195 gboolean
196 ges_timeline_add_layer (GESTimeline * timeline, GESTimelineLayer * layer)
197 {
198   GST_DEBUG ("timeline:%p, layer:%p", timeline, layer);
199
200   /* We can only add a layer that doesn't already belong to another timeline */
201   if (G_UNLIKELY (layer->timeline)) {
202     GST_WARNING ("Layer belongs to another timeline, can't add it");
203     return FALSE;
204   }
205
206   /* Add to the list of layers, make sure we don't already control it */
207   if (G_UNLIKELY (g_list_find (timeline->layers, (gconstpointer) layer))) {
208     GST_WARNING ("Layer is already controlled by this timeline");
209     return FALSE;
210   }
211
212   /* Reference is taken */
213   timeline->layers = g_list_append (timeline->layers, g_object_ref (layer));
214
215   /* Inform the layer that it belongs to a new timeline */
216   ges_timeline_layer_set_timeline (layer, timeline);
217
218   /* FIXME : GO OVER THE LIST OF EXISTING TIMELINE OBJECTS IN THAT LAYER
219    * AND ADD THEM !!! */
220
221   /* Connect to 'object-added'/'object-removed' signal from the new layer */
222   g_signal_connect (layer, "object-added", G_CALLBACK (layer_object_added_cb),
223       timeline);
224   g_signal_connect (layer, "object-removed",
225       G_CALLBACK (layer_object_removed_cb), timeline);
226
227   GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
228   g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
229
230   return TRUE;
231 }
232
233 gboolean
234 ges_timeline_remove_layer (GESTimeline * timeline, GESTimelineLayer * layer)
235 {
236   /* FIXME : IMPLEMENT */
237
238   /* Unassign tracks from the given layer */
239   return FALSE;
240 }
241
242 gboolean
243 ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
244 {
245   GST_DEBUG ("timeline:%p, track:%p", timeline, track);
246
247   /* Add to the list of tracks, make sure we don't already control it */
248   if (G_UNLIKELY (g_list_find (timeline->tracks, (gconstpointer) track))) {
249     GST_WARNING ("Track is already controlled by this timeline");
250     return FALSE;
251   }
252
253   /* Add the track to ourself (as a GstBin) 
254    * Reference is taken ! */
255   if (G_UNLIKELY (!gst_bin_add (GST_BIN (timeline), GST_ELEMENT (track)))) {
256     GST_WARNING ("Couldn't add track to ourself (GST)");
257     return FALSE;
258   }
259
260   /* Add the track to the list of tracks we track */
261   timeline->tracks = g_list_append (timeline->tracks, track);
262
263   /* Inform the track that it's currently being used by ourself */
264   ges_track_set_timeline (track, timeline);
265
266   GST_DEBUG ("Done adding track, emitting 'track-added' signal");
267
268   /* emit 'track-added' */
269   g_signal_emit (timeline, ges_timeline_signals[TRACK_ADDED], 0, track);
270
271   return TRUE;
272 }
273
274 gboolean
275 ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track)
276 {
277   /* FIXME : IMPLEMENT */
278
279   /* Signal track removal to all layers/objects */
280
281   /* */
282   return FALSE;
283 }