gst/gst.c: split plugin paths correctly
[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  * SECTION:gst
24  * @short_description: Media library supporting arbitrary formats and filter graphs.
25  * @see_also: Check out both <ulink url="http://www.cse.ogi.edu/sysl/">OGI's
26  *   pipeline</ulink> and Microsoft's DirectShow for some background.
27  *
28  * GStreamer is a framework for constructing graphs of various filters
29  * (termed elements here) that will handle streaming media.  Any discreet
30  * (packetizable) media type is supported, with provisions for automatically
31  * determining source type.  Formatting/framing information is provided with
32  * a powerful negotiation framework.  Plugins are heavily used to provide for
33  * all elements, allowing one to construct plugins outside of the GST
34  * library, even released binary-only if license require (please don't).
35  * 
36  * GStreamer borrows heavily from both the <ulink
37  * url="http://www.cse.ogi.edu/sysl/">OGI media pipeline</ulink> and
38  * Microsoft's DirectShow, hopefully taking the best of both and leaving the
39  * cruft behind.  Its interface is still very fluid and thus can be changed 
40  * to increase the sanity/noise ratio.
41  *
42  * The <application>GStreamer</application> library should be initialized with
43  * gst_init() before it can be used. You should pass pointers to the main argc
44  * and argv variables so that GStreamer can process its own command line
45  * options, as shown in the following example.
46  *
47  * <example>
48  * <title>Initializing the gstreamer library</title>
49  * <programlisting language="c">
50  * int 
51  * main (int argc, char *argv[])
52  * {
53  *   // initialize the GStreamer library
54  *   gst_init (&amp;argc, &amp;argv);
55  *   ...
56  * }
57  * </programlisting>
58  * </example>
59  * 
60  * It's allowed to pass two NULL pointers to gst_init() in case you don't want to
61  * pass the command line args to GStreamer.
62  *
63  * You can also use a popt table to initialize your own parameters as shown in
64  * the next code fragment:
65  * <example>
66  * <title>Initializing own parameters when initializing gstreamer</title>
67  * <programlisting>
68  * static gboolean stats = FALSE;
69  * ...
70  *  
71  * int 
72  * main (int argc, char *argv[])
73  * {
74  *   struct poptOption options[] = {
75  *     { "stats",  's',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &amp;stats,   0,
76  *         "Show pad stats", NULL},
77  *       POPT_TABLEEND
78  *     };
79  *   
80  *   // initialize the GStreamer library
81  *   gst_init_with_popt_table (&amp;argc, &amp;argv, options);
82  *   
83  *   ...
84  * }
85  * </programlisting>
86  * </example>
87  *
88  * Use gst_version() to query the library version at runtime or use the GST_VERSION_* macros
89  * to find the version at compile time.
90  *
91  * The functions gst_main() and gst_main_quit() enter and exit the main loop.
92  * GStreamer doesn't currently require you to use a mainloop but can intergrate
93  * with it without problems.
94  */
95
96 #include <stdlib.h>
97 #include <stdio.h>
98
99 #include "gst_private.h"
100 #include "gst-i18n-lib.h"
101 #include <locale.h>             /* for LC_ALL */
102
103 #include "gst.h"
104 #include "gstqueue.h"
105
106 #define GST_CAT_DEFAULT GST_CAT_GST_INIT
107
108 #define MAX_PATH_SPLIT  16
109 #define GST_PLUGIN_SEPARATOR ","
110
111 #ifndef GST_DISABLE_REGISTRY
112 gboolean _gst_registry_auto_load = TRUE;
113 #endif
114
115 static gboolean gst_initialized = FALSE;
116
117 extern gint _gst_trace_on;
118
119 /* set to TRUE when segfaults need to be left as is */
120 gboolean _gst_disable_segtrap = FALSE;
121
122
123 static void load_plugin_func (gpointer data, gpointer user_data);
124 static gboolean init_pre (void);
125 static gboolean init_post (void);
126 static gboolean parse_goption_arg (const gchar * s_opt,
127     const gchar * arg, gpointer data, GError ** err);
128
129 static GSList *preload_plugins = NULL;
130
131 const gchar *g_log_domain_gstreamer = "GStreamer";
132
133 static void
134 debug_log_handler (const gchar * log_domain,
135     GLogLevelFlags log_level, const gchar * message, gpointer user_data)
136 {
137   g_log_default_handler (log_domain, log_level, message, user_data);
138   /* FIXME: do we still need this ? fatal errors these days are all
139    * other than core errors */
140   /* g_on_error_query (NULL); */
141 }
142
143 enum
144 {
145   ARG_VERSION = 1,
146   ARG_FATAL_WARNINGS,
147 #ifndef GST_DISABLE_GST_DEBUG
148   ARG_DEBUG_LEVEL,
149   ARG_DEBUG,
150   ARG_DEBUG_DISABLE,
151   ARG_DEBUG_NO_COLOR,
152   ARG_DEBUG_HELP,
153 #endif
154   ARG_PLUGIN_SPEW,
155   ARG_PLUGIN_PATH,
156   ARG_PLUGIN_LOAD,
157   ARG_SEGTRAP_DISABLE
158 };
159
160 /* debug-spec ::= category-spec [, category-spec]*
161  * category-spec ::= category:val | val
162  * category ::= [^:]+
163  * val ::= [0-5]
164  */
165
166 #ifndef NUL
167 #define NUL '\0'
168 #endif
169
170 static gboolean
171 parse_debug_category (gchar * str, const gchar ** category)
172 {
173   if (!str)
174     return FALSE;
175
176   /* works in place */
177   g_strstrip (str);
178
179   if (str[0] != NUL) {
180     *category = str;
181     return TRUE;
182   }
183
184   return FALSE;
185 }
186
187 static gboolean
188 parse_debug_level (gchar * str, gint * level)
189 {
190   if (!str)
191     return FALSE;
192
193   /* works in place */
194   g_strstrip (str);
195
196   if (str[0] != NUL && str[1] == NUL
197       && str[0] >= '0' && str[0] < '0' + GST_LEVEL_COUNT) {
198     *level = str[0] - '0';
199     return TRUE;
200   }
201
202   return FALSE;
203 }
204
205 static void
206 parse_debug_list (const gchar * list)
207 {
208   gchar **split;
209   gchar **walk;
210
211   g_return_if_fail (list != NULL);
212
213   split = g_strsplit (list, ",", 0);
214
215   for (walk = split; *walk; walk++) {
216     if (strchr (*walk, ':')) {
217       gchar **values = g_strsplit (*walk, ":", 2);
218
219       if (values[0] && values[1]) {
220         gint level;
221         const gchar *category;
222
223         if (parse_debug_category (values[0], &category)
224             && parse_debug_level (values[1], &level))
225           gst_debug_set_threshold_for_name (category, level);
226       }
227
228       g_strfreev (values);
229     } else {
230       gint level;
231
232       if (parse_debug_level (*walk, &level))
233         gst_debug_set_default_threshold (level);
234     }
235   }
236
237   g_strfreev (split);
238 }
239
240 #ifndef GST_HAVE_GLIB_2_8
241 #define G_OPTION_FLAG_NO_ARG 0
242 #endif
243
244 /**
245  * gst_init_get_option_group:
246  *
247  * Returns a #GOptionGroup with GStreamer's argument specifications. The
248  * group is set up to use standard GOption callbacks, so when using this
249  * group in combination with GOption parsing methods, all argument parsing
250  * and initialization is automated.
251  *
252  * This function is useful if you want to integrate GStreamer with other
253  * libraries that use GOption.
254  *
255  * Returns: a pointer to a GStreamer option group. Should be dereferenced
256  * after use.
257  */
258
259 GOptionGroup *
260 gst_init_get_option_group (void)
261 {
262   GOptionGroup *group;
263   static GOptionEntry gst_args[] = {
264     {"gst-version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
265         parse_goption_arg, N_("Print the GStreamer version"), NULL},
266     {"gst-fatal-warnings", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
267         parse_goption_arg, N_("Make all warnings fatal"), NULL},
268 #ifndef GST_DISABLE_GST_DEBUG
269     {"gst-debug-help", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
270           parse_goption_arg, N_("Print available debug categories and exit"),
271         NULL},
272     {"gst-debug-level", 0, 0, G_OPTION_ARG_CALLBACK, parse_goption_arg,
273           N_("Default debug level from 1 (only error) to 5 (anything) or "
274               "0 for no output"),
275         N_("LEVEL")},
276     {"gst-debug", 0, 0, G_OPTION_ARG_CALLBACK, parse_goption_arg,
277           N_("Comma-separated list of category_name:level pairs to set "
278               "specific levels for the individual categories. Example: "
279               "GST_AUTOPLUG:5,GST_ELEMENT_*:3"),
280         N_("LIST")},
281     {"gst-debug-no-color", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
282         parse_goption_arg, N_("Disable colored debugging output"), NULL},
283     {"gst-debug-disable", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
284         parse_goption_arg, N_("Disable debugging"), NULL},
285 #endif
286     {"gst-plugin-spew", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
287           parse_goption_arg, N_("Enable verbose plugin loading diagnostics"),
288         NULL},
289     {"gst-plugin-path", 0, 0, G_OPTION_ARG_CALLBACK, parse_goption_arg,
290         N_("Colon-separated paths containing plugins"), N_("PATHS")},
291     {"gst-plugin-load", 0, 0, G_OPTION_ARG_CALLBACK, parse_goption_arg,
292           N_("Comma-separated list of plugins to preload in addition to the "
293               "list stored in environment variable GST_PLUGIN_PATH"),
294         N_("PLUGINS")},
295     {"gst-disable-segtrap", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
296           parse_goption_arg,
297           N_("Disable trapping of segmentation faults during plugin loading"),
298         NULL},
299     {NULL}
300   };
301
302   group = g_option_group_new ("gst", _("GStreamer Options"),
303       _("Show GStreamer Options"), NULL, NULL);
304   g_option_group_set_parse_hooks (group, (GOptionParseFunc) init_pre,
305       (GOptionParseFunc) init_post);
306
307   g_option_group_add_entries (group, gst_args);
308   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
309
310   return group;
311 }
312
313 /**
314  * gst_init_check:
315  * @argc: pointer to application's argc
316  * @argv: pointer to application's argv
317  * @err: pointer to a #GError to which a message will be posted on error
318  *
319  * Initializes the GStreamer library, setting up internal path lists,
320  * registering built-in elements, and loading standard plugins.
321  *
322  * This function will return %FALSE if GStreamer could not be initialized
323  * for some reason.  If you want your program to fail fatally,
324  * use gst_init() instead.
325  *
326  * Returns: %TRUE if GStreamer could be initialized.
327  */
328 gboolean
329 gst_init_check (int *argc, char **argv[], GError ** err)
330 {
331   GOptionGroup *group;
332   GOptionContext *ctx;
333   gboolean res;
334
335   if (gst_initialized) {
336     GST_DEBUG ("already initialized gst");
337     return TRUE;
338   }
339
340   ctx = g_option_context_new ("- GStreamer initialization");
341   group = gst_init_get_option_group ();
342   g_option_context_add_group (ctx, group);
343   res = g_option_context_parse (ctx, argc, argv, err);
344   g_option_context_free (ctx);
345
346   if (res) {
347     gst_initialized = TRUE;
348   }
349
350   return res;
351 }
352
353 /**
354  * gst_init:
355  * @argc: pointer to application's argc
356  * @argv: pointer to application's argv
357  *
358  * Initializes the GStreamer library, setting up internal path lists,
359  * registering built-in elements, and loading standard plugins.
360  *
361  * This function will terminate your program if it was unable to initialize
362  * GStreamer for some reason.  If you want your program to fall back,
363  * use gst_init_check() instead.
364  *
365  * WARNING: This function does not work in the same way as corresponding
366  * functions in other glib-style libraries, such as gtk_init().  In
367  * particular, unknown command line options cause this function to
368  * abort program execution.
369  */
370 void
371 gst_init (int *argc, char **argv[])
372 {
373   GError *err = NULL;
374
375   if (!gst_init_check (argc, argv, &err)) {
376     g_print ("Could not initialized GStreamer: %s\n",
377         err ? err->message : "unknown error occurred");
378     if (err) {
379       g_error_free (err);
380     }
381     exit (1);
382   }
383 }
384
385 #ifndef GST_DISABLE_REGISTRY
386 static void
387 add_path_func (gpointer data, gpointer user_data)
388 {
389   GST_INFO ("Adding plugin path: \"%s\"", (gchar *) data);
390   gst_registry_scan_path (gst_registry_get_default (), (gchar *) data);
391 }
392 #endif
393
394 static void
395 prepare_for_load_plugin_func (gpointer data, gpointer user_data)
396 {
397   preload_plugins = g_slist_prepend (preload_plugins, data);
398 }
399
400 static void
401 load_plugin_func (gpointer data, gpointer user_data)
402 {
403   GstPlugin *plugin;
404   const gchar *filename;
405   GError *err = NULL;
406
407   filename = (const gchar *) data;
408
409   plugin = gst_plugin_load_file (filename, &err);
410
411   if (plugin) {
412     GST_INFO ("Loaded plugin: \"%s\"", filename);
413
414     gst_default_registry_add_plugin (plugin);
415   } else {
416     if (err) {
417       /* Report error to user, and free error */
418       GST_ERROR ("Failed to load plugin: %s\n", err->message);
419       g_error_free (err);
420     } else {
421       GST_WARNING ("Failed to load plugin: \"%s\"", filename);
422     }
423   }
424
425   g_free (data);
426 }
427
428 static void
429 split_and_iterate (const gchar * stringlist, gchar * separator, GFunc iterator,
430     gpointer user_data)
431 {
432   gchar **strings;
433   gint j = 0;
434   gchar *lastlist = g_strdup (stringlist);
435
436   while (lastlist) {
437     strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT);
438     g_free (lastlist);
439     lastlist = NULL;
440
441     while (strings[j]) {
442       iterator (strings[j], user_data);
443       if (++j == MAX_PATH_SPLIT) {
444         lastlist = g_strdup (strings[j]);
445         g_strfreev (strings);
446         j = 0;
447         break;
448       }
449     }
450     g_strfreev (strings);
451   }
452 }
453
454 /* we have no fail cases yet, but maybe in the future */
455 static gboolean
456 init_pre (void)
457 {
458   g_type_init ();
459
460   if (g_thread_supported ()) {
461     /* somebody already initialized threading */
462   } else {
463     g_thread_init (NULL);
464   }
465   /* we need threading to be enabled right here */
466   _gst_debug_init ();
467
468 #ifdef ENABLE_NLS
469   setlocale (LC_ALL, "");
470   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
471 #endif /* ENABLE_NLS */
472
473 #ifndef GST_DISABLE_REGISTRY
474   {
475     const gchar *debug_list;
476
477     if (g_getenv ("GST_DEBUG_NO_COLOR") != NULL)
478       gst_debug_set_colored (FALSE);
479
480     debug_list = g_getenv ("GST_DEBUG");
481     if (debug_list) {
482       parse_debug_list (debug_list);
483     }
484   }
485 #endif
486   /* This is the earliest we can make stuff show up in the logs.
487    * So give some useful info about GStreamer here */
488   GST_INFO ("Initializing GStreamer Core Library version %s", VERSION);
489   GST_INFO ("Using library installed in %s", LIBDIR);
490
491   return TRUE;
492 }
493
494 static gboolean
495 gst_register_core_elements (GstPlugin * plugin)
496 {
497   /* register some standard builtin types */
498   if (!gst_element_register (plugin, "bin", GST_RANK_PRIMARY,
499           GST_TYPE_BIN) ||
500       !gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
501           GST_TYPE_PIPELINE) ||
502       !gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE)
503       )
504     g_assert_not_reached ();
505
506   return TRUE;
507 }
508
509 static GstPluginDesc plugin_desc = {
510   GST_VERSION_MAJOR,
511   GST_VERSION_MINOR,
512   "gstcoreelements",
513   "core elements of the GStreamer library",
514   gst_register_core_elements,
515   VERSION,
516   GST_LICENSE,
517   PACKAGE,
518   GST_PACKAGE,
519   GST_ORIGIN,
520
521   GST_PADDING_INIT
522 };
523
524 /*
525  * this bit handles:
526  * - initalization of threads if we use them
527  * - log handler
528  * - initial output
529  * - initializes gst_format
530  * - registers a bunch of types for gst_objects
531  *
532  * - we don't have cases yet where this fails, but in the future
533  *   we might and then it's nice to be able to return that
534  */
535 static gboolean
536 init_post (void)
537 {
538   GLogLevelFlags llf;
539
540 #ifndef GST_DISABLE_TRACE
541   GstTrace *gst_trace;
542 #endif /* GST_DISABLE_TRACE */
543
544   llf = G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL;
545   g_log_set_handler (g_log_domain_gstreamer, llf, debug_log_handler, NULL);
546
547   _gst_format_initialize ();
548   _gst_query_initialize ();
549   gst_object_get_type ();
550   gst_pad_get_type ();
551   gst_element_factory_get_type ();
552   gst_element_get_type ();
553   gst_type_find_factory_get_type ();
554   gst_bin_get_type ();
555
556 #ifndef GST_DISABLE_INDEX
557   gst_index_factory_get_type ();
558 #endif /* GST_DISABLE_INDEX */
559 #ifndef GST_DISABLE_URI
560   gst_uri_handler_get_type ();
561 #endif /* GST_DISABLE_URI */
562
563   /* register core plugins */
564   _gst_plugin_register_static (&plugin_desc);
565
566   gst_structure_get_type ();
567   _gst_value_initialize ();
568   gst_caps_get_type ();
569   _gst_plugin_initialize ();
570   _gst_event_initialize ();
571   _gst_buffer_initialize ();
572   _gst_message_initialize ();
573   _gst_tag_initialize ();
574
575 #ifndef GST_DISABLE_REGISTRY
576   {
577     char *registry_file;
578     const char *plugin_path;
579     GstRegistry *default_registry;
580
581     default_registry = gst_registry_get_default ();
582     registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
583     if (registry_file == NULL) {
584       registry_file = g_build_filename (g_get_home_dir (),
585           ".gstreamer-0.9", "registry.xml", NULL);
586     }
587     GST_DEBUG ("Reading registry cache");
588     gst_registry_xml_read_cache (default_registry, registry_file);
589
590     /* GST_PLUGIN_PATH specifies a list of directories to scan for
591      * additional plugins.  These take precedence over the system plugins */
592     plugin_path = g_getenv ("GST_PLUGIN_PATH");
593     if (plugin_path) {
594       char **list;
595       int i;
596
597       GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
598       list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
599       for (i = 0; list[i]; i++) {
600         gst_registry_scan_path (default_registry, list[i]);
601       }
602       g_strfreev (list);
603     } else {
604       GST_DEBUG ("GST_PLUGIN_PATH not set");
605     }
606
607     /* GST_PLUGIN_SYSTEM_PATH specifies a list of plugins that are always
608      * loaded by default.  If not set, this defaults to the system-installed
609      * path, and the plugins installed in the user's home directory */
610     plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
611     if (plugin_path == NULL) {
612       char *home_plugins;
613
614       GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set");
615
616       /* plugins in the user's home directory take precedence over
617        * system-installed ones */
618       home_plugins = g_build_filename (g_get_home_dir (),
619           ".gstreamer-0.9", "plugins", NULL);
620       gst_registry_scan_path (default_registry, home_plugins);
621       g_free (home_plugins);
622
623       /* add the main (installed) library path */
624       gst_registry_scan_path (default_registry, PLUGINS_DIR);
625     } else {
626       char **list;
627       int i;
628
629       GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path);
630       list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
631       for (i = 0; list[i]; i++) {
632         gst_registry_scan_path (default_registry, list[i]);
633       }
634       g_strfreev (list);
635     }
636
637     gst_registry_xml_write_cache (default_registry, registry_file);
638
639     _gst_registry_remove_cache_plugins (default_registry);
640
641     g_free (registry_file);
642   }
643
644 #endif /* GST_DISABLE_REGISTRY */
645
646   /* if we need to preload plugins */
647   if (preload_plugins) {
648     g_slist_foreach (preload_plugins, load_plugin_func, NULL);
649     g_slist_free (preload_plugins);
650     preload_plugins = NULL;
651   }
652 #ifndef GST_DISABLE_TRACE
653   _gst_trace_on = 0;
654   if (_gst_trace_on) {
655     gst_trace = gst_trace_new ("gst.trace", 1024);
656     gst_trace_set_default (gst_trace);
657   }
658 #endif /* GST_DISABLE_TRACE */
659
660   return TRUE;
661 }
662
663 #ifndef GST_DISABLE_GST_DEBUG
664 static gboolean
665 select_all (GstPlugin * plugin, gpointer user_data)
666 {
667   return TRUE;
668 }
669
670 static gint
671 sort_by_category_name (gconstpointer a, gconstpointer b)
672 {
673   return strcmp (gst_debug_category_get_name ((GstDebugCategory *) a),
674       gst_debug_category_get_name ((GstDebugCategory *) b));
675 }
676 static void
677 gst_debug_help (void)
678 {
679   GSList *list, *walk;
680   GList *list2, *g;
681
682   if (!init_post ())
683     exit (1);
684
685   list2 = gst_registry_plugin_filter (gst_registry_get_default (),
686       select_all, FALSE, NULL);
687
688   /* FIXME this is gross.  why don't debug have categories PluginFeatures? */
689   for (g = list2; g; g = g_list_next (g)) {
690     GstPlugin *plugin = GST_PLUGIN (g->data);
691
692     gst_plugin_load (plugin);
693   }
694   g_list_free (list2);
695
696   list = gst_debug_get_all_categories ();
697   walk = list = g_slist_sort (list, sort_by_category_name);
698
699   g_print ("\n");
700   g_print ("name                  level    description\n");
701   g_print ("---------------------+--------+--------------------------------\n");
702
703   while (walk) {
704     GstDebugCategory *cat = (GstDebugCategory *) walk->data;
705
706     if (gst_debug_is_colored ()) {
707       gchar *color = gst_debug_construct_term_color (cat->color);
708
709       g_print ("%s%-20s\033[00m  %1d %s  %s%s\033[00m\n",
710           color,
711           gst_debug_category_get_name (cat),
712           gst_debug_category_get_threshold (cat),
713           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
714           color, gst_debug_category_get_description (cat));
715       g_free (color);
716     } else {
717       g_print ("%-20s  %1d %s  %s\n", gst_debug_category_get_name (cat),
718           gst_debug_category_get_threshold (cat),
719           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
720           gst_debug_category_get_description (cat));
721     }
722     walk = g_slist_next (walk);
723   }
724   g_slist_free (list);
725   g_print ("\n");
726 }
727 #endif
728
729 static gboolean
730 parse_one_option (gint opt, const gchar * arg, GError ** err)
731 {
732   switch (opt) {
733     case ARG_VERSION:
734       g_print ("GStreamer Core Library version %s\n", GST_VERSION);
735       exit (0);
736     case ARG_FATAL_WARNINGS:{
737       GLogLevelFlags fatal_mask;
738
739       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
740       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
741       g_log_set_always_fatal (fatal_mask);
742       break;
743     }
744 #ifndef GST_DISABLE_GST_DEBUG
745     case ARG_DEBUG_LEVEL:{
746       gint tmp = 0;
747
748       tmp = strtol (arg, NULL, 0);
749       if (tmp >= 0 && tmp < GST_LEVEL_COUNT) {
750         gst_debug_set_default_threshold (tmp);
751       }
752       break;
753     }
754     case ARG_DEBUG:
755       parse_debug_list (arg);
756       break;
757     case ARG_DEBUG_NO_COLOR:
758       gst_debug_set_colored (FALSE);
759       break;
760     case ARG_DEBUG_DISABLE:
761       gst_debug_set_active (FALSE);
762       break;
763     case ARG_DEBUG_HELP:
764       gst_debug_help ();
765       exit (0);
766 #endif
767     case ARG_PLUGIN_SPEW:
768       break;
769     case ARG_PLUGIN_PATH:
770 #ifndef GST_DISABLE_REGISTRY
771       split_and_iterate (arg, G_SEARCHPATH_SEPARATOR_S, add_path_func, NULL);
772 #endif /* GST_DISABLE_REGISTRY */
773       break;
774     case ARG_PLUGIN_LOAD:
775       split_and_iterate (arg, ",", prepare_for_load_plugin_func, NULL);
776       break;
777     case ARG_SEGTRAP_DISABLE:
778       _gst_disable_segtrap = TRUE;
779       break;
780     default:
781       g_set_error (err, G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION,
782           _("Unknown option"));
783       return FALSE;
784   }
785
786   return TRUE;
787 }
788
789 static gboolean
790 parse_goption_arg (const gchar * opt,
791     const gchar * arg, gpointer data, GError ** err)
792 {
793   const struct
794   {
795     gchar *opt;
796     int val;
797   } options[] = {
798     {
799     "--gst-version", ARG_VERSION}, {
800     "--gst-fatal-warnings", ARG_FATAL_WARNINGS},
801 #ifndef GST_DISABLE_GST_DEBUG
802     {
803     "--gst-debug-level", ARG_DEBUG_LEVEL}, {
804     "--gst-debug", ARG_DEBUG}, {
805     "--gst-debug-disable", ARG_DEBUG_DISABLE}, {
806     "--gst-debug-no-color", ARG_DEBUG_NO_COLOR}, {
807     "--gst-debug-help", ARG_DEBUG_HELP},
808 #endif
809     {
810     "--gst-plugin-spew", ARG_PLUGIN_SPEW}, {
811     "--gst-plugin-path", ARG_PLUGIN_PATH}, {
812     "--gst-plugin-load", ARG_PLUGIN_LOAD}, {
813     "--gst-disable-segtrap", ARG_SEGTRAP_DISABLE}, {
814     NULL}
815   };
816   gint val = 0, n;
817
818   for (n = 0; options[n].opt; n++) {
819     if (!strcmp (opt, options[n].opt)) {
820       val = options[n].val;
821       break;
822     }
823   }
824
825   return parse_one_option (val, arg, err);
826 }
827
828 /**
829  * gst_deinit:
830  *
831  * Clean up.
832  * Call only once, before exiting.
833  * After this call GStreamer should not be used anymore.
834  */
835
836 extern GstRegistry *_gst_registry_default;
837 void
838 gst_deinit (void)
839 {
840   GstClock *clock;
841
842   GST_INFO ("deinitializing GStreamer");
843   clock = gst_system_clock_obtain ();
844   gst_object_unref (clock);
845   gst_object_unref (clock);
846
847   _gst_registry_cleanup ();
848
849   gst_initialized = FALSE;
850   GST_INFO ("deinitialized GStreamer");
851 }
852
853 /**
854  * gst_version:
855  * @major: pointer to a guint to store the major version number
856  * @minor: pointer to a guint to store the minor version number
857  * @micro: pointer to a guint to store the micro version number
858  *
859  * Gets the version number of the GStreamer library.
860  */
861 void
862 gst_version (guint * major, guint * minor, guint * micro)
863 {
864   g_return_if_fail (major);
865   g_return_if_fail (minor);
866   g_return_if_fail (micro);
867
868   *major = GST_VERSION_MAJOR;
869   *minor = GST_VERSION_MINOR;
870   *micro = GST_VERSION_MICRO;
871 }