gst.c 52 KB
Newer Older
1
2
3
4
5
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *
 * gst.c: Initialization and non-pipeline operations
Erik Walthinsen's avatar
Erik Walthinsen committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
22

23
24
/**
 * SECTION:gst
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
25
26
 * @short_description: Media library supporting arbitrary formats and filter
 *                     graphs.
27
 * @see_also: Check out both <ulink url="http://www.cse.ogi.edu/sysl/">OGI's
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
28
 *            pipeline</ulink> and Microsoft's DirectShow for some background.
29
30
31
32
33
34
35
36
 *
 * GStreamer is a framework for constructing graphs of various filters
 * (termed elements here) that will handle streaming media.  Any discreet
 * (packetizable) media type is supported, with provisions for automatically
 * determining source type.  Formatting/framing information is provided with
 * a powerful negotiation framework.  Plugins are heavily used to provide for
 * all elements, allowing one to construct plugins outside of the GST
 * library, even released binary-only if license require (please don't).
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
37
 *
38
39
40
 * GStreamer borrows heavily from both the <ulink
 * url="http://www.cse.ogi.edu/sysl/">OGI media pipeline</ulink> and
 * Microsoft's DirectShow, hopefully taking the best of both and leaving the
Wim Taymans's avatar
Wim Taymans committed
41
 * cruft behind. Its interface is slowly getting stable.
42
43
44
45
46
47
48
49
 *
 * The <application>GStreamer</application> library should be initialized with
 * gst_init() before it can be used. You should pass pointers to the main argc
 * and argv variables so that GStreamer can process its own command line
 * options, as shown in the following example.
 *
 * <example>
 * <title>Initializing the gstreamer library</title>
50
 * <programlisting language="c">
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
51
 * int
52
53
54
55
56
57
58
59
 * main (int argc, char *argv[])
 * {
 *   // initialize the GStreamer library
 *   gst_init (&amp;argc, &amp;argv);
 *   ...
 * }
 * </programlisting>
 * </example>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
60
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
61
62
 * It's allowed to pass two NULL pointers to gst_init() in case you don't want
 * to pass the command line args to GStreamer.
63
 *
64
 * You can also use GOption to initialize your own parameters as shown in
65
66
67
68
69
70
 * the next code fragment:
 * <example>
 * <title>Initializing own parameters when initializing gstreamer</title>
 * <programlisting>
 * static gboolean stats = FALSE;
 * ...
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
71
 * int
72
73
 * main (int argc, char *argv[])
 * {
74
75
76
77
78
 *  GOptionEntry options[] = {
 *   {"tags", 't', 0, G_OPTION_ARG_NONE, &amp;tags,
 *       N_("Output tags (also known as metadata)"), NULL},
 *   {NULL}
 *  };
79
80
81
82
 *  // must initialise the threading system before using any other GLib funtion
 *  if (!g_thread_supported ())
 *    g_thread_init (NULL);
 *  ctx = g_option_context_new ("[ADDITIONAL ARGUMENTS]");
83
84
85
 *  g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
 *  g_option_context_add_group (ctx, gst_init_get_option_group ());
 *  if (!g_option_context_parse (ctx, &amp;argc, &amp;argv, &amp;err)) {
86
 *    g_print ("Error initializing: &percnt;s\n", GST_STR_NULL (err->message));
87
88
89
90
 *    exit (1);
 *  }
 *  g_option_context_free (ctx);
 * ...
91
92
93
94
 * }
 * </programlisting>
 * </example>
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
95
 * Use gst_version() to query the library version at runtime or use the
Wim Taymans's avatar
Wim Taymans committed
96
97
 * GST_VERSION_* macros to find the version at compile time. Optionally
 * gst_version_string() returns a printable string.
98
 *
Wim Taymans's avatar
Wim Taymans committed
99
100
101
102
 * The gst_deinit() call is used to clean up all internal resources used
 * by <application>GStreamer</application>. It is mostly used in unit tests 
 * to check for leaks.
 *
Wim Taymans's avatar
Wim Taymans committed
103
 * Last reviewed on 2006-08-11 (0.10.10)
104
 */
Erik Walthinsen's avatar
Erik Walthinsen committed
105

106
#include "gst_private.h"
107
#include "gstconfig.h"
Wim Taymans's avatar
Wim Taymans committed
108
#include <stdlib.h>
109
#include <stdio.h>
110
#include <sys/types.h>
111
#ifdef HAVE_FORK
112
#include <sys/wait.h>
Wim Taymans's avatar
Wim Taymans committed
113
#endif /* HAVE_FORK */
114
115
116
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
117
#ifdef HAVE_UNISTD_H
118
#include <unistd.h>
119
#endif
120
121
122
123
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN     /* prevents from including too many things */
#include <windows.h>            /* GetStdHandle, windows console */
#endif
Wim Taymans's avatar
Wim Taymans committed
124

125
#include "gst-i18n-lib.h"
126
#include <locale.h>             /* for LC_ALL */
127

128
#include "gst.h"
Erik Walthinsen's avatar
Erik Walthinsen committed
129

130
131
#define GST_CAT_DEFAULT GST_CAT_GST_INIT

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
132
#define MAX_PATH_SPLIT  16
133
#define GST_PLUGIN_SEPARATOR ","
134

135
static gboolean gst_initialized = FALSE;
136
static gboolean gst_deinitialized = FALSE;
137

138
#ifndef GST_DISABLE_REGISTRY
139
static GList *plugin_paths = NULL;      /* for delayed processing in post_init */
140
#endif
141

142
143
144
145
#ifndef GST_DISABLE_GST_DEBUG
extern const gchar *priv_gst_dump_dot_dir;
#endif

Wim Taymans's avatar
Wim Taymans committed
146
/* defaults */
Julien Moutte Moutte's avatar
Julien Moutte Moutte committed
147
#if defined(HAVE_FORK) && !defined(GST_HAVE_UNSAFE_FORK)
148
#define DEFAULT_FORK TRUE
Wim Taymans's avatar
Wim Taymans committed
149
#else
150
#define DEFAULT_FORK FALSE
Wim Taymans's avatar
Wim Taymans committed
151
152
#endif /* HAVE_FORK */

153
154
/* set to TRUE when segfaults need to be left as is */
static gboolean _gst_disable_segtrap = FALSE;
155

Wim Taymans's avatar
Wim Taymans committed
156
157
158
/* control the behaviour of registry rebuild */
static gboolean _gst_enable_registry_fork = DEFAULT_FORK;

159
160
161
/*set to TRUE when registry needn't to be updated */
static gboolean _gst_disable_registry_update = FALSE;

162
static void load_plugin_func (gpointer data, gpointer user_data);
163
164
165
166
static gboolean init_pre (GOptionContext * context, GOptionGroup * group,
    gpointer data, GError ** error);
static gboolean init_post (GOptionContext * context, GOptionGroup * group,
    gpointer data, GError ** error);
167
#ifndef GST_DISABLE_OPTION_PARSING
168
169
static gboolean parse_goption_arg (const gchar * s_opt,
    const gchar * arg, gpointer data, GError ** err);
170
#endif
171
172

static GSList *preload_plugins = NULL;
173

174
const gchar g_log_domain_gstreamer[] = "GStreamer";
175
176

static void
177
178
debug_log_handler (const gchar * log_domain,
    GLogLevelFlags log_level, const gchar * message, gpointer user_data)
179
{
180
  g_log_default_handler (log_domain, log_level, message, user_data);
181
182
183
  /* FIXME: do we still need this ? fatal errors these days are all
   * other than core errors */
  /* g_on_error_query (NULL); */
184
185
}

186
187
188
enum
{
  ARG_VERSION = 1,
189
  ARG_FATAL_WARNINGS,
190
#ifndef GST_DISABLE_GST_DEBUG
191
192
193
194
195
  ARG_DEBUG_LEVEL,
  ARG_DEBUG,
  ARG_DEBUG_DISABLE,
  ARG_DEBUG_NO_COLOR,
  ARG_DEBUG_HELP,
Benjamin Otte's avatar
Benjamin Otte committed
196
#endif
197
198
199
  ARG_PLUGIN_SPEW,
  ARG_PLUGIN_PATH,
  ARG_PLUGIN_LOAD,
Wim Taymans's avatar
Wim Taymans committed
200
  ARG_SEGTRAP_DISABLE,
201
  ARG_REGISTRY_UPDATE_DISABLE,
Wim Taymans's avatar
Wim Taymans committed
202
  ARG_REGISTRY_FORK_DISABLE
203
204
};

205
206
207
208
209
210
211
212
213
214
/* debug-spec ::= category-spec [, category-spec]*
 * category-spec ::= category:val | val
 * category ::= [^:]+
 * val ::= [0-5]
 */

#ifndef NUL
#define NUL '\0'
#endif

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
215
#ifndef GST_DISABLE_GST_DEBUG
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
static gboolean
parse_debug_category (gchar * str, const gchar ** category)
{
  if (!str)
    return FALSE;

  /* works in place */
  g_strstrip (str);

  if (str[0] != NUL) {
    *category = str;
    return TRUE;
  }

  return FALSE;
}

static gboolean
parse_debug_level (gchar * str, gint * level)
{
  if (!str)
    return FALSE;

  /* works in place */
  g_strstrip (str);

  if (str[0] != NUL && str[1] == NUL
      && str[0] >= '0' && str[0] < '0' + GST_LEVEL_COUNT) {
    *level = str[0] - '0';
    return TRUE;
  }

  return FALSE;
}

251
252
253
254
255
256
257
258
static void
parse_debug_list (const gchar * list)
{
  gchar **split;
  gchar **walk;

  g_return_if_fail (list != NULL);

259
  split = g_strsplit (list, ",", 0);
260

261
262
263
  for (walk = split; *walk; walk++) {
    if (strchr (*walk, ':')) {
      gchar **values = g_strsplit (*walk, ":", 2);
264

265
266
267
      if (values[0] && values[1]) {
        gint level;
        const gchar *category;
268

269
270
271
        if (parse_debug_category (values[0], &category)
            && parse_debug_level (values[1], &level))
          gst_debug_set_threshold_for_name (category, level);
272
      }
273
274
275
276
277
278
279

      g_strfreev (values);
    } else {
      gint level;

      if (parse_debug_level (*walk, &level))
        gst_debug_set_default_threshold (level);
280
281
    }
  }
282

283
284
  g_strfreev (split);
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
285
#endif
286

287
/**
288
 * gst_init_get_option_group:
289
 *
290
291
292
293
 * Returns a #GOptionGroup with GStreamer's argument specifications. The
 * group is set up to use standard GOption callbacks, so when using this
 * group in combination with GOption parsing methods, all argument parsing
 * and initialization is automated.
294
 *
295
 * This function is useful if you want to integrate GStreamer with other
296
 * libraries that use GOption (see g_option_context_add_group() ).
297
 *
298
299
300
301
302
 * If you use this function, you should make sure you initialise the GLib
 * threading system as one of the very first things in your program
 * (see the example at the beginning of this section).
 *
 * Returns: a pointer to GStreamer's option group.
303
 */
304

305
306
307
GOptionGroup *
gst_init_get_option_group (void)
{
308
#ifndef GST_DISABLE_OPTION_PARSING
309
  GOptionGroup *group;
310
  static const GOptionEntry gst_args[] = {
311
    {"gst-version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
312
        (gpointer) parse_goption_arg, N_("Print the GStreamer version"), NULL},
313
    {"gst-fatal-warnings", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
314
        (gpointer) parse_goption_arg, N_("Make all warnings fatal"), NULL},
315
#ifndef GST_DISABLE_GST_DEBUG
316
    {"gst-debug-help", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
317
318
          (gpointer) parse_goption_arg,
          N_("Print available debug categories and exit"),
319
        NULL},
320
321
    {"gst-debug-level", 0, 0, G_OPTION_ARG_CALLBACK,
          (gpointer) parse_goption_arg,
322
323
324
          N_("Default debug level from 1 (only error) to 5 (anything) or "
              "0 for no output"),
        N_("LEVEL")},
325
    {"gst-debug", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) parse_goption_arg,
326
327
328
329
          N_("Comma-separated list of category_name:level pairs to set "
              "specific levels for the individual categories. Example: "
              "GST_AUTOPLUG:5,GST_ELEMENT_*:3"),
        N_("LIST")},
330
    {"gst-debug-no-color", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
331
332
          (gpointer) parse_goption_arg, N_("Disable colored debugging output"),
        NULL},
333
    {"gst-debug-disable", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
334
        (gpointer) parse_goption_arg, N_("Disable debugging"), NULL},
335
#endif
336
    {"gst-plugin-spew", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
337
338
          (gpointer) parse_goption_arg,
          N_("Enable verbose plugin loading diagnostics"),
339
        NULL},
340
341
    {"gst-plugin-path", 0, 0, G_OPTION_ARG_CALLBACK,
          (gpointer) parse_goption_arg,
342
        N_("Colon-separated paths containing plugins"), N_("PATHS")},
343
344
    {"gst-plugin-load", 0, 0, G_OPTION_ARG_CALLBACK,
          (gpointer) parse_goption_arg,
345
          N_("Comma-separated list of plugins to preload in addition to the "
346
              "list stored in environment variable GST_PLUGIN_PATH"),
347
        N_("PLUGINS")},
348
    {"gst-disable-segtrap", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
349
          (gpointer) parse_goption_arg,
350
351
          N_("Disable trapping of segmentation faults during plugin loading"),
        NULL},
352
353
354
355
356
    {"gst-disable-registry-update", 0, G_OPTION_FLAG_NO_ARG,
          G_OPTION_ARG_CALLBACK,
          (gpointer) parse_goption_arg,
          N_("Disable updating the registry"),
        NULL},
Wim Taymans's avatar
Wim Taymans committed
357
358
    {"gst-disable-registry-fork", 0, G_OPTION_FLAG_NO_ARG,
          G_OPTION_ARG_CALLBACK,
359
          (gpointer) parse_goption_arg,
Wim Taymans's avatar
Wim Taymans committed
360
361
          N_("Disable the use of fork() while scanning the registry"),
        NULL},
362
    {NULL}
363
364
  };

365
366
367
368
369
370
371
372
373
  /* The GLib threading system must be initialised before calling any other
   * GLib function according to the documentation; if the application hasn't
   * called gst_init() yet or initialised the threading system otherwise, we
   * better issue a warning here (since chances are high that the application
   * has already called other GLib functions such as g_option_context_new() */
  if (!g_thread_supported ()) {
    g_warning ("The GStreamer function gst_init_get_option_group() was\n"
        "\tcalled, but the GLib threading system has not been initialised\n"
        "\tyet, something that must happen before any other GLib function\n"
374
375
376
377
        "\tis called. The application needs to be fixed so that it calls\n"
        "\t   if (!g_thread_supported ()) g_thread_init(NULL);\n"
        "\tas very first thing in its main() function. Please file a bug\n"
        "\tagainst this application.");
378
379
380
    g_thread_init (NULL);
  }

381
382
383
384
385
386
387
  group = g_option_group_new ("gst", _("GStreamer Options"),
      _("Show GStreamer Options"), NULL, NULL);
  g_option_group_set_parse_hooks (group, (GOptionParseFunc) init_pre,
      (GOptionParseFunc) init_post);

  g_option_group_add_entries (group, gst_args);
  g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
388

389
  return group;
390
391
392
#else
  return NULL;
#endif
393
394
}

395
396
397
398
/**
 * gst_init_check:
 * @argc: pointer to application's argc
 * @argv: pointer to application's argv
399
 * @err: pointer to a #GError to which a message will be posted on error
400
401
402
403
404
405
406
 *
 * Initializes the GStreamer library, setting up internal path lists,
 * registering built-in elements, and loading standard plugins.
 *
 * This function will return %FALSE if GStreamer could not be initialized
 * for some reason.  If you want your program to fail fatally,
 * use gst_init() instead.
Wim Taymans's avatar
Wim Taymans committed
407
 *
408
409
410
411
 * This function should be called before calling any other GLib functions. If
 * this is not an option, your program must initialise the GLib thread system
 * using g_thread_init() before any other GLib functions are called.
 *
412
 * Returns: %TRUE if GStreamer could be initialized.
413
414
 */
gboolean
415
gst_init_check (int *argc, char **argv[], GError ** err)
416
{
417
#ifndef GST_DISABLE_OPTION_PARSING
418
419
  GOptionGroup *group;
  GOptionContext *ctx;
420
#endif
421
422
  gboolean res;

423
424
425
  if (!g_thread_supported ())
    g_thread_init (NULL);

426
427
428
429
  if (gst_initialized) {
    GST_DEBUG ("already initialized gst");
    return TRUE;
  }
430
#ifndef GST_DISABLE_OPTION_PARSING
431
  ctx = g_option_context_new ("- GStreamer initialization");
432
  g_option_context_set_ignore_unknown_options (ctx, TRUE);
433
434
435
436
  group = gst_init_get_option_group ();
  g_option_context_add_group (ctx, group);
  res = g_option_context_parse (ctx, argc, argv, err);
  g_option_context_free (ctx);
437
438
439
440
441
#else
  init_pre (NULL, NULL, NULL, NULL);
  init_post (NULL, NULL, NULL, NULL);
  res = TRUE;
#endif
442

443
444
  gst_initialized = res;

445
  if (res) {
Wim Taymans's avatar
Wim Taymans committed
446
447
448
    GST_INFO ("initialized GStreamer successfully");
  } else {
    GST_INFO ("failed to initialize GStreamer");
449
450
451
  }

  return res;
452
453
}

Erik Walthinsen's avatar
Erik Walthinsen committed
454
455
456
457
458
/**
 * gst_init:
 * @argc: pointer to application's argc
 * @argv: pointer to application's argv
 *
459
460
 * Initializes the GStreamer library, setting up internal path lists,
 * registering built-in elements, and loading standard plugins.
461
 *
462
463
464
465
 * This function should be called before calling any other GLib functions. If
 * this is not an option, your program must initialise the GLib thread system
 * using g_thread_init() before any other GLib functions are called.
 *
466
 * <note><para>
467
468
469
 * This function will terminate your program if it was unable to initialize
 * GStreamer for some reason.  If you want your program to fall back,
 * use gst_init_check() instead.
470
 * </para></note>
471
472
473
474
475
 *
 * WARNING: This function does not work in the same way as corresponding
 * functions in other glib-style libraries, such as gtk_init().  In
 * particular, unknown command line options cause this function to
 * abort program execution.
Erik Walthinsen's avatar
Erik Walthinsen committed
476
 */
477
void
Benjamin Otte's avatar
Benjamin Otte committed
478
479
gst_init (int *argc, char **argv[])
{
480
  GError *err = NULL;
481

482
  if (!gst_init_check (argc, argv, &err)) {
483
    g_print ("Could not initialize GStreamer: %s\n",
484
485
486
        err ? err->message : "unknown error occurred");
    if (err) {
      g_error_free (err);
487
    }
488
    exit (1);
489
490
491
  }
}

Wim Taymans's avatar
Wim Taymans committed
492
#ifndef GST_DISABLE_REGISTRY
493
static void
494
495
add_path_func (gpointer data, gpointer user_data)
{
496
497
  GST_INFO ("Adding plugin path: \"%s\", will scan later", (gchar *) data);
  plugin_paths = g_list_append (plugin_paths, g_strdup (data));
498
}
Wim Taymans's avatar
Wim Taymans committed
499
#endif
500

501
#ifndef GST_DISABLE_OPTION_PARSING
502
static void
503
504
prepare_for_load_plugin_func (gpointer data, gpointer user_data)
{
505
  preload_plugins = g_slist_prepend (preload_plugins, g_strdup (data));
506
}
507
#endif
508

509
static void
510
511
load_plugin_func (gpointer data, gpointer user_data)
{
Wim Taymans's avatar
Wim Taymans committed
512
513
  GstPlugin *plugin;
  const gchar *filename;
514
  GError *err = NULL;
Wim Taymans's avatar
Wim Taymans committed
515
516

  filename = (const gchar *) data;
517

518
  plugin = gst_plugin_load_file (filename, &err);
Wim Taymans's avatar
Wim Taymans committed
519

520
  if (plugin) {
521
    GST_INFO ("Loaded plugin: \"%s\"", filename);
Wim Taymans's avatar
Wim Taymans committed
522

David Schleef's avatar
remove    
David Schleef committed
523
    gst_default_registry_add_plugin (plugin);
524
  } else {
525
526
    if (err) {
      /* Report error to user, and free error */
527
      GST_ERROR ("Failed to load plugin: %s", err->message);
528
529
530
531
      g_error_free (err);
    } else {
      GST_WARNING ("Failed to load plugin: \"%s\"", filename);
    }
Wim Taymans's avatar
Wim Taymans committed
532
  }
533
534
}

535
#ifndef GST_DISABLE_OPTION_PARSING
536
static void
537
538
split_and_iterate (const gchar * stringlist, gchar * separator, GFunc iterator,
    gpointer user_data)
539
540
541
542
{
  gchar **strings;
  gint j = 0;
  gchar *lastlist = g_strdup (stringlist);
Erik Walthinsen's avatar
Erik Walthinsen committed
543

544
545
546
547
  while (lastlist) {
    strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT);
    g_free (lastlist);
    lastlist = NULL;
548

549
    while (strings[j]) {
550
      iterator (strings[j], user_data);
551
      if (++j == MAX_PATH_SPLIT) {
552
553
554
        lastlist = g_strdup (strings[j]);
        j = 0;
        break;
555
556
      }
    }
557
    g_strfreev (strings);
Wim Taymans's avatar
Wim Taymans committed
558
  }
559
}
560
#endif
Wim Taymans's avatar
Wim Taymans committed
561

562
563
/* we have no fail cases yet, but maybe in the future */
static gboolean
564
565
init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
    GError ** error)
566
{
567
568
569
570
571
  if (gst_initialized) {
    GST_DEBUG ("already initialized");
    return TRUE;
  }

572
573
574
575
576
577
578
579
580
581
  /* GStreamer was built against a GLib >= 2.8 and is therefore not doing
   * the refcount hack. Check that it isn't being run against an older GLib */
  if (glib_major_version < 2 ||
      (glib_major_version == 2 && glib_minor_version < 8)) {
    g_warning ("GStreamer was compiled against GLib %d.%d.%d but is running"
        " against %d.%d.%d. This will cause reference counting issues",
        GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION,
        glib_major_version, glib_minor_version, glib_micro_version);
  }

582
  g_type_init ();
583

584
  /* we need threading to be enabled right here */
585
  g_assert (g_thread_supported ());
586
  _gst_debug_init ();
587
588

#ifdef ENABLE_NLS
589
590
  setlocale (LC_ALL, "");
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
591
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
592
#endif /* ENABLE_NLS */
593

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
594
#ifndef GST_DISABLE_GST_DEBUG
595
596
  {
    const gchar *debug_list;
597

598
599
600
    if (g_getenv ("GST_DEBUG_NO_COLOR") != NULL)
      gst_debug_set_colored (FALSE);

601
602
603
604
605
    debug_list = g_getenv ("GST_DEBUG");
    if (debug_list) {
      parse_debug_list (debug_list);
    }
  }
606
607

  priv_gst_dump_dot_dir = g_getenv ("GST_DEBUG_DUMP_DOT_DIR");
608
#endif
609
610
611
  /* This is the earliest we can make stuff show up in the logs.
   * So give some useful info about GStreamer here */
  GST_INFO ("Initializing GStreamer Core Library version %s", VERSION);
612
  GST_INFO ("Using library installed in %s", LIBDIR);
613

614
615
616
617
618
619
620
621
622
623
624
625
626
  /* Print some basic system details if possible (OS/architecture) */
#ifdef HAVE_SYS_UTSNAME_H
  {
    struct utsname sys_details;

    if (uname (&sys_details) == 0) {
      GST_INFO ("%s %s %s %s %s", sys_details.sysname,
          sys_details.nodename, sys_details.release, sys_details.version,
          sys_details.machine);
    }
  }
#endif

627
  return TRUE;
628
629
630
}

static gboolean
631
gst_register_core_elements (GstPlugin * plugin)
632
633
{
  /* register some standard builtin types */
634
635
636
  if (!gst_element_register (plugin, "bin", GST_RANK_PRIMARY,
          GST_TYPE_BIN) ||
      !gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
637
          GST_TYPE_PIPELINE)
Wim Taymans's avatar
Wim Taymans committed
638
      )
639
    g_assert_not_reached ();
640
641

  return TRUE;
642
643
}

644
645
#ifndef GST_DISABLE_REGISTRY

646
647
648
649
650
651
652
typedef enum
{
  REGISTRY_SCAN_AND_UPDATE_FAILURE = 0,
  REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED,
  REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED
} GstRegistryScanAndUpdateResult;

653
654
655
656
657
658
/*
 * scan_and_update_registry:
 * @default_registry: the #GstRegistry
 * @registry_file: registry filename
 * @write_changes: write registry if it has changed?
 *
659
 * Scans for registry changes and eventually updates the registry cache. 
660
 *
661
662
663
664
 * Return: %REGISTRY_SCAN_AND_UPDATE_FAILURE if the registry could not scanned
 *         or updated, %REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED if the
 *         registry is clean and %REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED if
 *         it has been updated and the cache needs to be re-read.
665
 */
666
static GstRegistryScanAndUpdateResult
667
scan_and_update_registry (GstRegistry * default_registry,
668
    const gchar * registry_file, gboolean write_changes, GError ** error)
669
670
671
672
673
{
  const gchar *plugin_path;
  gboolean changed = FALSE;
  GList *l;

674
675
676
677
678
  GST_INFO ("Validating registry cache: %s", registry_file);
  /* It sounds tempting to just compare the mtime of directories with the mtime
   * of the registry cache, but it does not work. It would not catch updated
   * plugins, which might bring more or less features.
   */
679

680
681
682
683
  /* scan paths specified via --gst-plugin-path */
  GST_DEBUG ("scanning paths added via --gst-plugin-path");
  for (l = plugin_paths; l != NULL; l = l->next) {
    GST_INFO ("Scanning plugin path: \"%s\"", (gchar *) l->data);
684
    changed |= gst_registry_scan_path (default_registry, (gchar *) l->data);
685
  }
686
  /* keep plugin_paths around in case a re-scan is forced later on */
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717

  /* GST_PLUGIN_PATH specifies a list of directories to scan for
   * additional plugins.  These take precedence over the system plugins */
  plugin_path = g_getenv ("GST_PLUGIN_PATH");
  if (plugin_path) {
    char **list;
    int i;

    GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
    list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
    for (i = 0; list[i]; i++) {
      changed |= gst_registry_scan_path (default_registry, list[i]);
    }
    g_strfreev (list);
  } else {
    GST_DEBUG ("GST_PLUGIN_PATH not set");
  }

  /* GST_PLUGIN_SYSTEM_PATH specifies a list of plugins that are always
   * loaded by default.  If not set, this defaults to the system-installed
   * path, and the plugins installed in the user's home directory */
  plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
  if (plugin_path == NULL) {
    char *home_plugins;

    GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set");

    /* plugins in the user's home directory take precedence over
     * system-installed ones */
    home_plugins = g_build_filename (g_get_home_dir (),
        ".gstreamer-" GST_MAJORMINOR, "plugins", NULL);
718
    GST_DEBUG ("scanning home plugins %s", home_plugins);
719
720
721
722
    changed |= gst_registry_scan_path (default_registry, home_plugins);
    g_free (home_plugins);

    /* add the main (installed) library path */
723
    GST_DEBUG ("scanning main plugins %s", PLUGINDIR);
724
    changed |= gst_registry_scan_path (default_registry, PLUGINDIR);
725

726
#ifdef G_OS_WIN32
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
    {
      char *base_dir;
      char *dir;

      base_dir = g_win32_get_package_installation_directory (NULL,
          "libgstreamer-0.10-0.dll");

      dir = g_build_filename (base_dir, "lib", "gstreamer-0.10", NULL);
      GST_DEBUG ("scanning DLL dir %s", dir);

      changed |= gst_registry_scan_path (default_registry, dir);

      g_free (dir);
      g_free (base_dir);
    }
#endif
743
744
745
746
747
748
749
750
751
752
753
754
  } else {
    gchar **list;
    gint i;

    GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path);
    list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
    for (i = 0; list[i]; i++) {
      changed |= gst_registry_scan_path (default_registry, list[i]);
    }
    g_strfreev (list);
  }

755
756
757
  /* Remove cached plugins so stale info is cleared. */
  changed |= _priv_gst_registry_remove_cache_plugins (default_registry);

758
  if (!changed) {
759
    GST_INFO ("Registry cache has not changed");
760
    return REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED;
761
762
763
  }

  if (!write_changes) {
764
    GST_INFO ("Registry cache changed, but writing is disabled. Not writing.");
765
    return REGISTRY_SCAN_AND_UPDATE_FAILURE;
766
767
  }

768
  GST_INFO ("Registry cache changed. Writing new registry cache");
769
770
771
#ifdef USE_BINARY_REGISTRY
  if (!gst_registry_binary_write_cache (default_registry, registry_file)) {
#else
772
  if (!gst_registry_xml_write_cache (default_registry, registry_file)) {
773
#endif
774
775
776
    g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
        _("Error writing registry cache to %s: %s"),
        registry_file, g_strerror (errno));
777
    return REGISTRY_SCAN_AND_UPDATE_FAILURE;
778
779
  }

780
  GST_INFO ("Registry cache written successfully");
781
  return REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED;
782
783
}

784
785
static gboolean
ensure_current_registry_nonforking (GstRegistry * default_registry,
786
    const gchar * registry_file, GError ** error)
787
788
{
  /* fork() not available */
789
790
  GST_DEBUG ("Updating registry cache in-process");
  scan_and_update_registry (default_registry, registry_file, TRUE, error);
791
792
793
  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
794
795
/* when forking is not available this function always does nothing but return
 * TRUE immediatly */
796
797
static gboolean
ensure_current_registry_forking (GstRegistry * default_registry,
798
    const gchar * registry_file, GError ** error)
799
{
Wim Taymans's avatar
Wim Taymans committed
800
#ifdef HAVE_FORK
801
  pid_t pid;
802
  int pfd[2];
803
  int ret;
804
805
806

  /* We fork here, and let the child read and possibly rebuild the registry.
   * After that, the parent will re-read the freshly generated registry. */
807
  GST_DEBUG ("forking to update registry");
808
809
810
811
812
813
814
815

  if (pipe (pfd) == -1) {
    g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
        _("Error re-scanning registry %s: %s"),
        ", could not create pipes. Error", g_strerror (errno));
    return FALSE;
  }

816
817
818
  pid = fork ();
  if (pid == -1) {
    GST_ERROR ("Failed to fork()");
819
820
821
    g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
        _("Error re-scanning registry %s: %s"),
        ", failed to fork. Error", g_strerror (errno));
822
823
824
825
    return FALSE;
  }

  if (pid == 0) {
826
    gint result_code;
827
828

    /* this is the child. Close the read pipe */
829
    (void) close (pfd[0]);
830
831

    GST_DEBUG ("child reading registry cache");
832
    result_code =
833
        scan_and_update_registry (default_registry, registry_file, TRUE, NULL);
834
835
836

    /* need to use _exit, so that any exit handlers registered don't
     * bring down the main program */
837
    GST_DEBUG ("child exiting: %d", result_code);
838
839
840
841

    /* make valgrind happy (yes, you can call it insane) */
    g_free ((char *) registry_file);

842
    /* write a result byte to the pipe */
843
    do {
844
      ret = write (pfd[1], &result_code, sizeof (result_code));
845
846
847
848
849
    } while (ret == -1 && errno == EINTR);
    /* if ret == -1 now, we could not write to pipe, probably 
     * means parent has exited before us */
    (void) close (pfd[1]);

850
    _exit (0);
851
  } else {
852
    gint result_code;
853

854
    /* parent. Close write pipe */
855
    (void) close (pfd[1]);
856
857
858

    /* Wait for result from the pipe */
    GST_DEBUG ("Waiting for data from child");
859
    do {
860
      ret = read (pfd[0], &result_code, sizeof (result_code));
861
862
    } while (ret == -1 && errno == EINTR);

863
    if (ret == -1) {
864
865
      g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
          _("Error re-scanning registry %s: %s"),
866
867
          ", read returned error", g_strerror (errno));
      close (pfd[0]);
868
869
      return FALSE;
    }
870
    (void) close (pfd[0]);
871

872
873
874
875
876
877
878
879
880
    /* Wait to ensure the child is reaped, but ignore the result */
    GST_DEBUG ("parent waiting on child");
    waitpid (pid, NULL, 0);
    GST_DEBUG ("parent done waiting on child");

    if (ret == 0) {
      GST_ERROR ("child did not exit normally, terminated by signal");
      g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
          _("Error re-scanning registry %s"), ", child terminated by signal");
881
882
883
      return FALSE;
    }

884
    if (result_code == REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED) {
885
      GST_DEBUG ("Child succeeded. Parent reading registry cache");
886
      _priv_gst_registry_remove_cache_plugins (default_registry);
887
888
889
#ifdef USE_BINARY_REGISTRY
      gst_registry_binary_read_cache (default_registry, registry_file);
#else
890
      gst_registry_xml_read_cache (default_registry, registry_file);
891
#endif
892
    } else if (result_code == REGISTRY_SCAN_AND_UPDATE_FAILURE) {
893
      GST_DEBUG ("Child failed. Parent re-scanning registry, ignoring errors.");
894
      scan_and_update_registry (default_registry, registry_file, FALSE, NULL);
895
896
    }
  }
Wim Taymans's avatar
Wim Taymans committed
897
#endif /* HAVE_FORK */
898
899
900
901
  return TRUE;
}

static gboolean
902
ensure_current_registry (GError ** error)
903
{
904
  gchar *registry_file;
905
  GstRegistry *default_registry;
906
  gboolean ret = TRUE;
Wim Taymans's avatar
Wim Taymans committed
907
  gboolean do_fork;
908
  gboolean do_update;
909
  gboolean have_cache;
910
911
912
913

  default_registry = gst_registry_get_default ();
  registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
  if (registry_file == NULL) {
914
915
916
917
#ifdef USE_BINARY_REGISTRY
    registry_file = g_build_filename (g_get_home_dir (),
        ".gstreamer-" GST_MAJORMINOR, "registry." HOST_CPU ".bin", NULL);
#else
918
919
    registry_file = g_build_filename (g_get_home_dir (),
        ".gstreamer-" GST_MAJORMINOR, "registry." HOST_CPU ".xml", NULL);
920
#endif
921
  }
Wim Taymans's avatar
Wim Taymans committed
922

923
924
  GST_INFO ("reading registry cache: %s", registry_file);
#ifdef USE_BINARY_REGISTRY
925
  have_cache = gst_registry_binary_read_cache (default_registry, registry_file);
926
#else
927
  have_cache = gst_registry_xml_read_cache (default_registry, registry_file);
928
929
#endif

930
931
932
933
  if (have_cache) {
    do_update = !_gst_disable_registry_update;
    if (do_update) {
      const gchar *update_env;
Wim Taymans's avatar
Wim Taymans committed
934

935
936
937
938
      if ((update_env = g_getenv ("GST_REGISTRY_UPDATE"))) {
        /* do update for any value different from "no" */
        do_update = (strcmp (update_env, "no") != 0);
      }
Wim Taymans's avatar
Wim Taymans committed
939
    }
940
941
  } else {
    do_update = TRUE;
Wim Taymans's avatar
Wim Taymans committed
942
943
  }

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  if (do_update) {
    /* first see if forking is enabled */
    do_fork = _gst_enable_registry_fork;
    if (do_fork) {
      const gchar *fork_env;

      /* forking enabled, see if it is disabled with an env var */
      if ((fork_env = g_getenv ("GST_REGISTRY_FORK"))) {
        /* fork enabled for any value different from "no" */
        do_fork = strcmp (fork_env, "no") != 0;
      }
    }

    /* now check registry with or without forking */
    if (do_fork) {
      GST_DEBUG ("forking for registry rebuild");
      ret = ensure_current_registry_forking (default_registry, registry_file,
          error);
    } else {
      GST_DEBUG ("requested not to fork for registry rebuild");
      ret = ensure_current_registry_nonforking (default_registry, registry_file,
          error);
    }
967
968
969
  }

  g_free (registry_file);
970
  GST_INFO ("registry reading and updating done, result = %d", ret);
971
972
973

  return ret;
}
974
975
#endif /* GST_DISABLE_REGISTRY */

976
977
978
979
980
981
982
/*
 * this bit handles:
 * - initalization of threads if we use them
 * - log handler
 * - initial output
 * - initializes gst_format
 * - registers a bunch of types for gst_objects
983
984
985
 *
 * - we don't have cases yet where this fails, but in the future
 *   we might and then it's nice to be able to return that
986
 */
987
static gboolean
988
989
init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
    GError ** error)
990
991
{
  GLogLevelFlags llf;
992

993
994
#ifndef GST_DISABLE_TRACE
  GstTrace *gst_trace;
Wim Taymans's avatar
Wim Taymans committed
995
#endif /* GST_DISABLE_TRACE */
996

997
998
999
1000
1001
  if (gst_initialized) {
    GST_DEBUG ("already initialized");
    return TRUE;
  }

1002
  llf = G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL;
1003
  g_log_set_handler (g_log_domain_gstreamer, llf, debug_log_handler, NULL);
1004

1005
  _priv_gst_quarks_initialize ();
1006
  _gst_format_initialize ();
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1007
  _gst_query_initialize ();
1008
1009
1010
1011
1012
1013
  g_type_class_ref (gst_object_get_type ());
  g_type_class_ref (gst_pad_get_type ());
  g_type_class_ref