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