2896ac6f70f773fc8f39daeb4296f88ce2295a86
[platform/upstream/gst-editing-services.git] / ges / ges.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *               2009 Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION: ges.h
23  * @title: Initialization
24  * @short_description: GStreamer editing services initialization functions
25  *
26  * GES needs to be initialized after GStreamer itself. This section
27  * contains the various functions to do so.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <ges/ges.h>
36 #include "ges/gstframepositioner.h"
37 #include "ges-internal.h"
38
39 #ifndef DISABLE_XPTV
40 #include <ges/ges-pitivi-formatter.h>
41 #endif
42
43 #define GES_GNONLIN_VERSION_NEEDED_MAJOR 1
44 #define GES_GNONLIN_VERSION_NEEDED_MINOR 2
45 #define GES_GNONLIN_VERSION_NEEDED_MICRO 0
46
47 GST_DEBUG_CATEGORY (_ges_debug);
48
49 G_LOCK_DEFINE_STATIC (init_lock);
50
51 /* (without holding ref) thread object for thread_self() validation
52  * between init/deinit
53  */
54 static GThread *initialized_thread = NULL;
55
56 static gboolean
57 ges_init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
58     GError ** error)
59 {
60   if (initialized_thread) {
61     GST_DEBUG ("already initialized");
62     return TRUE;
63   }
64
65   /* initialize debugging category */
66   GST_DEBUG_CATEGORY_INIT (_ges_debug, "ges", GST_DEBUG_FG_YELLOW,
67       "GStreamer Editing Services");
68
69   return TRUE;
70 }
71
72 static gboolean
73 ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
74     GError ** error)
75 {
76   GESUriClipAssetClass *uriasset_klass = NULL;
77   GstElementFactory *nlecomposition_factory = NULL;
78
79   if (initialized_thread) {
80     GST_DEBUG ("already initialized ges");
81     return TRUE;
82   }
83
84   uriasset_klass = g_type_class_ref (GES_TYPE_URI_CLIP_ASSET);
85
86   _init_formatter_assets ();
87   if (!_ges_uri_asset_ensure_setup (uriasset_klass)) {
88     GST_ERROR ("cannot setup uri asset");
89     goto failed;
90   }
91
92   nlecomposition_factory = gst_element_factory_find ("nlecomposition");
93   if (!nlecomposition_factory) {
94     GST_ERROR ("The `nlecomposition` object was not found.");
95     if (error)
96       *error = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN,
97           "The `nle` plugin is missing.");
98
99     goto failed;
100   }
101   gst_object_unref (nlecomposition_factory);
102
103   /* register clip classes with the system */
104
105   g_type_class_ref (GES_TYPE_TEST_CLIP);
106   g_type_class_ref (GES_TYPE_URI_CLIP);
107   g_type_class_ref (GES_TYPE_TITLE_CLIP);
108   g_type_class_ref (GES_TYPE_TRANSITION_CLIP);
109   g_type_class_ref (GES_TYPE_OVERLAY_CLIP);
110   g_type_class_ref (GES_TYPE_OVERLAY_TEXT_CLIP);
111
112   g_type_class_ref (GES_TYPE_GROUP);
113
114   /* Register track elements */
115   g_type_class_ref (GES_TYPE_EFFECT);
116
117   ges_asset_cache_init ();
118
119   gst_element_register (NULL, "framepositioner", 0, GST_TYPE_FRAME_POSITIONNER);
120   gst_element_register (NULL, "gespipeline", 0, GES_TYPE_PIPELINE);
121
122   /* TODO: user-defined types? */
123   initialized_thread = g_thread_self ();
124   g_type_class_unref (uriasset_klass);
125
126   GST_DEBUG ("GStreamer Editing Services initialized");
127
128   return TRUE;
129
130 failed:
131   if (uriasset_klass)
132     g_type_class_unref (uriasset_klass);
133
134   GST_ERROR ("Could not initialize GES.");
135
136   return FALSE;
137 }
138
139 /**
140  * ges_init:
141  *
142  * Initialize the GStreamer Editing Service. Call this before any usage of
143  * GES. You should take care of initilizing GStreamer before calling this
144  * function.
145  *
146  * MT safety.
147  * GStreamer Editing Services do not guarantee MT safety.
148  * An application is required to use GES APIs (including ges_deinit())
149  * in the thread where ges_init() was called.
150  */
151
152 gboolean
153 ges_init (void)
154 {
155   gboolean ret;
156
157   G_LOCK (init_lock);
158   ges_init_pre (NULL, NULL, NULL, NULL);
159
160   ret = ges_init_post (NULL, NULL, NULL, NULL);
161   G_UNLOCK (init_lock);
162
163   return ret;
164 }
165
166 /**
167  * ges_deinit:
168  *
169  * Clean up any resources created by GES in ges_init().
170  *
171  * It is normally not needed to call this function in a normal application as the
172  * resources will automatically be freed when the program terminates.
173  * This function is therefore mostly used by testsuites and other memory profiling tools.
174  * This function should be called from the thread where ges_init() was called.
175  *
176  * After this call GES should not be used until another ges_init() call.
177  */
178 void
179 ges_deinit (void)
180 {
181   G_LOCK (init_lock);
182
183   GST_INFO ("deinitializing GES");
184
185   if (!initialized_thread) {
186     GST_DEBUG ("nothing to deinitialize");
187     G_UNLOCK (init_lock);
188     return;
189   }
190
191   /* Allow deinit only from a thread where ges_init() was called */
192   g_assert (initialized_thread == g_thread_self ());
193
194   _ges_uri_asset_cleanup ();
195
196   g_type_class_unref (g_type_class_peek (GES_TYPE_TEST_CLIP));
197   g_type_class_unref (g_type_class_peek (GES_TYPE_URI_CLIP));
198   g_type_class_unref (g_type_class_peek (GES_TYPE_TITLE_CLIP));
199   g_type_class_unref (g_type_class_peek (GES_TYPE_TRANSITION_CLIP));
200   g_type_class_unref (g_type_class_peek (GES_TYPE_OVERLAY_CLIP));
201   g_type_class_unref (g_type_class_peek (GES_TYPE_OVERLAY_TEXT_CLIP));
202
203   g_type_class_unref (g_type_class_peek (GES_TYPE_GROUP));
204   /* Register track elements */
205   g_type_class_unref (g_type_class_peek (GES_TYPE_EFFECT));
206
207   ges_asset_cache_deinit ();
208   ges_xml_formatter_deinit ();
209
210   initialized_thread = NULL;
211   G_UNLOCK (init_lock);
212
213   GST_INFO ("deinitialized GES");
214
215   return;
216 }
217
218 #ifndef GST_DISABLE_OPTION_PARSING
219 static gboolean
220 parse_goption_arg (const gchar * s_opt,
221     const gchar * arg, gpointer data, GError ** err)
222 {
223   if (g_strcmp0 (s_opt, "--ges-version") == 0) {
224     g_print ("GStreamer Editing Services version %s\n", PACKAGE_VERSION);
225     exit (0);
226   } else if (g_strcmp0 (s_opt, "--ges-sample-paths") == 0) {
227     ges_add_missing_uri_relocation_uri (arg, FALSE);
228   } else if (g_strcmp0 (s_opt, "--ges-sample-path-recurse") == 0) {
229     ges_add_missing_uri_relocation_uri (arg, TRUE);
230   }
231
232   return TRUE;
233 }
234 #endif
235
236 /**
237  * ges_init_get_option_group: (skip)
238  *
239  * Returns a #GOptionGroup with GES's argument specifications. The
240  * group is set up to use standard GOption callbacks, so when using this
241  * group in combination with GOption parsing methods, all argument parsing
242  * and initialization is automated.
243  *
244  * This function is useful if you want to integrate GES with other
245  * libraries that use GOption (see g_option_context_add_group() ).
246  *
247  * If you use this function, you should make sure you initialise the GStreamer
248  * as one of the very first things in your program. That means you need to
249  * use gst_init_get_option_group() and add it to the option context before
250  * using the ges_init_get_option_group() result.
251  *
252  * Returns: (transfer full): a pointer to GES's option group.
253  */
254 GOptionGroup *
255 ges_init_get_option_group (void)
256 {
257 #ifndef GST_DISABLE_OPTION_PARSING
258
259   GOptionGroup *group;
260   static const GOptionEntry ges_args[] = {
261     {"ges-version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
262           (gpointer) parse_goption_arg,
263           "Print the GStreamer Editing Services version",
264         NULL},
265     {"ges-sample-paths", 0, 0, G_OPTION_ARG_CALLBACK,
266           (gpointer) parse_goption_arg,
267         "List of pathes to look assets in if they were moved"},
268     {"ges-sample-path-recurse", 0, 0, G_OPTION_ARG_CALLBACK,
269           (gpointer) parse_goption_arg,
270         "Same as above, but recursing into the folder"},
271     {NULL}
272   };
273
274   group = g_option_group_new ("GES", "GStreamer Editing Services Options",
275       "Show GES Options", NULL, NULL);
276   g_option_group_set_parse_hooks (group, (GOptionParseFunc) ges_init_pre,
277       (GOptionParseFunc) ges_init_post);
278   g_option_group_add_entries (group, ges_args);
279
280   return group;
281
282 #else
283   return NULL;
284 #endif
285 }
286
287 /**
288  * ges_version:
289  * @major: (out): pointer to a guint to store the major version number
290  * @minor: (out): pointer to a guint to store the minor version number
291  * @micro: (out): pointer to a guint to store the micro version number
292  * @nano:  (out): pointer to a guint to store the nano version number
293  *
294  * Gets the version number of the GStreamer Editing Services library.
295  */
296 void
297 ges_version (guint * major, guint * minor, guint * micro, guint * nano)
298 {
299   g_return_if_fail (major);
300   g_return_if_fail (minor);
301   g_return_if_fail (micro);
302   g_return_if_fail (nano);
303
304   *major = GES_VERSION_MAJOR;
305   *minor = GES_VERSION_MINOR;
306   *micro = GES_VERSION_MICRO;
307   *nano = GES_VERSION_NANO;
308 }
309
310 /**
311  * ges_init_check:
312  * @argc: (inout) (allow-none): pointer to application's argc
313  * @argv: (inout) (array length=argc) (allow-none): pointer to application's argv
314  * @err: pointer to a #GError to which a message will be posted on error
315  *
316  * Initializes the GStreamer Editing Services library, setting up internal path lists,
317  * and loading evrything needed.
318  *
319  * This function will return %FALSE if GES could not be initialized
320  * for some reason.
321  *
322  * Returns: %TRUE if GES could be initialized.
323  */
324 gboolean
325 ges_init_check (int *argc, char **argv[], GError ** err)
326 {
327 #ifndef GST_DISABLE_OPTION_PARSING
328   GOptionGroup *group;
329   GOptionContext *ctx;
330 #endif
331   gboolean res;
332
333   G_LOCK (init_lock);
334
335   if (initialized_thread) {
336     GST_DEBUG ("already initialized ges");
337     G_UNLOCK (init_lock);
338     return TRUE;
339   }
340 #ifndef GST_DISABLE_OPTION_PARSING
341   ctx = g_option_context_new ("- GStreamer Editing Services initialization");
342   g_option_context_set_ignore_unknown_options (ctx, TRUE);
343   g_option_context_set_help_enabled (ctx, FALSE);
344   group = ges_init_get_option_group ();
345   g_option_context_add_group (ctx, group);
346   res = g_option_context_parse (ctx, argc, argv, err);
347   g_option_context_free (ctx);
348 #endif
349
350   if (!res) {
351     G_UNLOCK (init_lock);
352     return res;
353   }
354
355   ges_init_pre (NULL, NULL, NULL, NULL);
356   res = ges_init_post (NULL, NULL, NULL, NULL);
357
358   G_UNLOCK (init_lock);
359
360   return res;
361 }
362
363 /**
364  * ges_is_initialized:
365  *
366  * Use this function to check if GES has been initialized with ges_init()
367  * or ges_init_check().
368  *
369  * Returns: %TRUE if initialization has been done, %FALSE otherwise.
370  *
371  * Since: 1.16
372  */
373 gboolean
374 ges_is_initialized (void)
375 {
376   return initialized_thread ? TRUE : FALSE;
377 }