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