gst/base/gstbasesink.c: Prepare for more accurate position reporting and query handling.
[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 /* this will be set in popt callbacks when a problem has been encountered */
118 static gboolean _gst_initialization_failure = FALSE;
119 extern gint _gst_trace_on;
120
121 /* set to TRUE when segfaults need to be left as is */
122 gboolean _gst_disable_segtrap = FALSE;
123
124
125 static void load_plugin_func (gpointer data, gpointer user_data);
126 static void init_popt_callback (poptContext context,
127     enum poptCallbackReason reason,
128     const GstPoptOption * option, const char *arg, void *data);
129 static gboolean init_pre (void);
130 static gboolean init_post (void);
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_DISABLE_CPU_OPT,
158   ARG_PLUGIN_SPEW,
159   ARG_PLUGIN_PATH,
160   ARG_PLUGIN_LOAD,
161   ARG_SEGTRAP_DISABLE
162 };
163
164 /* debug-spec ::= category-spec [, category-spec]*
165  * category-spec ::= category:val | val
166  * category ::= [^:]+
167  * val ::= [0-5]
168  */
169
170 #ifndef NUL
171 #define NUL '\0'
172 #endif
173
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
244 /**
245  * gst_init_get_popt_table:
246  *
247  * Returns a popt option table with GStreamer's argument specifications. The
248  * table is set up to use popt's callback method, so whenever the parsing is
249  * actually performed (via poptGetContext), the GStreamer libraries will
250  * be initialized.
251  *
252  * This function is useful if you want to integrate GStreamer with other
253  * libraries that use popt.
254  *
255  * Returns: a pointer to the static GStreamer option table.
256  * No free is necessary.
257  */
258 const GstPoptOption *
259 gst_init_get_popt_table (void)
260 {
261   static GstPoptOption gstreamer_options[] = {
262     {NULL, NUL, POPT_ARG_CALLBACK | POPT_CBFLAG_PRE | POPT_CBFLAG_POST,
263         (void *) &init_popt_callback, 0, NULL, NULL},
264     /* make sure we use our GETTEXT_PACKAGE as the domain for popt translations */
265     {NULL, NUL, POPT_ARG_INTL_DOMAIN, GETTEXT_PACKAGE, 0, NULL, NULL},
266     {"gst-version", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL, ARG_VERSION,
267         N_("Print the GStreamer version"), NULL},
268     {"gst-fatal-warnings", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
269         ARG_FATAL_WARNINGS, N_("Make all warnings fatal"), NULL},
270
271 #ifndef GST_DISABLE_GST_DEBUG
272     {"gst-debug-help", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
273         ARG_DEBUG_HELP, N_("Print available debug categories and exit"), NULL},
274     {"gst-debug-level", NUL, POPT_ARG_INT | POPT_ARGFLAG_STRIP, NULL,
275           ARG_DEBUG_LEVEL,
276           N_("Default debug level from 1 (only error) to 5 (anything) or "
277               "0 for no output"),
278         N_("LEVEL")},
279     {"gst-debug", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL, ARG_DEBUG,
280           N_("Comma-separated list of category_name:level pairs to set "
281               "specific levels for the individual categories. Example: "
282               "GST_AUTOPLUG:5,GST_ELEMENT_*:3"),
283         N_("LIST")},
284     {"gst-debug-no-color", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
285         ARG_DEBUG_NO_COLOR, N_("Disable colored debugging output"), NULL},
286     {"gst-debug-disable", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
287         ARG_DEBUG_DISABLE, N_("Disable debugging")},
288 #endif
289
290     {"gst-plugin-spew", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
291         ARG_PLUGIN_SPEW, N_("Enable verbose plugin loading diagnostics"), NULL},
292     {"gst-plugin-path", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
293         ARG_PLUGIN_PATH, NULL, N_("PATHS")},
294     {"gst-plugin-load", NUL, POPT_ARG_STRING | POPT_ARGFLAG_STRIP, NULL,
295           ARG_PLUGIN_LOAD,
296           N_("Comma-separated list of plugins to preload in addition to the "
297               "list stored in environment variable GST_PLUGIN_PATH"),
298         N_("PLUGINS")},
299     {"gst-disable-segtrap", NUL, POPT_ARG_NONE | POPT_ARGFLAG_STRIP, NULL,
300           ARG_SEGTRAP_DISABLE,
301           N_("Disable trapping of segmentation faults during plugin loading"),
302         NULL},
303     POPT_TABLEEND
304   };
305   static gboolean inited = FALSE;
306
307   if (!inited) {
308     int i;
309
310     for (i = 0; i < G_N_ELEMENTS (gstreamer_options); i++) {
311       if (gstreamer_options[i].longName == NULL) {
312       } else if (strcmp (gstreamer_options[i].longName, "gst-plugin-path") == 0) {
313         gstreamer_options[i].descrip =
314             g_strdup_printf (_
315             ("path list for loading plugins (separated by '%s')"),
316             G_SEARCHPATH_SEPARATOR_S);
317       }
318     }
319
320     inited = TRUE;
321   }
322
323   return gstreamer_options;
324 }
325
326 /**
327  * gst_init_check:
328  * @argc: pointer to application's argc
329  * @argv: pointer to application's argv
330  *
331  * Initializes the GStreamer library, setting up internal path lists,
332  * registering built-in elements, and loading standard plugins.
333  *
334  * This function will return %FALSE if GStreamer could not be initialized
335  * for some reason.  If you want your program to fail fatally,
336  * use gst_init() instead.
337  *
338  * Returns: %TRUE if GStreamer could be initialized.
339  */
340 gboolean
341 gst_init_check (int *argc, char **argv[])
342 {
343   return gst_init_check_with_popt_table (argc, argv, NULL);
344 }
345
346 /**
347  * gst_init:
348  * @argc: pointer to application's argc
349  * @argv: pointer to application's argv
350  *
351  * Initializes the GStreamer library, setting up internal path lists,
352  * registering built-in elements, and loading standard plugins.
353  *
354  * This function will terminate your program if it was unable to initialize
355  * GStreamer for some reason.  If you want your program to fall back,
356  * use gst_init_check() instead.
357  *
358  * WARNING: This function does not work in the same way as corresponding
359  * functions in other glib-style libraries, such as gtk_init().  In
360  * particular, unknown command line options cause this function to
361  * abort program execution.
362  */
363 void
364 gst_init (int *argc, char **argv[])
365 {
366   gst_init_with_popt_table (argc, argv, NULL);
367 }
368
369 /**
370  * gst_init_with_popt_table:
371  * @argc: pointer to application's argc
372  * @argv: pointer to application's argv
373  * @popt_options: pointer to a popt table to append
374  *
375  * Initializes the GStreamer library, parsing the options,
376  * setting up internal path lists,
377  * registering built-in elements, and loading standard plugins.
378  *
379  * This function will terminate your program if it was unable to initialize
380  * GStreamer for some reason.  If you want your program to fall back,
381  * use gst_init_check_with_popt_table() instead.
382  */
383 void
384 gst_init_with_popt_table (int *argc, char **argv[],
385     const GstPoptOption * popt_options)
386 {
387   if (!gst_init_check_with_popt_table (argc, argv, popt_options)) {
388     g_print ("Could not initialize GStreamer !\n");
389     exit (1);
390   }
391 }
392
393 /**
394  * gst_init_check_with_popt_table:
395  * @argc: pointer to application's argc
396  * @argv: pointer to application's argv
397  * @popt_options: pointer to a popt table to append
398  *
399  * Initializes the GStreamer library, parsing the options,
400  * setting up internal path lists,
401  * registering built-in elements, and loading standard plugins.
402  *
403  * Returns: %TRUE if GStreamer could be initialized.
404  */
405 gboolean
406 gst_init_check_with_popt_table (int *argc, char **argv[],
407     const GstPoptOption * popt_options)
408 {
409   poptContext context;
410   gint nextopt;
411   GstPoptOption *options;
412   const gchar *gst_debug_env = NULL;
413
414   GstPoptOption options_with[] = {
415     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, poptHelpOptions, 0, "Help options:",
416         NULL},
417     {NULL, NUL, POPT_ARG_INCLUDE_TABLE,
418           (GstPoptOption *) gst_init_get_popt_table (), 0,
419         "GStreamer options:", NULL},
420     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, (GstPoptOption *) popt_options, 0,
421         "Application options:", NULL},
422     POPT_TABLEEND
423   };
424   GstPoptOption options_without[] = {
425     {NULL, NUL, POPT_ARG_INCLUDE_TABLE, poptHelpOptions, 0, "Help options:",
426         NULL},
427     {NULL, NUL, POPT_ARG_INCLUDE_TABLE,
428           (GstPoptOption *) gst_init_get_popt_table (), 0,
429         "GStreamer options:", NULL},
430     POPT_TABLEEND
431   };
432
433   if (gst_initialized) {
434     GST_DEBUG ("already initialized gst");
435     return TRUE;
436   }
437   if (!argc || !argv) {
438     if (argc || argv)
439       g_warning ("gst_init: Only one of argc or argv was NULL");
440
441     if (!init_pre ())
442       return FALSE;
443     if (!init_post ())
444       return FALSE;
445     gst_initialized = TRUE;
446     return TRUE;
447   }
448
449   if (popt_options == NULL) {
450     options = options_without;
451   } else {
452     options = options_with;
453   }
454   context = poptGetContext ("GStreamer", *argc, (const char **) *argv,
455       options, 0);
456
457   /* check for GST_DEBUG_NO_COLOR environment variable */
458   if (g_getenv ("GST_DEBUG_NO_COLOR") != NULL)
459     gst_debug_set_colored (FALSE);
460
461   /* check for GST_DEBUG environment variable */
462   gst_debug_env = g_getenv ("GST_DEBUG");
463   if (gst_debug_env)
464     parse_debug_list (gst_debug_env);
465
466   /* Scan until we reach the end (-1), ignoring errors */
467   while ((nextopt = poptGetNextOpt (context)) != -1) {
468
469     /* If an error occurred and it's not an missing options, throw an error
470      * We don't want to show the "unknown option" message, since it'll
471      * might interfere with the applications own command line parsing
472      */
473     if (nextopt < 0 && nextopt != POPT_ERROR_BADOPT) {
474       g_print ("Error on option %s: %s.\nRun '%s --help' "
475           "to see a full list of available command line options.\n",
476           poptBadOption (context, 0), poptStrerror (nextopt), (*argv)[0]);
477
478       poptFreeContext (context);
479       return FALSE;
480     }
481   }
482
483   *argc = poptStrippedArgv (context, *argc, *argv);
484
485   poptFreeContext (context);
486
487   return TRUE;
488 }
489
490 #ifndef GST_DISABLE_REGISTRY
491 static void
492 add_path_func (gpointer data, gpointer user_data)
493 {
494   GST_INFO ("Adding plugin path: \"%s\"", (gchar *) data);
495   gst_registry_scan_path (gst_registry_get_default (), (gchar *) data);
496 }
497 #endif
498
499 static void
500 prepare_for_load_plugin_func (gpointer data, gpointer user_data)
501 {
502   preload_plugins = g_slist_prepend (preload_plugins, data);
503 }
504
505 static void
506 load_plugin_func (gpointer data, gpointer user_data)
507 {
508   GstPlugin *plugin;
509   const gchar *filename;
510   GError *err = NULL;
511
512   filename = (const gchar *) data;
513
514   plugin = gst_plugin_load_file (filename, &err);
515
516   if (plugin) {
517     GST_INFO ("Loaded plugin: \"%s\"", filename);
518
519     gst_default_registry_add_plugin (plugin);
520   } else {
521     if (err) {
522       /* Report error to user, and free error */
523       GST_ERROR ("Failed to load plugin: %s\n", err->message);
524       g_error_free (err);
525     } else {
526       GST_WARNING ("Failed to load plugin: \"%s\"", filename);
527     }
528   }
529
530   g_free (data);
531 }
532
533 static void
534 split_and_iterate (const gchar * stringlist, gchar * separator, GFunc iterator,
535     gpointer user_data)
536 {
537   gchar **strings;
538   gint j = 0;
539   gchar *lastlist = g_strdup (stringlist);
540
541   while (lastlist) {
542     strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT);
543     g_free (lastlist);
544     lastlist = NULL;
545
546     while (strings[j]) {
547       iterator (strings[j], user_data);
548       if (++j == MAX_PATH_SPLIT) {
549         lastlist = g_strdup (strings[j]);
550         g_strfreev (strings);
551         j = 0;
552         break;
553       }
554     }
555     g_strfreev (strings);
556   }
557 }
558
559 /* we have no fail cases yet, but maybe in the future */
560 static gboolean
561 init_pre (void)
562 {
563   g_type_init ();
564
565   if (g_thread_supported ()) {
566     /* somebody already initialized threading */
567   } else {
568     g_thread_init (NULL);
569   }
570   /* we need threading to be enabled right here */
571   _gst_debug_init ();
572
573 #ifdef ENABLE_NLS
574   setlocale (LC_ALL, "");
575   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
576 #endif /* ENABLE_NLS */
577
578 #ifndef GST_DISABLE_REGISTRY
579   {
580     const gchar *debug_list;
581
582     if (g_getenv ("GST_DEBUG_NO_COLOR") != NULL)
583       gst_debug_set_colored (FALSE);
584
585     debug_list = g_getenv ("GST_DEBUG");
586     if (debug_list) {
587       parse_debug_list (debug_list);
588     }
589   }
590 #endif
591   /* This is the earliest we can make stuff show up in the logs.
592    * So give some useful info about GStreamer here */
593   GST_INFO ("Initializing GStreamer Core Library version %s", VERSION);
594   GST_INFO ("Using library from %s", LIBDIR);
595
596   return TRUE;
597 }
598
599 static gboolean
600 gst_register_core_elements (GstPlugin * plugin)
601 {
602   /* register some standard builtin types */
603   if (!gst_element_register (plugin, "bin", GST_RANK_PRIMARY,
604           GST_TYPE_BIN) ||
605       !gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
606           GST_TYPE_PIPELINE) ||
607       !gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE)
608       )
609     g_assert_not_reached ();
610
611   return TRUE;
612 }
613
614 static GstPluginDesc plugin_desc = {
615   GST_VERSION_MAJOR,
616   GST_VERSION_MINOR,
617   "gstcoreelements",
618   "core elements of the GStreamer library",
619   gst_register_core_elements,
620   VERSION,
621   GST_LICENSE,
622   PACKAGE,
623   GST_PACKAGE,
624   GST_ORIGIN,
625
626   GST_PADDING_INIT
627 };
628
629 /*
630  * this bit handles:
631  * - initalization of threads if we use them
632  * - log handler
633  * - initial output
634  * - initializes gst_format
635  * - registers a bunch of types for gst_objects
636  *
637  * - we don't have cases yet where this fails, but in the future
638  *   we might and then it's nice to be able to return that
639  */
640 static gboolean
641 init_post (void)
642 {
643   GLogLevelFlags llf;
644
645 #ifndef GST_DISABLE_TRACE
646   GstTrace *gst_trace;
647 #endif /* GST_DISABLE_TRACE */
648
649   llf = G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL;
650   g_log_set_handler (g_log_domain_gstreamer, llf, debug_log_handler, NULL);
651
652   _gst_format_initialize ();
653   _gst_query_initialize ();
654   gst_object_get_type ();
655   gst_pad_get_type ();
656   gst_element_factory_get_type ();
657   gst_element_get_type ();
658   gst_type_find_factory_get_type ();
659   gst_bin_get_type ();
660
661 #ifndef GST_DISABLE_INDEX
662   gst_index_factory_get_type ();
663 #endif /* GST_DISABLE_INDEX */
664 #ifndef GST_DISABLE_URI
665   gst_uri_handler_get_type ();
666 #endif /* GST_DISABLE_URI */
667
668   /* register core plugins */
669   _gst_plugin_register_static (&plugin_desc);
670
671   gst_structure_get_type ();
672   _gst_value_initialize ();
673   gst_caps_get_type ();
674   _gst_plugin_initialize ();
675   _gst_event_initialize ();
676   _gst_buffer_initialize ();
677   _gst_message_initialize ();
678   _gst_tag_initialize ();
679
680 #ifndef GST_DISABLE_REGISTRY
681   {
682     char *registry_file;
683     const char *plugin_path;
684     GstRegistry *default_registry;
685
686     default_registry = gst_registry_get_default ();
687     registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
688     if (registry_file == NULL) {
689       registry_file = g_build_filename (g_get_home_dir (),
690           ".gstreamer-0.9", "registry.xml", NULL);
691     }
692     GST_DEBUG ("Reading registry cache");
693     gst_registry_xml_read_cache (default_registry, registry_file);
694
695     plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
696     if (plugin_path == NULL) {
697 #ifdef PLUGINS_USE_BUILDDIR
698       /* location libgstelements.so */
699       gst_registry_scan_path (default_registry,
700           PLUGINS_BUILDDIR "/gst/elements/.libs");
701       gst_registry_scan_path (default_registry,
702           PLUGINS_BUILDDIR "/gst/indexers/.libs");
703 #else
704       char *home_plugins;
705
706       /* add the main (installed) library path */
707       gst_registry_scan_path (default_registry, PLUGINS_DIR);
708
709       home_plugins = g_build_filename (g_get_home_dir (),
710           ".gstreamer-0.9", "plugins", NULL);
711       gst_registry_scan_path (default_registry, home_plugins);
712       g_free (home_plugins);
713 #endif /* PLUGINS_USE_BUILDDIR */
714     } else {
715       char **list;
716       int i;
717
718       /* FIXME this doesn't split paths correctly on windows */
719       list = g_strsplit (plugin_path, ":", 0);
720       for (i = 0; list[i]; i++) {
721         gst_registry_scan_path (default_registry, list[i]);
722       }
723       g_strfreev (list);
724     }
725
726     plugin_path = g_getenv ("GST_PLUGIN_PATH");
727     if (plugin_path) {
728       char **list;
729       int i;
730
731       /* FIXME this doesn't split paths correctly on windows */
732       list = g_strsplit (plugin_path, ":", 0);
733       for (i = 0; list[i]; i++) {
734         gst_registry_scan_path (default_registry, list[i]);
735       }
736       g_strfreev (list);
737     }
738
739     gst_registry_xml_write_cache (default_registry, registry_file);
740
741     _gst_registry_remove_cache_plugins (default_registry);
742
743     g_free (registry_file);
744   }
745 #endif /* GST_DISABLE_REGISTRY */
746
747   /* if we need to preload plugins */
748   if (preload_plugins) {
749     g_slist_foreach (preload_plugins, load_plugin_func, NULL);
750     g_slist_free (preload_plugins);
751     preload_plugins = NULL;
752   }
753 #ifndef GST_DISABLE_TRACE
754   _gst_trace_on = 0;
755   if (_gst_trace_on) {
756     gst_trace = gst_trace_new ("gst.trace", 1024);
757     gst_trace_set_default (gst_trace);
758   }
759 #endif /* GST_DISABLE_TRACE */
760
761   return TRUE;
762 }
763
764 #ifndef GST_DISABLE_GST_DEBUG
765 static gboolean
766 select_all (GstPlugin * plugin, gpointer user_data)
767 {
768   return TRUE;
769 }
770
771 static gint
772 sort_by_category_name (gconstpointer a, gconstpointer b)
773 {
774   return strcmp (gst_debug_category_get_name ((GstDebugCategory *) a),
775       gst_debug_category_get_name ((GstDebugCategory *) b));
776 }
777 static void
778 gst_debug_help (void)
779 {
780   GSList *list, *walk;
781   GList *list2, *g;
782
783   if (!init_post ())
784     exit (1);
785
786   list2 = gst_registry_plugin_filter (gst_registry_get_default (),
787       select_all, FALSE, NULL);
788
789   /* FIXME this is gross.  why don't debug have categories PluginFeatures? */
790   for (g = list2; g; g = g_list_next (g)) {
791     GstPlugin *plugin = GST_PLUGIN (g->data);
792
793     gst_plugin_load (plugin);
794   }
795   g_list_free (list2);
796
797   list = gst_debug_get_all_categories ();
798   walk = list = g_slist_sort (list, sort_by_category_name);
799
800   g_print ("\n");
801   g_print ("name                  level    description\n");
802   g_print ("---------------------+--------+--------------------------------\n");
803
804   while (walk) {
805     GstDebugCategory *cat = (GstDebugCategory *) walk->data;
806
807     if (gst_debug_is_colored ()) {
808       gchar *color = gst_debug_construct_term_color (cat->color);
809
810       g_print ("%s%-20s\033[00m  %1d %s  %s%s\033[00m\n",
811           color,
812           gst_debug_category_get_name (cat),
813           gst_debug_category_get_threshold (cat),
814           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
815           color, gst_debug_category_get_description (cat));
816       g_free (color);
817     } else {
818       g_print ("%-20s  %1d %s  %s\n", gst_debug_category_get_name (cat),
819           gst_debug_category_get_threshold (cat),
820           gst_debug_level_get_name (gst_debug_category_get_threshold (cat)),
821           gst_debug_category_get_description (cat));
822     }
823     walk = g_slist_next (walk);
824   }
825   g_slist_free (list);
826   g_print ("\n");
827 }
828 #endif
829
830 static void
831 init_popt_callback (poptContext context, enum poptCallbackReason reason,
832     const GstPoptOption * option, const char *arg, void *data)
833 {
834   GLogLevelFlags fatal_mask;
835
836   if (gst_initialized)
837     return;
838   switch (reason) {
839     case POPT_CALLBACK_REASON_PRE:
840       if (!init_pre ())
841         _gst_initialization_failure = TRUE;
842       break;
843     case POPT_CALLBACK_REASON_OPTION:
844       switch (option->val) {
845         case ARG_VERSION:
846           g_print ("GStreamer Core Library version %s\n", GST_VERSION);
847           exit (0);
848         case ARG_FATAL_WARNINGS:
849           fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
850           fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
851           g_log_set_always_fatal (fatal_mask);
852           break;
853 #ifndef GST_DISABLE_GST_DEBUG
854         case ARG_DEBUG_LEVEL:{
855           gint tmp = 0;
856
857           tmp = strtol (arg, NULL, 0);
858           if (tmp >= 0 && tmp < GST_LEVEL_COUNT) {
859             gst_debug_set_default_threshold (tmp);
860           }
861           break;
862         }
863         case ARG_DEBUG:
864           parse_debug_list (arg);
865           break;
866         case ARG_DEBUG_NO_COLOR:
867           gst_debug_set_colored (FALSE);
868           break;
869         case ARG_DEBUG_DISABLE:
870           gst_debug_set_active (FALSE);
871           break;
872         case ARG_DEBUG_HELP:
873           gst_debug_help ();
874           exit (0);
875 #endif
876         case ARG_PLUGIN_SPEW:
877           break;
878         case ARG_PLUGIN_PATH:
879 #ifndef GST_DISABLE_REGISTRY
880           split_and_iterate (arg, G_SEARCHPATH_SEPARATOR_S, add_path_func,
881               NULL);
882 #endif /* GST_DISABLE_REGISTRY */
883           break;
884         case ARG_PLUGIN_LOAD:
885           split_and_iterate (arg, ",", prepare_for_load_plugin_func, NULL);
886           break;
887         case ARG_SEGTRAP_DISABLE:
888           _gst_disable_segtrap = TRUE;
889           break;
890         default:
891           g_warning ("option %d not recognized", option->val);
892           break;
893       }
894       break;
895     case POPT_CALLBACK_REASON_POST:
896       if (!init_post ())
897         _gst_initialization_failure = TRUE;
898       gst_initialized = TRUE;
899       break;
900   }
901 }
902
903 /**
904  * gst_deinit:
905  *
906  * Clean up.
907  * Call only once, before exiting.
908  * After this call GStreamer should not be used anymore.
909  */
910
911 extern GstRegistry *_gst_registry_default;
912 void
913 gst_deinit (void)
914 {
915   GstClock *clock;
916
917   GST_INFO ("deinitializing GStreamer");
918   clock = gst_system_clock_obtain ();
919   gst_object_unref (clock);
920   gst_object_unref (clock);
921
922   _gst_registry_cleanup ();
923
924   gst_initialized = FALSE;
925   GST_INFO ("deinitialized GStreamer");
926 }
927
928 /**
929  * gst_version:
930  * @major: pointer to a guint to store the major version number
931  * @minor: pointer to a guint to store the minor version number
932  * @micro: pointer to a guint to store the micro version number
933  *
934  * Gets the version number of the GStreamer library.
935  */
936 void
937 gst_version (guint * major, guint * minor, guint * micro)
938 {
939   g_return_if_fail (major);
940   g_return_if_fail (minor);
941   g_return_if_fail (micro);
942
943   *major = GST_VERSION_MAJOR;
944   *minor = GST_VERSION_MINOR;
945   *micro = GST_VERSION_MICRO;
946 }