smart-mixer: Use the new 'samples-selected' signal to handle queuing in aggregator...
[platform/upstream/gst-editing-services.git] / ges / ges-utils.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2010 Edward Hervey <edward.hervey@collabora.co.uk>
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:ges-utils
22  * @title: GES utilities
23  * @short_description: Convenience methods
24  *
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <string.h>
31
32 #include "ges-internal.h"
33 #include "ges-timeline.h"
34 #include "ges-track.h"
35 #include "ges-layer.h"
36 #include "ges.h"
37 #include <gst/base/base.h>
38
39 static GstElementFactory *compositor_factory = NULL;
40
41 /**
42  * ges_timeline_new_audio_video:
43  *
44  * Creates a new timeline containing a single #GESAudioTrack and a
45  * single #GESVideoTrack.
46  *
47  * Returns: (transfer floating): The new timeline, or %NULL if the tracks
48  * could not be created and added.
49  */
50
51 GESTimeline *
52 ges_timeline_new_audio_video (void)
53 {
54   GESTrack *tracka, *trackv;
55   GESTimeline *timeline;
56
57   /* This is our main GESTimeline */
58   timeline = ges_timeline_new ();
59
60   tracka = GES_TRACK (ges_audio_track_new ());
61   trackv = GES_TRACK (ges_video_track_new ());
62
63   if (!ges_timeline_add_track (timeline, trackv) ||
64       !ges_timeline_add_track (timeline, tracka)) {
65     gst_object_unref (timeline);
66     timeline = NULL;
67   }
68
69   return timeline;
70 }
71
72 /* Internal utilities */
73 gint
74 element_start_compare (GESTimelineElement * a, GESTimelineElement * b)
75 {
76   if (a->start == b->start) {
77     if (a->priority < b->priority)
78       return -1;
79     if (a->priority > b->priority)
80       return 1;
81     if (a->duration < b->duration)
82       return -1;
83     if (a->duration > b->duration)
84       return 1;
85     return 0;
86   } else if (a->start < b->start)
87     return -1;
88
89   return 1;
90 }
91
92 gint
93 element_end_compare (GESTimelineElement * a, GESTimelineElement * b)
94 {
95   if (GES_TIMELINE_ELEMENT_END (a) == GES_TIMELINE_ELEMENT_END (b)) {
96     if (a->priority < b->priority)
97       return -1;
98     if (a->priority > b->priority)
99       return 1;
100     if (a->duration < b->duration)
101       return -1;
102     if (a->duration > b->duration)
103       return 1;
104     return 0;
105   } else if (GES_TIMELINE_ELEMENT_END (a) < (GES_TIMELINE_ELEMENT_END (b)))
106     return -1;
107
108   return 1;
109 }
110
111 gboolean
112 ges_pspec_equal (gconstpointer key_spec_1, gconstpointer key_spec_2)
113 {
114   const GParamSpec *key1 = key_spec_1;
115   const GParamSpec *key2 = key_spec_2;
116
117   return (key1->owner_type == key2->owner_type &&
118       strcmp (key1->name, key2->name) == 0);
119 }
120
121 guint
122 ges_pspec_hash (gconstpointer key_spec)
123 {
124   const GParamSpec *key = key_spec;
125   const gchar *p;
126   guint h = key->owner_type;
127
128   for (p = key->name; *p; p++)
129     h = (h << 5) - h + *p;
130
131   return h;
132 }
133
134 static gboolean
135 find_compositor (GstPluginFeatureFilter * feature, gpointer udata)
136 {
137   gboolean res = FALSE;
138   const gchar *klass;
139   GstPluginFeature *loaded_feature = NULL;
140
141   if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
142     return FALSE;
143
144   klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY_CAST (feature),
145       GST_ELEMENT_METADATA_KLASS);
146
147   if (strstr (klass, "Compositor") == NULL)
148     return FALSE;
149
150   loaded_feature = gst_plugin_feature_load (feature);
151   if (!loaded_feature) {
152     GST_ERROR ("Could not load feature: %" GST_PTR_FORMAT, feature);
153     return FALSE;
154   }
155
156   res =
157       g_type_is_a (gst_element_factory_get_element_type (GST_ELEMENT_FACTORY
158           (loaded_feature)), GST_TYPE_AGGREGATOR);
159   gst_object_unref (loaded_feature);
160   return res;
161 }
162
163 gboolean
164 ges_util_structure_get_clocktime (GstStructure * structure, const gchar * name,
165     GstClockTime * val, GESFrameNumber * frames)
166 {
167   gboolean found = FALSE;
168
169   const GValue *gvalue;
170
171   if (!val && !frames)
172     return FALSE;
173
174   gvalue = gst_structure_get_value (structure, name);
175   if (!gvalue)
176     return FALSE;
177
178   if (frames)
179     *frames = GES_FRAME_NUMBER_NONE;
180
181   found = TRUE;
182   if (val && G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) {
183     *val = (GstClockTime) g_value_get_uint64 (gvalue);
184   } else if (val && G_VALUE_TYPE (gvalue) == G_TYPE_UINT64) {
185     *val = (GstClockTime) g_value_get_uint64 (gvalue);
186   } else if (val && G_VALUE_TYPE (gvalue) == G_TYPE_UINT) {
187     *val = (GstClockTime) g_value_get_uint (gvalue);
188   } else if (val && G_VALUE_TYPE (gvalue) == G_TYPE_INT) {
189     *val = (GstClockTime) g_value_get_int (gvalue);
190   } else if (val && G_VALUE_TYPE (gvalue) == G_TYPE_INT64) {
191     *val = (GstClockTime) g_value_get_int64 (gvalue);
192   } else if (val && G_VALUE_TYPE (gvalue) == G_TYPE_DOUBLE) {
193     gdouble d = g_value_get_double (gvalue);
194
195     if (d == -1.0)
196       *val = GST_CLOCK_TIME_NONE;
197     else
198       *val = d * GST_SECOND;
199   } else if (frames && G_VALUE_TYPE (gvalue) == G_TYPE_STRING) {
200     const gchar *str = g_value_get_string (gvalue);
201
202     found = FALSE;
203     if (str && str[0] == 'f') {
204       GValue v = G_VALUE_INIT;
205
206       g_value_init (&v, G_TYPE_UINT64);
207       if (gst_value_deserialize (&v, &str[1])) {
208         *frames = g_value_get_uint64 (&v);
209         if (val)
210           *val = GST_CLOCK_TIME_NONE;
211         found = TRUE;
212       }
213       g_value_reset (&v);
214     }
215   } else {
216     found = FALSE;
217
218   }
219
220   return found;
221 }
222
223
224 GstElementFactory *
225 ges_get_compositor_factory (void)
226 {
227   GList *result;
228
229   if (compositor_factory)
230     return compositor_factory;
231
232   result = gst_registry_feature_filter (gst_registry_get (),
233       (GstPluginFeatureFilter) find_compositor, FALSE, NULL);
234
235   /* sort on rank and name */
236   result = g_list_sort (result, gst_plugin_feature_rank_compare_func);
237   g_assert (result);
238
239   compositor_factory = result->data;
240   gst_plugin_feature_list_free (result);
241
242   return compositor_factory;
243 }
244
245 void
246 ges_idle_add (GSourceFunc func, gpointer udata, GDestroyNotify notify)
247 {
248   GMainContext *context = g_main_context_get_thread_default ();
249   GSource *source = g_idle_source_new ();
250   if (!context)
251     context = g_main_context_default ();
252
253   g_source_set_callback (source, func, udata, notify);
254   g_source_attach (source, context);
255
256 }
257
258 gboolean
259 ges_nle_composition_add_object (GstElement * comp, GstElement * object)
260 {
261   return gst_bin_add (GST_BIN (comp), object);
262 }
263
264 gboolean
265 ges_nle_composition_remove_object (GstElement * comp, GstElement * object)
266 {
267   return gst_bin_remove (GST_BIN (comp), object);
268 }
269
270 gboolean
271 ges_nle_object_commit (GstElement * nlesource, gboolean recurse)
272 {
273   gboolean ret;
274
275   g_signal_emit_by_name (nlesource, "commit", recurse, &ret);
276
277   return ret;
278 }