GESTrack: document more
[platform/upstream/gstreamer.git] / ges / ges-track.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 /**
21  * SECTION:ges-track
22  * @short_description: Composition of objects
23  *
24  * Corresponds to one output format (i.e. audio OR video).
25  *
26  * Contains the compatible TrackObject(s).
27  *
28  * Wraps GNonLin's 'gnlcomposition' element.
29  */
30
31 #include "ges-internal.h"
32 #include "ges-track.h"
33 #include "ges-track-object.h"
34
35 G_DEFINE_TYPE (GESTrack, ges_track, GST_TYPE_BIN);
36
37 enum
38 {
39   ARG_0,
40   ARG_CAPS,
41   ARG_TYPE
42 };
43
44 static void pad_added_cb (GstElement * element, GstPad * pad, GESTrack * track);
45
46 static void
47 pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track);
48
49 #define C_ENUM(v) ((gint) v)
50 static void
51 register_ges_track_type_select_result (GType * id)
52 {
53   static const GEnumValue values[] = {
54     {C_ENUM (GES_TRACK_TYPE_AUDIO), "GES_TRACK_TYPE_AUDIO", "audio"},
55     {C_ENUM (GES_TRACK_TYPE_VIDEO), "GES_TRACK_TYPE_VIDEO", "video"},
56     {C_ENUM (GES_TRACK_TYPE_TEXT), "GES_TRACK_TYPE_TEXT", "text"},
57     {C_ENUM (GES_TRACK_TYPE_CUSTOM), "GES_TRACK_TYPE_CUSTOM", "custom"},
58     {0, NULL, NULL}
59   };
60
61   *id = g_enum_register_static ("GESTrackType", values);
62 }
63
64 GType
65 ges_track_type_get_type (void)
66 {
67   static GType id;
68   static GOnce once = G_ONCE_INIT;
69
70   g_once (&once, (GThreadFunc) register_ges_track_type_select_result, &id);
71   return id;
72 }
73
74 static void
75 ges_track_get_property (GObject * object, guint property_id,
76     GValue * value, GParamSpec * pspec)
77 {
78   GESTrack *track = GES_TRACK (object);
79
80   switch (property_id) {
81     case ARG_CAPS:
82       gst_value_set_caps (value, track->caps);
83       break;
84     case ARG_TYPE:
85       g_value_set_enum (value, track->type);
86       break;
87     default:
88       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
89   }
90 }
91
92 static void
93 ges_track_set_property (GObject * object, guint property_id,
94     const GValue * value, GParamSpec * pspec)
95 {
96   GESTrack *track = GES_TRACK (object);
97
98   switch (property_id) {
99     case ARG_CAPS:
100       ges_track_set_caps (track, gst_value_get_caps (value));
101       break;
102     case ARG_TYPE:
103       track->type = g_value_get_enum (value);
104       break;
105     default:
106       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
107   }
108 }
109
110 static void
111 ges_track_dispose (GObject * object)
112 {
113   GESTrack *track = (GESTrack *) object;
114
115   /* FIXME : Remove all TrackObjects ! */
116
117   if (track->composition) {
118     gst_bin_remove (GST_BIN (object), track->composition);
119     track->composition = NULL;
120   }
121
122   G_OBJECT_CLASS (ges_track_parent_class)->dispose (object);
123 }
124
125 static void
126 ges_track_finalize (GObject * object)
127 {
128   G_OBJECT_CLASS (ges_track_parent_class)->finalize (object);
129 }
130
131 static void
132 ges_track_class_init (GESTrackClass * klass)
133 {
134   GObjectClass *object_class = G_OBJECT_CLASS (klass);
135
136   object_class->get_property = ges_track_get_property;
137   object_class->set_property = ges_track_set_property;
138   object_class->dispose = ges_track_dispose;
139   object_class->finalize = ges_track_finalize;
140
141   /**
142    * GESTrack:caps
143    *
144    * Caps used to filter/choose the output stream. This is generally set to
145    * a generic set of caps like 'video/x-raw-rgb;video/x-raw-yuv' for raw video.
146    *
147    * Default value: #GST_CAPS_ANY.
148    */
149   g_object_class_install_property (object_class, ARG_CAPS,
150       g_param_spec_boxed ("caps", "Caps",
151           "Caps used to filter/choose the output stream",
152           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
153
154   /**
155    * GESTrack:track-type
156    *
157    * Type of stream the track outputs. This is used when creating the #GESTrack
158    * to specify in generic terms what type of content will be outputted.
159    *
160    * It also serves as a 'fast' way to check what type of data will be outputted
161    * from the #GESTrack without having to actually check the #GESTrack's caps
162    * property.
163    */
164   g_object_class_install_property (object_class, ARG_TYPE,
165       g_param_spec_enum ("track-type", "TrackType",
166           "Type of stream the track outputs",
167           GES_TYPE_TRACK_TYPE, GES_TRACK_TYPE_CUSTOM,
168           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
169 }
170
171 static void
172 ges_track_init (GESTrack * self)
173 {
174   self->composition = gst_element_factory_make ("gnlcomposition", NULL);
175
176   g_signal_connect (self->composition, "pad-added", (GCallback) pad_added_cb,
177       self);
178   g_signal_connect (self->composition, "pad-removed",
179       (GCallback) pad_removed_cb, self);
180
181   if (!gst_bin_add (GST_BIN (self), self->composition))
182     GST_ERROR ("Couldn't add composition to bin !");
183 }
184
185 /**
186  * ges_track_new:
187  * @type: The type of track
188  * @caps: The caps to restrict the output of the track to.
189  *
190  * Creates a new #GESTrack with the given @type and @caps.
191  *
192  * Returns: A new #GESTrack.
193  */
194 GESTrack *
195 ges_track_new (GESTrackType type, GstCaps * caps)
196 {
197   return g_object_new (GES_TYPE_TRACK, "caps", caps, "track-type", type, NULL);
198 }
199
200 /**
201  * ges_track_video_raw_new:
202  *
203  * Creates a new #GESTrack of type #GES_TRACK_TYPE_VIDEO and with generic
204  * raw video caps ("video/x-raw-yuv;video/x-raw-rgb");
205  *
206  * Returns: A new #GESTrack.
207  */
208 GESTrack *
209 ges_track_video_raw_new ()
210 {
211   GESTrack *track;
212   GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb");
213
214   track = ges_track_new (GES_TRACK_TYPE_VIDEO, caps);
215   gst_caps_unref (caps);
216
217   return track;
218 }
219
220 /**
221  * ges_track_audio_raw_new:
222  *
223  * Creates a new #GESTrack of type #GES_TRACK_TYPE_AUDIO and with generic
224  * raw audio caps ("audio/x-raw-int;audio/x-raw-float");
225  *
226  * Returns: A new #GESTrack.
227  */
228 GESTrack *
229 ges_track_audio_raw_new ()
230 {
231   GESTrack *track;
232   GstCaps *caps = gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
233
234   track = ges_track_new (GES_TRACK_TYPE_AUDIO, caps);
235   gst_caps_unref (caps);
236
237   return track;
238 }
239
240 void
241 ges_track_set_timeline (GESTrack * track, GESTimeline * timeline)
242 {
243   GST_DEBUG ("track:%p, timeline:%p", track, timeline);
244
245   track->timeline = timeline;
246 }
247
248 /**
249  * ges_track_set_caps:
250  * @track: a #GESTrack
251  * @caps: the #GstCaps to set
252  *
253  * Sets the given @caps on the track.
254  */
255 void
256 ges_track_set_caps (GESTrack * track, const GstCaps * caps)
257 {
258   GST_DEBUG ("track:%p, caps:%" GST_PTR_FORMAT, track, caps);
259
260   g_return_if_fail (GST_IS_CAPS (caps));
261
262   if (track->caps)
263     gst_caps_unref (track->caps);
264   track->caps = gst_caps_copy (caps);
265
266   /* FIXME : update all trackobjects ? */
267 }
268
269 /**
270  * ges_track_add_object:
271  * @track: a #GESTrack
272  * @object: the #GESTrackObject to add
273  *
274  * Adds the given object to the track.
275  *
276  * Returns: #TRUE if the object was properly added. #FALSE if the track does not
277  * want to accept the object.
278  */
279 gboolean
280 ges_track_add_object (GESTrack * track, GESTrackObject * object)
281 {
282   GST_DEBUG ("track:%p, object:%p", track, object);
283
284   if (G_UNLIKELY (object->track != NULL)) {
285     GST_WARNING ("Object already belongs to another track");
286     return FALSE;
287   }
288
289   if (G_UNLIKELY (object->gnlobject != NULL)) {
290     GST_ERROR ("TrackObject doesn't have a gnlobject !");
291     return FALSE;
292   }
293
294   if (G_UNLIKELY (!ges_track_object_set_track (object, track))) {
295     GST_ERROR ("Couldn't properly add the object to the Track");
296     return FALSE;
297   }
298
299   GST_DEBUG ("Adding object to ourself");
300
301   /* make sure the object has a valid gnlobject ! */
302   if (G_UNLIKELY (!gst_bin_add (GST_BIN (track->composition),
303               object->gnlobject))) {
304     GST_WARNING ("Couldn't add object to the GnlComposition");
305     return FALSE;
306   }
307
308   return TRUE;
309 }
310
311 /**
312  * ges_track_remove_object:
313  * @track: a #GESTrack
314  * @object: the #GESTrackObject to remove
315  *
316  * Removes the object from the track.
317  *
318  * Returns: #TRUE if the object was removed, else #FALSE if the track
319  * could not remove the object (like if it didn't belong to the track).
320  */
321 gboolean
322 ges_track_remove_object (GESTrack * track, GESTrackObject * object)
323 {
324   GST_DEBUG ("track:%p, object:%p", track, object);
325
326   if (G_UNLIKELY (object->track != track)) {
327     GST_WARNING ("Object belongs to another track");
328     return FALSE;
329   }
330
331   if (G_LIKELY (object->gnlobject != NULL)) {
332     GST_DEBUG ("Removing GnlObject from composition");
333     if (!gst_bin_remove (GST_BIN (track->composition), object->gnlobject)) {
334       GST_WARNING ("Failed to remove gnlobject from composition");
335       return FALSE;
336     }
337   }
338
339   ges_track_object_set_track (object, NULL);
340
341   return TRUE;
342 }
343
344 static void
345 pad_added_cb (GstElement * element, GstPad * pad, GESTrack * track)
346 {
347   GST_DEBUG ("track:%p, pad %s:%s", track, GST_DEBUG_PAD_NAME (pad));
348
349   /* ghost the pad */
350   track->srcpad = gst_ghost_pad_new ("src", pad);
351
352   gst_pad_set_active (track->srcpad, TRUE);
353
354   gst_element_add_pad (GST_ELEMENT (track), track->srcpad);
355
356   GST_DEBUG ("done");
357 }
358
359 static void
360 pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track)
361 {
362   GST_DEBUG ("track:%p, pad %s:%s", track, GST_DEBUG_PAD_NAME (pad));
363
364   if (G_LIKELY (track->srcpad)) {
365     gst_pad_set_active (track->srcpad, FALSE);
366     gst_element_remove_pad (GST_ELEMENT (track), track->srcpad);
367     track->srcpad = NULL;
368   }
369
370   GST_DEBUG ("done");
371 }