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