First THREADED backport attempt, focusing on adding locks and making sure the API...
[platform/upstream/gstreamer.git] / gst / gst.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gst.c: Initialization and non-pipeline operations
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 #include "gst_private.h"
27 #include "gst-i18n-lib.h"
28 #include <locale.h>             /* for LC_ALL */
29
30 #include "gst.h"
31 #include "gstqueue.h"
32 #ifndef GST_DISABLE_REGISTRY
33 #include "registries/gstxmlregistry.h"
34 #endif /* GST_DISABLE_REGISTRY */
35 #include "gstregistrypool.h"
36
37 #define GST_CAT_DEFAULT GST_CAT_GST_INIT
38
39 #define MAX_PATH_SPLIT  16
40 #define GST_PLUGIN_SEPARATOR ","
41
42 #ifndef GST_DISABLE_REGISTRY
43 gboolean _gst_registry_auto_load = TRUE;
44 static GstRegistry *_global_registry;
45 static GstRegistry *_user_registry;
46 static gboolean _gst_registry_fixed = FALSE;
47 #endif
48
49 static gboolean _gst_enable_cpu_opt = TRUE;
50
51 static gboolean gst_initialized = FALSE;
52
53 /* this will be set in popt callbacks when a problem has been encountered */
54 static gboolean _gst_initialization_failure = FALSE;
55 extern gint _gst_trace_on;
56
57 /* set to TRUE when segfaults need to be left as is */
58 gboolean _gst_disable_segtrap = FALSE;
59
60
61 static void load_plugin_func (gpointer data, gpointer user_data);
62 static void init_popt_callback (poptContext context,
63     enum poptCallbackReason reason,
64     const GstPoptOption * option, const char *arg, void *data);
65 static gboolean init_pre (void);
66 static gboolean init_post (void);
67
68 static GSList *preload_plugins = NULL;
69
70 const gchar *g_log_domain_gstreamer = "GStreamer";
71
72 static void
73 debug_log_handler (const gchar * log_domain,
74     GLogLevelFlags log_level, const gchar * message, gpointer user_data)
75 {
76   g_log_default_handler (log_domain, log_level, message, user_data);
77   /* FIXME: do we still need this ? fatal errors these days are all
78    * other than core errors */
79   /* g_on_error_query (NULL); */
80 }
81
82 enum
83 {
84   ARG_VERSION = 1,
85   ARG_FATAL_WARNINGS,
86 #ifndef GST_DISABLE_GST_DEBUG
87   ARG_DEBUG_LEVEL,
88   ARG_DEBUG,
89   ARG_DEBUG_DISABLE,
90   ARG_DEBUG_NO_COLOR,
91   ARG_DEBUG_HELP,
92 #endif
93   ARG_DISABLE_CPU_OPT,
94   ARG_PLUGIN_SPEW,
95   ARG_PLUGIN_PATH,
96   ARG_PLUGIN_LOAD,
97   ARG_SEGTRAP_DISABLE,
98   ARG_SCHEDULER,
99   ARG_REGISTRY
100 };
101
102 static void
103 parse_debug_list (const gchar * list)
104 {
105   gchar **split;
106   gchar **walk;
107
108   g_return_if_fail (list != NULL);
109
110   walk = split = g_strsplit (list, ",", 0);
111
112   while (walk[0]) {
113     gchar **values = g_strsplit (walk[0], ":", 2);
114
115     if (values[0] && values[1]) {
116       gint level = 0;
117
118       g_strstrip (values[0]);
119       g_strstrip (values[1]);
120       level = strtol (values[1], NULL, 0);
121       if (level >= 0 && level < GST_LEVEL_COUNT) {
122         GST_DEBUG ("setting debugging to level %d for name \"%s\"",
123             level, values[0]);
124         gst_debug_set_threshold_for_name (values[0], level);
125       }
126     }
127     g_strfreev (values);
128     walk++;
129   }
130   g_strfreev (split);
131 }
132
133 #ifndef NUL
134 #define NUL '\0'
135 #endif
136
137 /**
138  * gst_init_get_popt_table:
139  *
140  * Returns a popt option table with GStreamer's argument specifications. The
141  * table is set up to use popt's callback method, so whenever the parsing is
142  * actually performed (via poptGetContext), the GStreamer libraries will
143  * be initialized.
144  *
145  * This function is useful if you want to integrate GStreamer with other
146  * libraries that use popt.
147  *
148  * Returns: a pointer to the static GStreamer option table.
149  * No free is necessary.
150  */
151 const GstPoptOption *
152 gst_init_get_popt_table (void)
153 {
154   static GstPoptOption gstreamer_options[] = {
155     {NULL, NUL, POPT_ARG_CALLBACK | POPT_CBFLAG_PRE | POPT_CBFLAG_POST,
156         (void *) &init_popt_callback, 0, NULL, NULL},
157     /* make sure we use our GETTEXT_PACKAGE as the domain for popt translations */
158     {NULL, NUL, POPT_ARG_INTL_DOMAIN, GETTEXT_PACKAGE, 0, NULL, NULL},
159     {"gst-version", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL, ARG_VERSION,
160         N_("Print the GStreamer version"), NULL},
161     {"gst-fatal-warnings", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
162         ARG_FATAL_WARNINGS, N_("Make all warnings fatal"), NULL},
163
164 #ifndef GST_DISABLE_GST_DEBUG
165     {"gst-debug-help", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
166         ARG_DEBUG_HELP, N_("Print available debug categories and exit"), NULL},
167     {"gst-debug-level", NUL, POPT_ARG_INT | POPT_ARGFLAG_STRIP, NULL,
168           ARG_DEBUG_LEVEL,
169           N_("Default debug level from 1 (only error) to 5 (anything) or "
170               "0 for no output"),
171         N_("LEVEL")},
172     {"gst-debug", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL, ARG_DEBUG,
173           N_("Comma-separated list of category_name:level pairs to set "
174               "specific levels for the individual categories. Example: "
175               "GST_AUTOPLUG:5,GST_ELEMENT_*:3"),
176         N_("LIST")},
177     {"gst-debug-no-color", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
178         ARG_DEBUG_NO_COLOR, N_("Disable colored debugging output"), NULL},
179     {"gst-debug-disable", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
180         ARG_DEBUG_DISABLE, N_("Disable debugging")},
181 #endif
182
183     {"gst-disable-cpu-opt", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
184         ARG_DISABLE_CPU_OPT, N_("Disable accelerated CPU instructions"), NULL},
185     {"gst-plugin-spew", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
186         ARG_PLUGIN_SPEW, N_("Enable verbose plugin loading diagnostics"), NULL},
187     {"gst-plugin-path", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
188         ARG_PLUGIN_PATH, NULL, N_("PATHS")},
189     {"gst-plugin-load", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
190           ARG_PLUGIN_LOAD,
191           N_("Comma-separated list of plugins to preload in addition to the "
192               "list stored in environment variable GST_PLUGIN_PATH"),
193         N_("PLUGINS")},
194     {"gst-disable-segtrap", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
195           ARG_SEGTRAP_DISABLE,
196           N_("Disable trapping of segmentation faults during plugin loading"),
197         NULL},
198     {"gst-scheduler", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
199         ARG_SCHEDULER, NULL, N_("SCHEDULER")},
200     {"gst-registry", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
201         ARG_REGISTRY, N_("Registry to use"), N_("REGISTRY")},
202     POPT_TABLEEND
203   };
204   static gboolean inited = FALSE;
205
206   if (!inited) {
207     int i;
208
209     for (i = 0; i < G_N_ELEMENTS (gstreamer_options); i++) {
210       if (gstreamer_options[i].longName == NULL) {
211       } else if (strcmp (gstreamer_options[i].longName, "gst-plugin-path") == 0) {
212         gstreamer_options[i].descrip =
213             g_strdup_printf (_
214             ("path list for loading plugins (separated by '%s')"),
215             G_SEARCHPATH_SEPARATOR_S);
216       } else if (strcmp (gstreamer_options[i].longName, "gst-scheduler") == 0) {
217         gstreamer_options[i].descrip =
218             g_strdup_printf (_("Scheduler to use (default is '%s')"),
219             GST_SCHEDULER_DEFAULT_NAME);
220       }
221     }
222
223     inited = TRUE;
224   }
225
226   return gstreamer_options;
227 }
228
229 /**
230  * gst_init_check:
231  * @argc: pointer to application's argc
232  * @argv: pointer to application's argv
233  *
234  * Initializes the GStreamer library, setting up internal path lists,
235  * registering built-in elements, and loading standard plugins.
236  *
237  * This function will return %FALSE if GStreamer could not be initialized
238  * for some reason.  If you want your program to fail fatally,
239  * use gst_init() instead.
240  *
241  * Returns: %TRUE if GStreamer could be initialized.
242  */
243 gboolean
244 gst_init_check (int *argc, char **argv[])
245 {
246   return gst_init_check_with_popt_table (argc, argv, NULL);
247 }
248
249 /**
250  * gst_init:
251  * @argc: pointer to application's argc
252  * @argv: pointer to application's argv
253  *
254  * Initializes the GStreamer library, setting up internal path lists,
255  * registering built-in elements, and loading standard plugins.
256  *
257  * This function will terminate your program if it was unable to initialize
258  * GStreamer for some reason.  If you want your program to fall back,
259  * use gst_init_check() instead.
260  *
261  * WARNING: This function does not work in the same way as corresponding
262  * functions in other glib-style libraries, such as gtk_init().  In
263  * particular, unknown command line options cause this function to
264  * abort program execution.
265  */
266 void
267 gst_init (int *argc, char **argv[])
268 {
269   gst_init_with_popt_table (argc, argv, NULL);
270 }
271
272 /**
273  * gst_init_with_popt_table:
274  * @argc: pointer to application's argc
275  * @argv: pointer to application's argv
276  * @popt_options: pointer to a popt table to append
277  *
278  * Initializes the GStreamer library, parsing the options,
279  * setting up internal path lists,
280  * registering built-in elements, and loading standard plugins.
281  *
282  * This function will terminate your program if it was unable to initialize
283  * GStreamer for some reason.  If you want your program to fall back,
284  * use gst_init_check_with_popt_table() instead.
285  */
286 void
287 gst_init_with_popt_table (int *argc, char **argv[],
288     const GstPoptOption * popt_options)
289 {
290   if (!gst_init_check_with_popt_table (argc, argv, popt_options)) {
291     g_print ("Could not initialize GStreamer !\n");
292     exit (1);
293   }
294 }
295
296 /**
297  * gst_init_check_with_popt_table:
298  * @argc: pointer to application's argc
299  * @argv: pointer to application's argv
300  * @popt_options: pointer to a popt table to append
301  *
302  * Initializes the GStreamer library, parsing the options,
303  * setting up internal path lists,
304  * registering built-in elements, and loading standard plugins.
305  *
306  * Returns: %TRUE if GStreamer could be initialized.
307  */
308 gboolean
309 gst_init_check_with_popt_table (int *argc, char **argv[],
310     const GstPoptOption * popt_options)
311 {
312   poptContext context;
313   gint nextopt;
314   GstPoptOption *options;
315   const gchar *gst_debug_env = NULL;
316
317   GstPoptOption options_with[] = {
318     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, poptHelpOptions, 0, "Help options:",
319         NULL},
320     {NULL, NUL, POPT_ARG_INCLUDE_TABLE,
321           (GstPoptOption *) gst_init_get_popt_table (), 0,
322         "GStreamer options:", NULL},
323     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, (GstPoptOption *) popt_options, 0,
324         "Application options:", NULL},
325     POPT_TABLEEND
326   };
327   GstPoptOption options_without[] = {
328     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, poptHelpOptions, 0, "Help options:",
329         NULL},
330     {NULL, NUL, POPT_ARG_INCLUDE_TABLE,
331           (GstPoptOption *) gst_init_get_popt_table (), 0,
332         "GStreamer options:", NULL},
333     POPT_TABLEEND
334   };
335
336   if (gst_initialized) {
337     GST_DEBUG ("already initialized gst");
338     return TRUE;
339   }
340   if (!argc || !argv) {
341     if (argc || argv)
342       g_warning ("gst_init: Only one of argc or argv was NULL");
343
344     if (!init_pre ())
345       return FALSE;
346     if (!init_post ())
347       return FALSE;
348     gst_initialized = TRUE;
349     return TRUE;
350   }
351
352   if (popt_options == NULL) {
353     options = options_without;
354   } else {
355     options = options_with;
356   }
357   context = poptGetContext ("GStreamer", *argc, (const char **) *argv,
358       options, 0);
359
360   /* check for GST_DEBUG environment variable */
361   gst_debug_env = g_getenv ("GST_DEBUG");
362   if (gst_debug_env)
363     parse_debug_list (gst_debug_env);
364
365   /* Scan until we reach the end (-1), ignoring errors */
366   while ((nextopt = poptGetNextOpt (context)) != -1) {
367
368     /* If an error occurred and it's not an missing options, throw an error
369      * We don't want to show the "unknown option" message, since it'll
370      * might interfere with the applications own command line parsing
371      */
372     if (nextopt < 0 && nextopt != POPT_ERROR_BADOPT) {
373       g_print ("Error on option %s: %s.\nRun '%s --help' "
374           "to see a full list of available command line options.\n",
375           poptBadOption (context, 0), poptStrerror (nextopt), (*argv)[0]);
376
377       poptFreeContext (context);
378       return FALSE;
379     }
380   }
381
382   *argc = poptStrippedArgv (context, *argc, *argv);
383
384   poptFreeContext (context);
385
386   return TRUE;
387 }
388
389 #ifndef GST_DISABLE_REGISTRY
390 static void
391 add_path_func (gpointer data, gpointer user_data)
392 {
393   GstRegistry *registry = GST_REGISTRY (user_data);
394
395   GST_INFO ("Adding plugin path: \"%s\"", (gchar *) data);
396   gst_registry_add_path (registry, (gchar *) data);
397 }
398 #endif
399
400 static void
401 prepare_for_load_plugin_func (gpointer data, gpointer user_data)
402 {
403   preload_plugins = g_slist_prepend (preload_plugins, data);
404 }
405
406 static void
407 load_plugin_func (gpointer data, gpointer user_data)
408 {
409   GstPlugin *plugin;
410   const gchar *filename;
411   GError *err = NULL;
412
413   filename = (const gchar *) data;
414
415   plugin = gst_plugin_load_file (filename, &err);
416
417   if (plugin) {
418     GST_INFO ("Loaded plugin: \"%s\"", filename);
419
420     gst_registry_pool_add_plugin (plugin);
421   } else {
422     if (err) {
423       /* Report error to user, and free error */
424       GST_ERROR ("Failed to load plugin: %s\n", err->message);
425       g_error_free (err);
426     } else {
427       GST_WARNING ("Failed to load plugin: \"%s\"", filename);
428     }
429   }
430
431   g_free (data);
432 }
433
434 static void
435 split_and_iterate (const gchar * stringlist, gchar * separator, GFunc iterator,
436     gpointer user_data)
437 {
438   gchar **strings;
439   gint j = 0;
440   gchar *lastlist = g_strdup (stringlist);
441
442   while (lastlist) {
443     strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT);
444     g_free (lastlist);
445     lastlist = NULL;
446
447     while (strings[j]) {
448       iterator (strings[j], user_data);
449       if (++j == MAX_PATH_SPLIT) {
450         lastlist = g_strdup (strings[j]);
451         g_strfreev (strings);
452         j = 0;
453         break;
454       }
455     }
456   }
457 }
458
459 /* we have no fail cases yet, but maybe in the future */
460 static gboolean
461 init_pre (void)
462 {
463   g_type_init ();
464
465   if (g_thread_supported ()) {
466     /* somebody already initialized threading */
467   } else {
468     g_thread_init (NULL);
469   }
470   /* we need threading to be enabled right here */
471   _gst_debug_init ();
472
473 #ifdef ENABLE_NLS
474   setlocale (LC_ALL, "");
475   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
476 #endif /* ENABLE_NLS */
477
478 #ifndef GST_DISABLE_REGISTRY
479   {
480     const gchar *debug_list;
481
482     debug_list = g_getenv ("GST_DEBUG");
483     if (debug_list) {
484       parse_debug_list (debug_list);
485     }
486   }
487 #endif
488   /* This is the earliest we can make stuff show up in the logs.
489    * So give some useful info about GStreamer here */
490   GST_INFO ("Initializing GStreamer Core Library version %s", VERSION);
491   GST_INFO ("Using library from %s", LIBDIR);
492
493 #ifndef GST_DISABLE_REGISTRY
494   {
495     gchar *user_reg;
496     const gchar *homedir;
497
498     _global_registry =
499         gst_xml_registry_new ("global_registry", GLOBAL_REGISTRY_FILE);
500
501 #ifdef PLUGINS_USE_BUILDDIR
502     /* location libgstelements.so */
503     gst_registry_add_path (_global_registry, PLUGINS_BUILDDIR "/libs/gst");
504     gst_registry_add_path (_global_registry, PLUGINS_BUILDDIR "/gst/elements");
505     gst_registry_add_path (_global_registry, PLUGINS_BUILDDIR "/gst/types");
506     gst_registry_add_path (_global_registry, PLUGINS_BUILDDIR "/gst/autoplug");
507     gst_registry_add_path (_global_registry,
508         PLUGINS_BUILDDIR "/gst/schedulers");
509     gst_registry_add_path (_global_registry, PLUGINS_BUILDDIR "/gst/indexers");
510 #else
511     /* add the main (installed) library path */
512     gst_registry_add_path (_global_registry, PLUGINS_DIR);
513 #endif /* PLUGINS_USE_BUILDDIR */
514
515     if (g_getenv ("GST_REGISTRY")) {
516       user_reg = g_strdup (g_getenv ("GST_REGISTRY"));
517     } else {
518       homedir = g_get_home_dir ();
519       user_reg = g_strjoin ("/", homedir, LOCAL_REGISTRY_FILE, NULL);
520     }
521     _user_registry = gst_xml_registry_new ("user_registry", user_reg);
522
523     g_free (user_reg);
524   }
525 #endif /* GST_DISABLE_REGISTRY */
526
527   return TRUE;
528 }
529
530 static gboolean
531 gst_register_core_elements (GstPlugin * plugin)
532 {
533   /* register some standard builtin types */
534   if (!gst_element_register (plugin, "bin", GST_RANK_PRIMARY,
535           GST_TYPE_BIN) ||
536       !gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
537           GST_TYPE_PIPELINE) ||
538       !gst_element_register (plugin, "thread", GST_RANK_PRIMARY,
539           GST_TYPE_THREAD) ||
540       !gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE))
541     g_assert_not_reached ();
542
543   return TRUE;
544 }
545
546 static GstPluginDesc plugin_desc = {
547   GST_VERSION_MAJOR,
548   GST_VERSION_MINOR,
549   "gstcoreelements",
550   "core elements of the GStreamer library",
551   gst_register_core_elements,
552   NULL,
553   VERSION,
554   GST_LICENSE,
555   GST_PACKAGE,
556   GST_ORIGIN,
557
558   GST_PADDING_INIT
559 };
560
561 /*
562  * this bit handles:
563  * - initalization of threads if we use them
564  * - log handler
565  * - initial output
566  * - initializes gst_format
567  * - registers a bunch of types for gst_objects
568  *
569  * - we don't have cases yet where this fails, but in the future
570  *   we might and then it's nice to be able to return that
571  */
572 static gboolean
573 init_post (void)
574 {
575   GLogLevelFlags llf;
576   const gchar *plugin_path;
577
578 #ifndef GST_DISABLE_TRACE
579   GstTrace *gst_trace;
580 #endif /* GST_DISABLE_TRACE */
581
582   llf = G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL;
583   g_log_set_handler (g_log_domain_gstreamer, llf, debug_log_handler, NULL);
584
585   _gst_format_initialize ();
586   _gst_query_type_initialize ();
587   gst_object_get_type ();
588   gst_probe_get_type ();
589   gst_pad_get_type ();
590   gst_real_pad_get_type ();
591   gst_ghost_pad_get_type ();
592   gst_element_factory_get_type ();
593   gst_element_get_type ();
594   gst_scheduler_factory_get_type ();
595   gst_type_find_factory_get_type ();
596   gst_bin_get_type ();
597 #ifndef GST_DISABLE_INDEX
598   gst_index_factory_get_type ();
599 #endif /* GST_DISABLE_INDEX */
600 #ifndef GST_DISABLE_URI
601   gst_uri_handler_get_type ();
602 #endif /* GST_DISABLE_URI */
603
604   plugin_path = g_getenv ("GST_PLUGIN_PATH");
605 #ifndef GST_DISABLE_REGISTRY
606   split_and_iterate (plugin_path, G_SEARCHPATH_SEPARATOR_S, add_path_func,
607       _global_registry);
608 #endif /* GST_DISABLE_REGISTRY */
609
610   /* register core plugins */
611   _gst_plugin_register_static (&plugin_desc);
612
613   _gst_cpu_initialize (_gst_enable_cpu_opt);
614   gst_structure_get_type ();
615   _gst_value_initialize ();
616   gst_caps_get_type ();
617   _gst_plugin_initialize ();
618   _gst_event_initialize ();
619   _gst_buffer_initialize ();
620   _gst_tag_initialize ();
621
622 #ifndef GST_DISABLE_REGISTRY
623   if (!_gst_registry_fixed) {
624     /* don't override command-line options */
625     if (g_getenv ("GST_REGISTRY")) {
626       g_object_set (_global_registry, "location", g_getenv ("GST_REGISTRY"),
627           NULL);
628       _gst_registry_fixed = TRUE;
629     }
630   }
631
632   if (!_gst_registry_fixed) {
633     gst_registry_pool_add (_global_registry, 100);
634     gst_registry_pool_add (_user_registry, 50);
635   } else {
636
637     gst_registry_pool_add (_global_registry, 100);
638   }
639
640   if (_gst_registry_auto_load) {
641     gst_registry_pool_load_all ();
642   }
643 #endif /* GST_DISABLE_REGISTRY */
644
645   /* if we need to preload plugins */
646   if (preload_plugins) {
647     g_slist_foreach (preload_plugins, load_plugin_func, NULL);
648     g_slist_free (preload_plugins);
649     preload_plugins = NULL;
650   }
651 #ifndef GST_DISABLE_TRACE
652   _gst_trace_on = 0;
653   if (_gst_trace_on) {
654     gst_trace = gst_trace_new ("gst.trace", 1024);
655     gst_trace_set_default (gst_trace);
656   }
657 #endif /* GST_DISABLE_TRACE */
658
659   return TRUE;
660 }
661
662 #ifndef GST_DISABLE_GST_DEBUG
663 static gint
664 sort_by_category_name (gconstpointer a, gconstpointer b)
665 {
666   return strcmp (gst_debug_category_get_name ((GstDebugCategory *) a),
667       gst_debug_category_get_name ((GstDebugCategory *) b));
668 }
669 static void
670 gst_debug_help (void)
671 {
672   GSList *list, *walk;
673   GList *list2, *walk2;
674
675   if (!init_post ())
676     exit (1);
677
678   walk2 = list2 = gst_registry_pool_plugin_list ();
679   while (walk2) {
680     GstPlugin *plugin = GST_PLUGIN (walk2->data);
681
682     walk2 = g_list_next (walk2);
683
684     if (!gst_plugin_is_loaded (plugin)) {
685 #ifndef GST_DISABLE_REGISTRY
686       if (GST_IS_REGISTRY (plugin->manager)) {
687         GST_CAT_LOG (GST_CAT_PLUGIN_LOADING, "loading plugin %s",
688             plugin->desc.name);
689         if (gst_registry_load_plugin (GST_REGISTRY (plugin->manager),
690                 plugin) != GST_REGISTRY_OK)
691           GST_CAT_WARNING (GST_CAT_PLUGIN_LOADING, "loading plugin %s failed",
692               plugin->desc.name);
693       }
694 #endif /* GST_DISABLE_REGISTRY */
695     }
696   }
697   g_list_free (list2);
698
699   list = gst_debug_get_all_categories ();
700   walk = list = g_slist_sort (list, sort_by_category_name);
701
702   g_print ("\n");
703   g_print ("name                  level    description\n");
704   g_print ("---------------------+--------+--------------------------------\n");
705
706   while (walk) {
707     GstDebugCategory *cat = (GstDebugCategory *) walk->data;
708
709     if (gst_debug_is_colored ()) {
710       gchar *color = gst_debug_construct_term_color (cat->color);
711
712       g_print ("%s%-20s\033[00m  %1d %s  %s%s\033[00m\n",
713           color,
714           gst_debug_category_get_name (cat),
715           gst_debug_category_get_threshold (cat),
716           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
717           color, gst_debug_category_get_description (cat));
718       g_free (color);
719     } else {
720       g_print ("%-20s  %1d %s  %s\n", gst_debug_category_get_name (cat),
721           gst_debug_category_get_threshold (cat),
722           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
723           gst_debug_category_get_description (cat));
724     }
725     walk = g_slist_next (walk);
726   }
727   g_slist_free (list);
728   g_print ("\n");
729 }
730 #endif
731
732 static void
733 init_popt_callback (poptContext context, enum poptCallbackReason reason,
734     const GstPoptOption * option, const char *arg, void *data)
735 {
736   GLogLevelFlags fatal_mask;
737
738   if (gst_initialized)
739     return;
740   switch (reason) {
741     case POPT_CALLBACK_REASON_PRE:
742       if (!init_pre ())
743         _gst_initialization_failure = TRUE;
744       break;
745     case POPT_CALLBACK_REASON_OPTION:
746       switch (option->val) {
747         case ARG_VERSION:
748           g_print ("GStreamer Core Library version %s\n", GST_VERSION);
749           exit (0);
750         case ARG_FATAL_WARNINGS:
751           fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
752           fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
753           g_log_set_always_fatal (fatal_mask);
754           break;
755 #ifndef GST_DISABLE_GST_DEBUG
756         case ARG_DEBUG_LEVEL:{
757           gint tmp = 0;
758
759           tmp = strtol (arg, NULL, 0);
760           if (tmp >= 0 && tmp < GST_LEVEL_COUNT) {
761             gst_debug_set_default_threshold (tmp);
762           }
763           break;
764         }
765         case ARG_DEBUG:
766           parse_debug_list (arg);
767           break;
768         case ARG_DEBUG_NO_COLOR:
769           gst_debug_set_colored (FALSE);
770           break;
771         case ARG_DEBUG_DISABLE:
772           gst_debug_set_active (FALSE);
773           break;
774         case ARG_DEBUG_HELP:
775           gst_debug_help ();
776           exit (0);
777 #endif
778         case ARG_DISABLE_CPU_OPT:
779           _gst_enable_cpu_opt = FALSE;
780           break;
781         case ARG_PLUGIN_SPEW:
782           break;
783         case ARG_PLUGIN_PATH:
784 #ifndef GST_DISABLE_REGISTRY
785           split_and_iterate (arg, G_SEARCHPATH_SEPARATOR_S, add_path_func,
786               _user_registry);
787 #endif /* GST_DISABLE_REGISTRY */
788           break;
789         case ARG_PLUGIN_LOAD:
790           split_and_iterate (arg, ",", prepare_for_load_plugin_func, NULL);
791           break;
792         case ARG_SEGTRAP_DISABLE:
793           _gst_disable_segtrap = TRUE;
794           break;
795         case ARG_SCHEDULER:
796           gst_scheduler_factory_set_default_name (arg);
797           break;
798         case ARG_REGISTRY:
799 #ifndef GST_DISABLE_REGISTRY
800           g_object_set (G_OBJECT (_user_registry), "location", arg, NULL);
801           _gst_registry_fixed = TRUE;
802 #endif /* GST_DISABLE_REGISTRY */
803           break;
804         default:
805           g_warning ("option %d not recognized", option->val);
806           break;
807       }
808       break;
809     case POPT_CALLBACK_REASON_POST:
810       if (!init_post ())
811         _gst_initialization_failure = TRUE;
812       gst_initialized = TRUE;
813       break;
814   }
815 }
816
817 /**
818  * gst_version:
819  * @major: pointer to a guint to store the major version number
820  * @minor: pointer to a guint to store the minor version number
821  * @micro: pointer to a guint to store the micro version number
822  *
823  * Gets the version number of the GStreamer library.
824  */
825 void
826 gst_version (guint * major, guint * minor, guint * micro)
827 {
828   g_return_if_fail (major);
829   g_return_if_fail (minor);
830   g_return_if_fail (micro);
831
832   *major = GST_VERSION_MAJOR;
833   *minor = GST_VERSION_MINOR;
834   *micro = GST_VERSION_MICRO;
835 }