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