info: add a function to set debug threshold from a GST_DEBUG-style string
[platform/upstream/gstreamer.git] / gst / gstinfo.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
5  * Copyright (C) 2008-2009 Tim-Philipp Müller <tim centricular net>
6  *
7  * gstinfo.c: debugging functions
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:gstinfo
27  * @short_description: Debugging and logging facilities
28  * @see_also: #gstreamer-gstconfig, #gstreamer-Gst for command line parameters
29  * and environment variables that affect the debugging output.
30  *
31  * GStreamer's debugging subsystem is an easy way to get information about what
32  * the application is doing.  It is not meant for programming errors. Use GLib
33  * methods (g_warning and friends) for that.
34  *
35  * The debugging subsystem works only after GStreamer has been initialized
36  * - for example by calling gst_init().
37  *
38  * The debugging subsystem is used to log informational messages while the
39  * application runs.  Each messages has some properties attached to it. Among
40  * these properties are the debugging category, the severity (called "level"
41  * here) and an optional #GObject it belongs to. Each of these messages is sent
42  * to all registered debugging handlers, which then handle the messages.
43  * GStreamer attaches a default handler on startup, which outputs requested
44  * messages to stderr.
45  *
46  * Messages are output by using shortcut macros like #GST_DEBUG,
47  * #GST_CAT_ERROR_OBJECT or similar. These all expand to calling gst_debug_log()
48  * with the right parameters.
49  * The only thing a developer will probably want to do is define his own
50  * categories. This is easily done with 3 lines. At the top of your code,
51  * declare
52  * the variables and set the default category.
53  * <informalexample>
54  * <programlisting>
55  * GST_DEBUG_CATEGORY_STATIC (my_category);     // define category (statically)
56  * &hash;define GST_CAT_DEFAULT my_category     // set as default
57  * </programlisting>
58  * </informalexample>
59  * After that you only need to initialize the category.
60  * <informalexample>
61  * <programlisting>
62  * GST_DEBUG_CATEGORY_INIT (my_category, "my category",
63  *                          0, "This is my very own");
64  * </programlisting>
65  * </informalexample>
66  * Initialization must be done before the category is used first.
67  * Plugins do this
68  * in their plugin_init function, libraries and applications should do that
69  * during their initialization.
70  *
71  * The whole debugging subsystem can be disabled at build time with passing the
72  * --disable-gst-debug switch to configure. If this is done, every function,
73  * macro and even structs described in this file evaluate to default values or
74  * nothing at all.
75  * So don't take addresses of these functions or use other tricks.
76  * If you must do that for some reason, there is still an option.
77  * If the debugging
78  * subsystem was compiled out, #GST_DISABLE_GST_DEBUG is defined in
79  * &lt;gst/gst.h&gt;,
80  * so you can check that before doing your trick.
81  * Disabling the debugging subsystem will give you a slight (read: unnoticeable)
82  * speed increase and will reduce the size of your compiled code. The GStreamer
83  * library itself becomes around 10% smaller.
84  *
85  * Please note that there are naming conventions for the names of debugging
86  * categories. These are explained at GST_DEBUG_CATEGORY_INIT().
87  */
88
89 #define GST_INFO_C
90 #include "gst_private.h"
91 #include "gstinfo.h"
92
93 #undef gst_debug_remove_log_function
94 #undef gst_debug_add_log_function
95
96 #ifndef GST_DISABLE_GST_DEBUG
97
98 #ifdef HAVE_DLFCN_H
99 #  include <dlfcn.h>
100 #endif
101 #ifdef HAVE_PRINTF_EXTENSION
102 #  include <printf.h>
103 #endif
104 #include <stdio.h>              /* fprintf */
105 #include <glib/gstdio.h>
106 #include <errno.h>
107 #ifdef HAVE_UNISTD_H
108 #  include <unistd.h>           /* getpid on UNIX */
109 #endif
110 #ifdef HAVE_PROCESS_H
111 #  include <process.h>          /* getpid on win32 */
112 #endif
113 #include <string.h>             /* G_VA_COPY */
114 #ifdef G_OS_WIN32
115 #  define WIN32_LEAN_AND_MEAN   /* prevents from including too many things */
116 #  include <windows.h>          /* GetStdHandle, windows console */
117 #endif
118
119 #include "gst_private.h"
120 #include "gstutils.h"
121 #include "gstquark.h"
122 #include "gstsegment.h"
123 #include "gstvalue.h"
124
125 #ifdef HAVE_VALGRIND_VALGRIND_H
126 #  include <valgrind/valgrind.h>
127 #endif
128 #include <glib/gprintf.h>       /* g_sprintf */
129
130 #endif /* !GST_DISABLE_GST_DEBUG */
131
132 extern gboolean gst_is_initialized (void);
133
134 /* we want these symbols exported even if debug is disabled, to maintain
135  * ABI compatibility. Unless GST_REMOVE_DISABLED is defined. */
136 #if !defined(GST_DISABLE_GST_DEBUG) || !defined(GST_REMOVE_DISABLED)
137
138 /* disabled by default, as soon as some threshold is set > NONE,
139  * it becomes enabled. */
140 gboolean _gst_debug_enabled = FALSE;
141 GstDebugLevel _gst_debug_min = GST_LEVEL_NONE;
142
143 GstDebugCategory *GST_CAT_DEFAULT = NULL;
144
145 GstDebugCategory *GST_CAT_GST_INIT = NULL;
146 GstDebugCategory *GST_CAT_MEMORY = NULL;
147 GstDebugCategory *GST_CAT_PARENTAGE = NULL;
148 GstDebugCategory *GST_CAT_STATES = NULL;
149 GstDebugCategory *GST_CAT_SCHEDULING = NULL;
150
151 GstDebugCategory *GST_CAT_BUFFER = NULL;
152 GstDebugCategory *GST_CAT_BUFFER_LIST = NULL;
153 GstDebugCategory *GST_CAT_BUS = NULL;
154 GstDebugCategory *GST_CAT_CAPS = NULL;
155 GstDebugCategory *GST_CAT_CLOCK = NULL;
156 GstDebugCategory *GST_CAT_ELEMENT_PADS = NULL;
157 GstDebugCategory *GST_CAT_PADS = NULL;
158 GstDebugCategory *GST_CAT_PERFORMANCE = NULL;
159 GstDebugCategory *GST_CAT_PIPELINE = NULL;
160 GstDebugCategory *GST_CAT_PLUGIN_LOADING = NULL;
161 GstDebugCategory *GST_CAT_PLUGIN_INFO = NULL;
162 GstDebugCategory *GST_CAT_PROPERTIES = NULL;
163 GstDebugCategory *GST_CAT_NEGOTIATION = NULL;
164 GstDebugCategory *GST_CAT_REFCOUNTING = NULL;
165 GstDebugCategory *GST_CAT_ERROR_SYSTEM = NULL;
166 GstDebugCategory *GST_CAT_EVENT = NULL;
167 GstDebugCategory *GST_CAT_MESSAGE = NULL;
168 GstDebugCategory *GST_CAT_PARAMS = NULL;
169 GstDebugCategory *GST_CAT_CALL_TRACE = NULL;
170 GstDebugCategory *GST_CAT_SIGNAL = NULL;
171 GstDebugCategory *GST_CAT_PROBE = NULL;
172 GstDebugCategory *GST_CAT_REGISTRY = NULL;
173 GstDebugCategory *GST_CAT_QOS = NULL;
174 GstDebugCategory *_priv_GST_CAT_POLL = NULL;
175 GstDebugCategory *GST_CAT_META = NULL;
176 GstDebugCategory *GST_CAT_LOCKING = NULL;
177
178
179 #endif /* !defined(GST_DISABLE_GST_DEBUG) || !defined(GST_REMOVE_DISABLED) */
180
181 #ifndef GST_DISABLE_GST_DEBUG
182
183 /* underscore is to prevent conflict with GST_CAT_DEBUG define */
184 GST_DEBUG_CATEGORY_STATIC (_GST_CAT_DEBUG);
185
186 /* time of initialization, so we get useful debugging output times
187  * FIXME: we use this in gstdebugutils.c, what about a function + macro to
188  * get the running time: GST_DEBUG_RUNNING_TIME
189  */
190 GstClockTime _priv_gst_info_start_time;
191
192 #if 0
193 #if defined __sgi__
194 #include <rld_interface.h>
195 typedef struct DL_INFO
196 {
197   const char *dli_fname;
198   void *dli_fbase;
199   const char *dli_sname;
200   void *dli_saddr;
201   int dli_version;
202   int dli_reserved1;
203   long dli_reserved[4];
204 }
205 Dl_info;
206
207 #define _RLD_DLADDR             14
208 int dladdr (void *address, Dl_info * dl);
209
210 int
211 dladdr (void *address, Dl_info * dl)
212 {
213   void *v;
214
215   v = _rld_new_interface (_RLD_DLADDR, address, dl);
216   return (int) v;
217 }
218 #endif /* __sgi__ */
219 #endif
220
221 static void gst_debug_reset_threshold (gpointer category, gpointer unused);
222 static void gst_debug_reset_all_thresholds (void);
223
224 #ifdef GST_USING_PRINTF_EXTENSION
225 static int _gst_info_printf_extension_ptr (FILE * stream,
226     const struct printf_info *info, const void *const *args);
227 static int _gst_info_printf_extension_segment (FILE * stream,
228     const struct printf_info *info, const void *const *args);
229 #ifdef HAVE_REGISTER_PRINTF_SPECIFIER
230 static int _gst_info_printf_extension_arginfo (const struct printf_info *info,
231     size_t n, int *argtypes, int *size);
232 #else
233 static int _gst_info_printf_extension_arginfo (const struct printf_info *info,
234     size_t n, int *argtypes);
235 #endif
236 #endif
237
238 struct _GstDebugMessage
239 {
240   gchar *message;
241   const gchar *format;
242   va_list arguments;
243 };
244
245 /* list of all name/level pairs from --gst-debug and GST_DEBUG */
246 static GMutex __level_name_mutex;
247 static GSList *__level_name = NULL;
248 typedef struct
249 {
250   GPatternSpec *pat;
251   GstDebugLevel level;
252 }
253 LevelNameEntry;
254
255 /* list of all categories */
256 static GMutex __cat_mutex;
257 static GSList *__categories = NULL;
258
259 /* all registered debug handlers */
260 typedef struct
261 {
262   GstLogFunction func;
263   gpointer user_data;
264   GDestroyNotify notify;
265 }
266 LogFuncEntry;
267 static GMutex __log_func_mutex;
268 static GSList *__log_functions = NULL;
269
270 #define PRETTY_TAGS_DEFAULT  TRUE
271 static gboolean pretty_tags = PRETTY_TAGS_DEFAULT;
272
273 static volatile gint G_GNUC_MAY_ALIAS __default_level = GST_LEVEL_DEFAULT;
274 static volatile gint G_GNUC_MAY_ALIAS __use_color = 1;
275
276 static FILE *log_file;
277
278 /* FIXME: export this? */
279 gboolean
280 _priv_gst_in_valgrind (void)
281 {
282   static enum
283   {
284     GST_VG_UNCHECKED,
285     GST_VG_NO_VALGRIND,
286     GST_VG_INSIDE
287   }
288   in_valgrind = GST_VG_UNCHECKED;
289
290   if (in_valgrind == GST_VG_UNCHECKED) {
291 #ifdef HAVE_VALGRIND_VALGRIND_H
292     if (RUNNING_ON_VALGRIND) {
293       GST_CAT_INFO (GST_CAT_GST_INIT, "we're running inside valgrind");
294       printf ("GStreamer has detected that it is running inside valgrind.\n");
295       printf ("It might now take different code paths to ease debugging.\n");
296       printf ("Of course, this may also lead to different bugs.\n");
297       in_valgrind = GST_VG_INSIDE;
298     } else {
299       GST_CAT_LOG (GST_CAT_GST_INIT, "not doing extra valgrind stuff");
300       in_valgrind = GST_VG_NO_VALGRIND;
301     }
302 #else
303     in_valgrind = GST_VG_NO_VALGRIND;
304 #endif
305     g_assert (in_valgrind == GST_VG_NO_VALGRIND ||
306         in_valgrind == GST_VG_INSIDE);
307   }
308   return (in_valgrind == GST_VG_INSIDE);
309 }
310
311 /* Initialize the debugging system */
312 void
313 _priv_gst_debug_init (void)
314 {
315   const gchar *env;
316
317   env = g_getenv ("GST_DEBUG_FILE");
318   if (env != NULL && *env != '\0') {
319     if (strcmp (env, "-") == 0) {
320       log_file = stdout;
321     } else {
322       log_file = g_fopen (env, "w");
323       if (log_file == NULL) {
324         g_printerr ("Could not open log file '%s' for writing: %s\n", env,
325             g_strerror (errno));
326         log_file = stderr;
327       }
328     }
329   } else {
330     log_file = stderr;
331   }
332
333   /* get time we started for debugging messages */
334   _priv_gst_info_start_time = gst_util_get_timestamp ();
335
336 #ifdef GST_USING_PRINTF_EXTENSION
337 #ifdef HAVE_REGISTER_PRINTF_SPECIFIER
338   register_printf_specifier (GST_PTR_FORMAT[0], _gst_info_printf_extension_ptr,
339       _gst_info_printf_extension_arginfo);
340   register_printf_specifier (GST_SEGMENT_FORMAT[0],
341       _gst_info_printf_extension_segment, _gst_info_printf_extension_arginfo);
342 #else
343   register_printf_function (GST_PTR_FORMAT[0], _gst_info_printf_extension_ptr,
344       _gst_info_printf_extension_arginfo);
345   register_printf_function (GST_SEGMENT_FORMAT[0],
346       _gst_info_printf_extension_segment, _gst_info_printf_extension_arginfo);
347 #endif
348 #endif
349
350   /* do NOT use a single debug function before this line has been run */
351   GST_CAT_DEFAULT = _gst_debug_category_new ("default",
352       GST_DEBUG_UNDERLINE, NULL);
353   _GST_CAT_DEBUG = _gst_debug_category_new ("GST_DEBUG",
354       GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW, "debugging subsystem");
355
356   gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
357
358   /* FIXME: add descriptions here */
359   GST_CAT_GST_INIT = _gst_debug_category_new ("GST_INIT",
360       GST_DEBUG_BOLD | GST_DEBUG_FG_RED, NULL);
361   GST_CAT_MEMORY = _gst_debug_category_new ("GST_MEMORY",
362       GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, "memory");
363   GST_CAT_PARENTAGE = _gst_debug_category_new ("GST_PARENTAGE",
364       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
365   GST_CAT_STATES = _gst_debug_category_new ("GST_STATES",
366       GST_DEBUG_BOLD | GST_DEBUG_FG_RED, NULL);
367   GST_CAT_SCHEDULING = _gst_debug_category_new ("GST_SCHEDULING",
368       GST_DEBUG_BOLD | GST_DEBUG_FG_MAGENTA, NULL);
369   GST_CAT_BUFFER = _gst_debug_category_new ("GST_BUFFER",
370       GST_DEBUG_BOLD | GST_DEBUG_BG_GREEN, NULL);
371   GST_CAT_BUFFER_LIST = _gst_debug_category_new ("GST_BUFFER_LIST",
372       GST_DEBUG_BOLD | GST_DEBUG_BG_GREEN, NULL);
373   GST_CAT_BUS = _gst_debug_category_new ("GST_BUS", GST_DEBUG_BG_YELLOW, NULL);
374   GST_CAT_CAPS = _gst_debug_category_new ("GST_CAPS",
375       GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL);
376   GST_CAT_CLOCK = _gst_debug_category_new ("GST_CLOCK",
377       GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW, NULL);
378   GST_CAT_ELEMENT_PADS = _gst_debug_category_new ("GST_ELEMENT_PADS",
379       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
380   GST_CAT_PADS = _gst_debug_category_new ("GST_PADS",
381       GST_DEBUG_BOLD | GST_DEBUG_FG_RED | GST_DEBUG_BG_RED, NULL);
382   GST_CAT_PERFORMANCE = _gst_debug_category_new ("GST_PERFORMANCE",
383       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
384   GST_CAT_PIPELINE = _gst_debug_category_new ("GST_PIPELINE",
385       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
386   GST_CAT_PLUGIN_LOADING = _gst_debug_category_new ("GST_PLUGIN_LOADING",
387       GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN, NULL);
388   GST_CAT_PLUGIN_INFO = _gst_debug_category_new ("GST_PLUGIN_INFO",
389       GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN, NULL);
390   GST_CAT_PROPERTIES = _gst_debug_category_new ("GST_PROPERTIES",
391       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_BLUE, NULL);
392   GST_CAT_NEGOTIATION = _gst_debug_category_new ("GST_NEGOTIATION",
393       GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL);
394   GST_CAT_REFCOUNTING = _gst_debug_category_new ("GST_REFCOUNTING",
395       GST_DEBUG_BOLD | GST_DEBUG_FG_RED | GST_DEBUG_BG_BLUE, NULL);
396   GST_CAT_ERROR_SYSTEM = _gst_debug_category_new ("GST_ERROR_SYSTEM",
397       GST_DEBUG_BOLD | GST_DEBUG_FG_RED | GST_DEBUG_BG_WHITE, NULL);
398
399   GST_CAT_EVENT = _gst_debug_category_new ("GST_EVENT",
400       GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL);
401   GST_CAT_MESSAGE = _gst_debug_category_new ("GST_MESSAGE",
402       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
403   GST_CAT_PARAMS = _gst_debug_category_new ("GST_PARAMS",
404       GST_DEBUG_BOLD | GST_DEBUG_FG_BLACK | GST_DEBUG_BG_YELLOW, NULL);
405   GST_CAT_CALL_TRACE = _gst_debug_category_new ("GST_CALL_TRACE",
406       GST_DEBUG_BOLD, NULL);
407   GST_CAT_SIGNAL = _gst_debug_category_new ("GST_SIGNAL",
408       GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
409   GST_CAT_PROBE = _gst_debug_category_new ("GST_PROBE",
410       GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, "pad probes");
411   GST_CAT_REGISTRY = _gst_debug_category_new ("GST_REGISTRY", 0, "registry");
412   GST_CAT_QOS = _gst_debug_category_new ("GST_QOS", 0, "QoS");
413   _priv_GST_CAT_POLL = _gst_debug_category_new ("GST_POLL", 0, "poll");
414   GST_CAT_META = _gst_debug_category_new ("GST_META", 0, "meta");
415   GST_CAT_LOCKING = _gst_debug_category_new ("GST_LOCKING", 0, "locking");
416
417
418   /* print out the valgrind message if we're in valgrind */
419   _priv_gst_in_valgrind ();
420
421   env = g_getenv ("GST_DEBUG_OPTIONS");
422   if (env != NULL) {
423     if (strstr (env, "full_tags") || strstr (env, "full-tags"))
424       pretty_tags = FALSE;
425     else if (strstr (env, "pretty_tags") || strstr (env, "pretty-tags"))
426       pretty_tags = TRUE;
427   }
428 }
429
430 /* we can't do this further above, because we initialize the GST_CAT_DEFAULT struct */
431 #define GST_CAT_DEFAULT _GST_CAT_DEBUG
432
433 /**
434  * gst_debug_log:
435  * @category: category to log
436  * @level: level of the message is in
437  * @file: the file that emitted the message, usually the __FILE__ identifier
438  * @function: the function that emitted the message
439  * @line: the line from that the message was emitted, usually __LINE__
440  * @object: (transfer none) (allow-none): the object this message relates to,
441  *     or NULL if none
442  * @format: a printf style format string
443  * @...: optional arguments for the format
444  *
445  * Logs the given message using the currently registered debugging handlers.
446  */
447 void
448 gst_debug_log (GstDebugCategory * category, GstDebugLevel level,
449     const gchar * file, const gchar * function, gint line,
450     GObject * object, const gchar * format, ...)
451 {
452   va_list var_args;
453
454   va_start (var_args, format);
455   gst_debug_log_valist (category, level, file, function, line, object, format,
456       var_args);
457   va_end (var_args);
458 }
459
460 #ifdef _MSC_VER
461 /* based on g_basename(), which we can't use because it was deprecated */
462 static inline const gchar *
463 gst_path_basename (const gchar * file_name)
464 {
465   register const gchar *base;
466
467   base = strrchr (file_name, G_DIR_SEPARATOR);
468
469   {
470     const gchar *q = strrchr (file_name, '/');
471     if (base == NULL || (q != NULL && q > base))
472       base = q;
473   }
474
475   if (base)
476     return base + 1;
477
478   if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
479     return file_name + 2;
480
481   return file_name;
482 }
483 #endif
484
485 /**
486  * gst_debug_log_valist:
487  * @category: category to log
488  * @level: level of the message is in
489  * @file: the file that emitted the message, usually the __FILE__ identifier
490  * @function: the function that emitted the message
491  * @line: the line from that the message was emitted, usually __LINE__
492  * @object: (transfer none) (allow-none): the object this message relates to,
493  *     or NULL if none
494  * @format: a printf style format string
495  * @args: optional arguments for the format
496  *
497  * Logs the given message using the currently registered debugging handlers.
498  */
499 void
500 gst_debug_log_valist (GstDebugCategory * category, GstDebugLevel level,
501     const gchar * file, const gchar * function, gint line,
502     GObject * object, const gchar * format, va_list args)
503 {
504   GstDebugMessage message;
505   LogFuncEntry *entry;
506   GSList *handler;
507
508   g_return_if_fail (category != NULL);
509   g_return_if_fail (file != NULL);
510   g_return_if_fail (function != NULL);
511   g_return_if_fail (format != NULL);
512
513   /* The predefined macro __FILE__ is always the exact path given to the
514    * compiler with MSVC, which may or may not be the basename.  We work
515    * around it at runtime to improve the readability. */
516 #ifdef _MSC_VER
517   file = gst_path_basename (file);
518 #endif
519
520   message.message = NULL;
521   message.format = format;
522   G_VA_COPY (message.arguments, args);
523
524   handler = __log_functions;
525   while (handler) {
526     entry = handler->data;
527     handler = g_slist_next (handler);
528     entry->func (category, level, file, function, line, object, &message,
529         entry->user_data);
530   }
531   g_free (message.message);
532   va_end (message.arguments);
533 }
534
535 /**
536  * gst_debug_message_get:
537  * @message: a debug message
538  *
539  * Gets the string representation of a #GstDebugMessage. This function is used
540  * in debug handlers to extract the message.
541  *
542  * Returns: the string representation of a #GstDebugMessage.
543  */
544 const gchar *
545 gst_debug_message_get (GstDebugMessage * message)
546 {
547   if (message->message == NULL) {
548     message->message = g_strdup_vprintf (message->format, message->arguments);
549   }
550   return message->message;
551 }
552
553 #define MAX_BUFFER_DUMP_STRING_LEN  100
554
555 /* structure_to_pretty_string:
556  * @structure: a #GstStructure
557  *
558  * Converts @structure to a human-readable string representation. Basically
559  * the same as gst_structure_to_string(), but if the structure contains large
560  * buffers such as images the hex representation of those buffers will be
561  * shortened so that the string remains readable.
562  *
563  * Returns: a newly-allocated string. g_free() when no longer needed.
564  */
565 static gchar *
566 structure_to_pretty_string (const GstStructure * s)
567 {
568   gchar *str, *pos, *end;
569
570   str = gst_structure_to_string (s);
571   if (str == NULL)
572     return NULL;
573
574   pos = str;
575   while ((pos = strstr (pos, "(buffer)"))) {
576     guint count = 0;
577
578     pos += strlen ("(buffer)");
579     for (end = pos; *end != '\0' && *end != ';' && *end != ' '; ++end)
580       ++count;
581     if (count > MAX_BUFFER_DUMP_STRING_LEN) {
582       memcpy (pos + MAX_BUFFER_DUMP_STRING_LEN - 6, "..", 2);
583       memcpy (pos + MAX_BUFFER_DUMP_STRING_LEN - 4, pos + count - 4, 4);
584       g_memmove (pos + MAX_BUFFER_DUMP_STRING_LEN, pos + count,
585           strlen (pos + count) + 1);
586       pos += MAX_BUFFER_DUMP_STRING_LEN;
587     }
588   }
589
590   return str;
591 }
592
593 static inline gchar *
594 gst_info_structure_to_string (const GstStructure * s)
595 {
596   if (G_UNLIKELY (pretty_tags && s->name == GST_QUARK (TAGLIST)))
597     return structure_to_pretty_string (s);
598   else
599     return gst_structure_to_string (s);
600 }
601
602 static gchar *
603 gst_debug_print_object (gpointer ptr)
604 {
605   GObject *object = (GObject *) ptr;
606
607 #ifdef unused
608   /* This is a cute trick to detect unmapped memory, but is unportable,
609    * slow, screws around with madvise, and not actually that useful. */
610   {
611     int ret;
612
613     ret = madvise ((void *) ((unsigned long) ptr & (~0xfff)), 4096, 0);
614     if (ret == -1 && errno == ENOMEM) {
615       buffer = g_strdup_printf ("%p (unmapped memory)", ptr);
616     }
617   }
618 #endif
619
620   /* nicely printed object */
621   if (object == NULL) {
622     return g_strdup ("(NULL)");
623   }
624   if (*(GType *) ptr == GST_TYPE_CAPS) {
625     return gst_caps_to_string ((const GstCaps *) ptr);
626   }
627   if (*(GType *) ptr == GST_TYPE_STRUCTURE) {
628     return gst_info_structure_to_string ((const GstStructure *) ptr);
629   }
630   if (*(GType *) ptr == GST_TYPE_TAG_LIST) {
631     /* FIXME: want pretty tag list with long byte dumps removed.. */
632     return gst_tag_list_to_string ((GstTagList *) ptr);
633   }
634   if (*(GType *) ptr == GST_TYPE_DATE_TIME) {
635     return __gst_date_time_serialize ((GstDateTime *) ptr, TRUE);
636   }
637   if (GST_IS_BUFFER (ptr)) {
638     GstBuffer *buf = (GstBuffer *) ptr;
639     gchar *ret;
640
641     ret =
642         g_strdup_printf ("%p, pts %" GST_TIME_FORMAT ", dts %" GST_TIME_FORMAT
643         ", dur %" GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT ", offset %"
644         G_GUINT64_FORMAT ", offset_end %" G_GUINT64_FORMAT, buf,
645         GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
646         GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
647         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), gst_buffer_get_size (buf),
648         GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
649     return ret;
650   }
651 #ifdef USE_POISONING
652   if (*(guint32 *) ptr == 0xffffffff) {
653     return g_strdup_printf ("<poisoned@%p>", ptr);
654   }
655 #endif
656   if (GST_IS_PAD (object) && GST_OBJECT_NAME (object)) {
657     return g_strdup_printf ("<%s:%s>", GST_DEBUG_PAD_NAME (object));
658   }
659   if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object)) {
660     return g_strdup_printf ("<%s>", GST_OBJECT_NAME (object));
661   }
662   if (G_IS_OBJECT (object)) {
663     return g_strdup_printf ("<%s@%p>", G_OBJECT_TYPE_NAME (object), object);
664   }
665   if (GST_IS_MESSAGE (object)) {
666     GstMessage *msg = GST_MESSAGE_CAST (object);
667     gchar *s, *ret;
668     const GstStructure *structure;
669
670     structure = gst_message_get_structure (msg);
671
672     if (structure) {
673       s = gst_info_structure_to_string (structure);
674     } else {
675       s = g_strdup ("(NULL)");
676     }
677
678     ret = g_strdup_printf ("%s message from element '%s': %s",
679         GST_MESSAGE_TYPE_NAME (msg), (msg->src != NULL) ?
680         GST_ELEMENT_NAME (msg->src) : "(NULL)", s);
681     g_free (s);
682     return ret;
683   }
684   if (GST_IS_QUERY (object)) {
685     GstQuery *query = GST_QUERY_CAST (object);
686     const GstStructure *structure;
687
688     structure = gst_query_get_structure (query);
689
690     if (structure) {
691       return gst_info_structure_to_string (structure);
692     } else {
693       const gchar *query_type_name;
694
695       query_type_name = gst_query_type_get_name (query->type);
696       if (G_LIKELY (query_type_name != NULL)) {
697         return g_strdup_printf ("%s query", query_type_name);
698       } else {
699         return g_strdup_printf ("query of unknown type %d", query->type);
700       }
701     }
702   }
703   if (GST_IS_EVENT (object)) {
704     GstEvent *event = GST_EVENT_CAST (object);
705     gchar *s, *ret;
706     GstStructure *structure;
707
708     structure = (GstStructure *) gst_event_get_structure (event);
709     if (structure) {
710       s = gst_info_structure_to_string (structure);
711     } else {
712       s = g_strdup ("(NULL)");
713     }
714
715     ret = g_strdup_printf ("%s event at time %"
716         GST_TIME_FORMAT ": %s",
717         GST_EVENT_TYPE_NAME (event), GST_TIME_ARGS (event->timestamp), s);
718     g_free (s);
719     return ret;
720   }
721
722   return g_strdup_printf ("%p", ptr);
723 }
724
725 #ifdef GST_USING_PRINTF_EXTENSION
726
727 static gchar *
728 gst_debug_print_segment (gpointer ptr)
729 {
730   GstSegment *segment = (GstSegment *) ptr;
731
732   /* nicely printed segment */
733   if (segment == NULL) {
734     return g_strdup ("(NULL)");
735   }
736
737   switch (segment->format) {
738     case GST_FORMAT_UNDEFINED:{
739       return g_strdup_printf ("UNDEFINED segment");
740     }
741     case GST_FORMAT_TIME:{
742       return g_strdup_printf ("time segment start=%" GST_TIME_FORMAT
743           ", stop=%" GST_TIME_FORMAT ", rate=%f, applied_rate=%f"
744           ", flags=0x%02x, time=%" GST_TIME_FORMAT ", base=%" GST_TIME_FORMAT
745           ", position %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
746           GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop),
747           segment->rate, segment->applied_rate, (guint) segment->flags,
748           GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->base),
749           GST_TIME_ARGS (segment->position), GST_TIME_ARGS (segment->duration));
750     }
751     default:{
752       const gchar *format_name;
753
754       format_name = gst_format_get_name (segment->format);
755       if (G_UNLIKELY (format_name == NULL))
756         format_name = "(UNKNOWN FORMAT)";
757       return g_strdup_printf ("%s segment start=%" G_GINT64_FORMAT
758           ", stop=%" G_GINT64_FORMAT ", rate=%f, applied_rate=%f"
759           ", flags=0x%02x, time=%" G_GINT64_FORMAT ", base=%" G_GINT64_FORMAT
760           ", position %" G_GINT64_FORMAT ", duration %" G_GINT64_FORMAT,
761           format_name, segment->start, segment->stop, segment->rate,
762           segment->applied_rate, (guint) segment->flags,
763           segment->time, segment->base, segment->position, segment->duration);
764     }
765   }
766 }
767
768 #endif /* GST_USING_PRINTF_EXTENSION */
769
770 /**
771  * gst_debug_construct_term_color:
772  * @colorinfo: the color info
773  *
774  * Constructs a string that can be used for getting the desired color in color
775  * terminals.
776  * You need to free the string after use.
777  *
778  * Returns: (transfer full) (type gchar*): a string containing the color
779  *     definition
780  */
781 gchar *
782 gst_debug_construct_term_color (guint colorinfo)
783 {
784   GString *color;
785
786   color = g_string_new ("\033[00");
787
788   if (colorinfo & GST_DEBUG_BOLD) {
789     g_string_append_len (color, ";01", 3);
790   }
791   if (colorinfo & GST_DEBUG_UNDERLINE) {
792     g_string_append_len (color, ";04", 3);
793   }
794   if (colorinfo & GST_DEBUG_FG_MASK) {
795     g_string_append_printf (color, ";3%1d", colorinfo & GST_DEBUG_FG_MASK);
796   }
797   if (colorinfo & GST_DEBUG_BG_MASK) {
798     g_string_append_printf (color, ";4%1d",
799         (colorinfo & GST_DEBUG_BG_MASK) >> 4);
800   }
801   g_string_append_c (color, 'm');
802
803   return g_string_free (color, FALSE);
804 }
805
806 /**
807  * gst_debug_construct_win_color:
808  * @colorinfo: the color info
809  *
810  * Constructs an integer that can be used for getting the desired color in
811  * windows' terminals (cmd.exe). As there is no mean to underline, we simply
812  * ignore this attribute.
813  *
814  * This function returns 0 on non-windows machines.
815  *
816  * Returns: an integer containing the color definition
817  */
818 gint
819 gst_debug_construct_win_color (guint colorinfo)
820 {
821   gint color = 0;
822 #ifdef G_OS_WIN32
823   static const guchar ansi_to_win_fg[8] = {
824     0,                          /* black   */
825     FOREGROUND_RED,             /* red     */
826     FOREGROUND_GREEN,           /* green   */
827     FOREGROUND_RED | FOREGROUND_GREEN,  /* yellow  */
828     FOREGROUND_BLUE,            /* blue    */
829     FOREGROUND_RED | FOREGROUND_BLUE,   /* magenta */
830     FOREGROUND_GREEN | FOREGROUND_BLUE, /* cyan    */
831     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* white   */
832   };
833   static const guchar ansi_to_win_bg[8] = {
834     0,
835     BACKGROUND_RED,
836     BACKGROUND_GREEN,
837     BACKGROUND_RED | BACKGROUND_GREEN,
838     BACKGROUND_BLUE,
839     BACKGROUND_RED | BACKGROUND_BLUE,
840     BACKGROUND_GREEN | FOREGROUND_BLUE,
841     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
842   };
843
844   /* we draw black as white, as cmd.exe can only have black bg */
845   if (colorinfo == 0) {
846     return ansi_to_win_fg[7];
847   }
848
849   if (colorinfo & GST_DEBUG_BOLD) {
850     color |= FOREGROUND_INTENSITY;
851   }
852   if (colorinfo & GST_DEBUG_FG_MASK) {
853     color |= ansi_to_win_fg[colorinfo & GST_DEBUG_FG_MASK];
854   }
855   if (colorinfo & GST_DEBUG_BG_MASK) {
856     color |= ansi_to_win_bg[(colorinfo & GST_DEBUG_BG_MASK) >> 4];
857   }
858 #endif
859   return color;
860 }
861
862 /* width of %p varies depending on actual value of pointer, which can make
863  * output unevenly aligned if multiple threads are involved, hence the %14p
864  * (should really be %18p, but %14p seems a good compromise between too many
865  * white spaces and likely unalignment on my system) */
866 #if defined (GLIB_SIZEOF_VOID_P) && GLIB_SIZEOF_VOID_P == 8
867 #define PTR_FMT "%14p"
868 #else
869 #define PTR_FMT "%10p"
870 #endif
871 #define PID_FMT "%5d"
872 #define CAT_FMT "%20s %s:%d:%s:%s"
873
874 #ifdef G_OS_WIN32
875 static const guchar levelcolormap[GST_LEVEL_COUNT] = {
876   /* GST_LEVEL_NONE */
877   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
878   /* GST_LEVEL_ERROR */
879   FOREGROUND_RED | FOREGROUND_INTENSITY,
880   /* GST_LEVEL_WARNING */
881   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
882   /* GST_LEVEL_INFO */
883   FOREGROUND_GREEN | FOREGROUND_INTENSITY,
884   /* GST_LEVEL_DEBUG */
885   FOREGROUND_GREEN | FOREGROUND_BLUE,
886   /* GST_LEVEL_LOG */
887   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
888   /* GST_LEVEL_FIXME */
889   FOREGROUND_RED | FOREGROUND_GREEN,
890   /* GST_LEVEL_TRACE */
891   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
892   /* placeholder for log level 8 */
893   0,
894   /* GST_LEVEL_MEMDUMP */
895   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
896 };
897
898 static const guchar available_colors[] = {
899   FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_RED | FOREGROUND_GREEN,
900   FOREGROUND_BLUE, FOREGROUND_RED | FOREGROUND_BLUE,
901   FOREGROUND_GREEN | FOREGROUND_BLUE,
902 };
903 #else
904 static const gchar *levelcolormap[GST_LEVEL_COUNT] = {
905   "\033[37m",                   /* GST_LEVEL_NONE */
906   "\033[31;01m",                /* GST_LEVEL_ERROR */
907   "\033[33;01m",                /* GST_LEVEL_WARNING */
908   "\033[32;01m",                /* GST_LEVEL_INFO */
909   "\033[36m",                   /* GST_LEVEL_DEBUG */
910   "\033[37m",                   /* GST_LEVEL_LOG */
911   "\033[33;01m",                /* GST_LEVEL_FIXME */
912   "\033[37m",                   /* GST_LEVEL_TRACE */
913   "\033[37m",                   /* placeholder for log level 8 */
914   "\033[37m"                    /* GST_LEVEL_MEMDUMP */
915 };
916 #endif
917
918 /**
919  * gst_debug_log_default:
920  * @category: category to log
921  * @level: level of the message
922  * @file: the file that emitted the message, usually the __FILE__ identifier
923  * @function: the function that emitted the message
924  * @line: the line from that the message was emitted, usually __LINE__
925  * @message: the actual message
926  * @object: (transfer none) (allow-none): the object this message relates to,
927  *     or NULL if none
928  * @unused: an unused variable, reserved for some user_data.
929  *
930  * The default logging handler used by GStreamer. Logging functions get called
931  * whenever a macro like GST_DEBUG or similar is used. This function outputs the
932  * message and additional info to stderr (or the log file specified via the
933  * GST_DEBUG_FILE environment variable).
934  *
935  * You can add other handlers by using gst_debug_add_log_function().
936  * And you can remove this handler by calling
937  * gst_debug_remove_log_function(gst_debug_log_default);
938  */
939 void
940 gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level,
941     const gchar * file, const gchar * function, gint line,
942     GObject * object, GstDebugMessage * message, gpointer unused)
943 {
944   gint pid;
945   GstClockTime elapsed;
946   gchar *obj = NULL;
947   gboolean is_colored;
948
949   if (level > gst_debug_category_get_threshold (category))
950     return;
951
952   pid = getpid ();
953   is_colored = gst_debug_is_colored ();
954
955   if (object) {
956     obj = gst_debug_print_object (object);
957   } else {
958     obj = g_strdup ("");
959   }
960
961   elapsed = GST_CLOCK_DIFF (_priv_gst_info_start_time,
962       gst_util_get_timestamp ());
963
964   if (is_colored) {
965 #ifndef G_OS_WIN32
966     /* colors, non-windows */
967     gchar *color = NULL;
968     const gchar *clear;
969     gchar pidcolor[10];
970     const gchar *levelcolor;
971
972     color = gst_debug_construct_term_color (gst_debug_category_get_color
973         (category));
974     clear = "\033[00m";
975     g_sprintf (pidcolor, "\033[3%1dm", pid % 6 + 31);
976     levelcolor = levelcolormap[level];
977
978 #define PRINT_FMT " %s"PID_FMT"%s "PTR_FMT" %s%s%s %s"CAT_FMT"%s %s\n"
979     fprintf (log_file, "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed),
980         pidcolor, pid, clear, g_thread_self (), levelcolor,
981         gst_debug_level_get_name (level), clear, color,
982         gst_debug_category_get_name (category), file, line, function, obj,
983         clear, gst_debug_message_get (message));
984     fflush (log_file);
985 #undef PRINT_FMT
986     g_free (color);
987 #else
988     /* colors, windows. We take a lock to keep colors and content together.
989      * Maybe there is a better way but for now this will do the right
990      * thing. */
991     static GMutex win_print_mutex;
992     const gint clear = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
993 #define SET_COLOR(c) G_STMT_START { \
994   if (log_file == stderr) \
995     SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (c)); \
996   } G_STMT_END
997     g_mutex_lock (&win_print_mutex);
998     /* timestamp */
999     fprintf (log_file, "%" GST_TIME_FORMAT " ", GST_TIME_ARGS (elapsed));
1000     fflush (log_file);
1001     /* pid */
1002     SET_COLOR (available_colors[pid % G_N_ELEMENTS (available_colors)]);
1003     fprintf (log_file, PID_FMT, pid);
1004     fflush (log_file);
1005     /* thread */
1006     SET_COLOR (clear);
1007     fprintf (log_file, " " PTR_FMT " ", g_thread_self ());
1008     fflush (log_file);
1009     /* level */
1010     SET_COLOR (levelcolormap[level]);
1011     fprintf (log_file, "%s ", gst_debug_level_get_name (level));
1012     fflush (log_file);
1013     /* category */
1014     SET_COLOR (gst_debug_construct_win_color (gst_debug_category_get_color
1015             (category)));
1016     fprintf (log_file, CAT_FMT, gst_debug_category_get_name (category),
1017         file, line, function, obj);
1018     fflush (log_file);
1019     /* message */
1020     SET_COLOR (clear);
1021     fprintf (log_file, " %s\n", gst_debug_message_get (message));
1022     fflush (log_file);
1023     g_mutex_unlock (&win_print_mutex);
1024 #endif
1025   } else {
1026     /* no color, all platforms */
1027 #define PRINT_FMT " "PID_FMT" "PTR_FMT" %s "CAT_FMT" %s\n"
1028     fprintf (log_file, "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed),
1029         pid, g_thread_self (), gst_debug_level_get_name (level),
1030         gst_debug_category_get_name (category), file, line, function, obj,
1031         gst_debug_message_get (message));
1032     fflush (log_file);
1033 #undef PRINT_FMT
1034   }
1035
1036   g_free (obj);
1037 }
1038
1039 /**
1040  * gst_debug_level_get_name:
1041  * @level: the level to get the name for
1042  *
1043  * Get the string representation of a debugging level
1044  *
1045  * Returns: the name
1046  */
1047 const gchar *
1048 gst_debug_level_get_name (GstDebugLevel level)
1049 {
1050   switch (level) {
1051     case GST_LEVEL_NONE:
1052       return "";
1053     case GST_LEVEL_ERROR:
1054       return "ERROR  ";
1055     case GST_LEVEL_WARNING:
1056       return "WARN   ";
1057     case GST_LEVEL_INFO:
1058       return "INFO   ";
1059     case GST_LEVEL_DEBUG:
1060       return "DEBUG  ";
1061     case GST_LEVEL_LOG:
1062       return "LOG    ";
1063     case GST_LEVEL_FIXME:
1064       return "FIXME  ";
1065     case GST_LEVEL_TRACE:
1066       return "TRACE  ";
1067     case GST_LEVEL_MEMDUMP:
1068       return "MEMDUMP";
1069     default:
1070       g_warning ("invalid level specified for gst_debug_level_get_name");
1071       return "";
1072   }
1073 }
1074
1075 /**
1076  * gst_debug_add_log_function:
1077  * @func: the function to use
1078  * @user_data: user data
1079  * @notify: called when @user_data is not used anymore
1080  *
1081  * Adds the logging function to the list of logging functions.
1082  * Be sure to use #G_GNUC_NO_INSTRUMENT on that function, it is needed.
1083  */
1084 void
1085 gst_debug_add_log_function (GstLogFunction func, gpointer user_data,
1086     GDestroyNotify notify)
1087 {
1088   LogFuncEntry *entry;
1089   GSList *list;
1090
1091   if (func == NULL)
1092     func = gst_debug_log_default;
1093
1094   entry = g_slice_new (LogFuncEntry);
1095   entry->func = func;
1096   entry->user_data = user_data;
1097   entry->notify = notify;
1098   /* FIXME: we leak the old list here - other threads might access it right now
1099    * in gst_debug_logv. Another solution is to lock the mutex in gst_debug_logv,
1100    * but that is waaay costly.
1101    * It'd probably be clever to use some kind of RCU here, but I don't know
1102    * anything about that.
1103    */
1104   g_mutex_lock (&__log_func_mutex);
1105   list = g_slist_copy (__log_functions);
1106   __log_functions = g_slist_prepend (list, entry);
1107   g_mutex_unlock (&__log_func_mutex);
1108
1109   if (gst_is_initialized ())
1110     GST_DEBUG ("prepended log function %p (user data %p) to log functions",
1111         func, user_data);
1112 }
1113
1114 static gint
1115 gst_debug_compare_log_function_by_func (gconstpointer entry, gconstpointer func)
1116 {
1117   gpointer entryfunc = (gpointer) (((LogFuncEntry *) entry)->func);
1118
1119   return (entryfunc < func) ? -1 : (entryfunc > func) ? 1 : 0;
1120 }
1121
1122 static gint
1123 gst_debug_compare_log_function_by_data (gconstpointer entry, gconstpointer data)
1124 {
1125   gpointer entrydata = ((LogFuncEntry *) entry)->user_data;
1126
1127   return (entrydata < data) ? -1 : (entrydata > data) ? 1 : 0;
1128 }
1129
1130 static guint
1131 gst_debug_remove_with_compare_func (GCompareFunc func, gpointer data)
1132 {
1133   GSList *found;
1134   GSList *new, *cleanup = NULL;
1135   guint removals = 0;
1136
1137   g_mutex_lock (&__log_func_mutex);
1138   new = __log_functions;
1139   cleanup = NULL;
1140   while ((found = g_slist_find_custom (new, data, func))) {
1141     if (new == __log_functions) {
1142       /* make a copy when we have the first hit, so that we modify the copy and
1143        * make that the new list later */
1144       new = g_slist_copy (new);
1145       continue;
1146     }
1147     cleanup = g_slist_prepend (cleanup, found->data);
1148     new = g_slist_delete_link (new, found);
1149     removals++;
1150   }
1151   /* FIXME: We leak the old list here. See _add_log_function for why. */
1152   __log_functions = new;
1153   g_mutex_unlock (&__log_func_mutex);
1154
1155   while (cleanup) {
1156     LogFuncEntry *entry = cleanup->data;
1157
1158     if (entry->notify)
1159       entry->notify (entry->user_data);
1160
1161     g_slice_free (LogFuncEntry, entry);
1162     cleanup = g_slist_delete_link (cleanup, cleanup);
1163   }
1164   return removals;
1165 }
1166
1167 /**
1168  * gst_debug_remove_log_function:
1169  * @func: (scope call): the log function to remove
1170  *
1171  * Removes all registered instances of the given logging functions.
1172  *
1173  * Returns: How many instances of the function were removed
1174  */
1175 guint
1176 gst_debug_remove_log_function (GstLogFunction func)
1177 {
1178   guint removals;
1179
1180   if (func == NULL)
1181     func = gst_debug_log_default;
1182
1183   removals =
1184       gst_debug_remove_with_compare_func
1185       (gst_debug_compare_log_function_by_func, (gpointer) func);
1186   if (gst_is_initialized ())
1187     GST_DEBUG ("removed log function %p %d times from log function list", func,
1188         removals);
1189
1190   return removals;
1191 }
1192
1193 /**
1194  * gst_debug_remove_log_function_by_data:
1195  * @data: user data of the log function to remove
1196  *
1197  * Removes all registered instances of log functions with the given user data.
1198  *
1199  * Returns: How many instances of the function were removed
1200  */
1201 guint
1202 gst_debug_remove_log_function_by_data (gpointer data)
1203 {
1204   guint removals;
1205
1206   removals =
1207       gst_debug_remove_with_compare_func
1208       (gst_debug_compare_log_function_by_data, data);
1209
1210   if (gst_is_initialized ())
1211     GST_DEBUG
1212         ("removed %d log functions with user data %p from log function list",
1213         removals, data);
1214
1215   return removals;
1216 }
1217
1218 /**
1219  * gst_debug_set_colored:
1220  * @colored: Whether to use colored output or not
1221  *
1222  * Sets or unsets the use of coloured debugging output.
1223  *
1224  * This function may be called before gst_init().
1225  */
1226 void
1227 gst_debug_set_colored (gboolean colored)
1228 {
1229   g_atomic_int_set (&__use_color, (gint) colored);
1230 }
1231
1232 /**
1233  * gst_debug_is_colored:
1234  *
1235  * Checks if the debugging output should be colored.
1236  *
1237  * Returns: TRUE, if the debug output should be colored.
1238  */
1239 gboolean
1240 gst_debug_is_colored (void)
1241 {
1242   return (gboolean) g_atomic_int_get (&__use_color);
1243 }
1244
1245 /**
1246  * gst_debug_set_active:
1247  * @active: Whether to use debugging output or not
1248  *
1249  * If activated, debugging messages are sent to the debugging
1250  * handlers.
1251  * It makes sense to deactivate it for speed issues.
1252  * <note><para>This function is not threadsafe. It makes sense to only call it
1253  * during initialization.</para></note>
1254  */
1255 void
1256 gst_debug_set_active (gboolean active)
1257 {
1258   _gst_debug_enabled = active;
1259   if (active)
1260     _gst_debug_min = GST_LEVEL_COUNT;
1261   else
1262     _gst_debug_min = GST_LEVEL_NONE;
1263 }
1264
1265 /**
1266  * gst_debug_is_active:
1267  *
1268  * Checks if debugging output is activated.
1269  *
1270  * Returns: TRUE, if debugging is activated
1271  */
1272 gboolean
1273 gst_debug_is_active (void)
1274 {
1275   return _gst_debug_enabled;
1276 }
1277
1278 /**
1279  * gst_debug_set_default_threshold:
1280  * @level: level to set
1281  *
1282  * Sets the default threshold to the given level and updates all categories to
1283  * use this threshold.
1284  *
1285  * This function may be called before gst_init().
1286  */
1287 void
1288 gst_debug_set_default_threshold (GstDebugLevel level)
1289 {
1290   g_atomic_int_set (&__default_level, level);
1291   gst_debug_reset_all_thresholds ();
1292 }
1293
1294 /**
1295  * gst_debug_get_default_threshold:
1296  *
1297  * Returns the default threshold that is used for new categories.
1298  *
1299  * Returns: the default threshold level
1300  */
1301 GstDebugLevel
1302 gst_debug_get_default_threshold (void)
1303 {
1304   return (GstDebugLevel) g_atomic_int_get (&__default_level);
1305 }
1306
1307 static void
1308 gst_debug_reset_threshold (gpointer category, gpointer unused)
1309 {
1310   GstDebugCategory *cat = (GstDebugCategory *) category;
1311   GSList *walk;
1312
1313   g_mutex_lock (&__level_name_mutex);
1314   walk = __level_name;
1315   while (walk) {
1316     LevelNameEntry *entry = walk->data;
1317
1318     walk = g_slist_next (walk);
1319     if (g_pattern_match_string (entry->pat, cat->name)) {
1320       if (gst_is_initialized ())
1321         GST_LOG ("category %s matches pattern %p - gets set to level %d",
1322             cat->name, entry->pat, entry->level);
1323       gst_debug_category_set_threshold (cat, entry->level);
1324       goto exit;
1325     }
1326   }
1327   gst_debug_category_set_threshold (cat, gst_debug_get_default_threshold ());
1328
1329 exit:
1330   g_mutex_unlock (&__level_name_mutex);
1331 }
1332
1333 static void
1334 gst_debug_reset_all_thresholds (void)
1335 {
1336   g_mutex_lock (&__cat_mutex);
1337   g_slist_foreach (__categories, gst_debug_reset_threshold, NULL);
1338   g_mutex_unlock (&__cat_mutex);
1339 }
1340
1341 static void
1342 for_each_threshold_by_entry (gpointer data, gpointer user_data)
1343 {
1344   GstDebugCategory *cat = (GstDebugCategory *) data;
1345   LevelNameEntry *entry = (LevelNameEntry *) user_data;
1346
1347   if (g_pattern_match_string (entry->pat, cat->name)) {
1348     if (gst_is_initialized ())
1349       GST_LOG ("category %s matches pattern %p - gets set to level %d",
1350           cat->name, entry->pat, entry->level);
1351     gst_debug_category_set_threshold (cat, entry->level);
1352   }
1353 }
1354
1355 /**
1356  * gst_debug_set_threshold_for_name:
1357  * @name: name of the categories to set
1358  * @level: level to set them to
1359  *
1360  * Sets all categories which match the given glob style pattern to the given
1361  * level.
1362  */
1363 void
1364 gst_debug_set_threshold_for_name (const gchar * name, GstDebugLevel level)
1365 {
1366   GPatternSpec *pat;
1367   LevelNameEntry *entry;
1368
1369   g_return_if_fail (name != NULL);
1370
1371   pat = g_pattern_spec_new (name);
1372   entry = g_slice_new (LevelNameEntry);
1373   entry->pat = pat;
1374   entry->level = level;
1375   g_mutex_lock (&__level_name_mutex);
1376   __level_name = g_slist_prepend (__level_name, entry);
1377   g_mutex_unlock (&__level_name_mutex);
1378   g_mutex_lock (&__cat_mutex);
1379   g_slist_foreach (__categories, for_each_threshold_by_entry, entry);
1380   g_mutex_unlock (&__cat_mutex);
1381 }
1382
1383 /**
1384  * gst_debug_unset_threshold_for_name:
1385  * @name: name of the categories to set
1386  *
1387  * Resets all categories with the given name back to the default level.
1388  */
1389 void
1390 gst_debug_unset_threshold_for_name (const gchar * name)
1391 {
1392   GSList *walk;
1393   GPatternSpec *pat;
1394
1395   g_return_if_fail (name != NULL);
1396
1397   pat = g_pattern_spec_new (name);
1398   g_mutex_lock (&__level_name_mutex);
1399   walk = __level_name;
1400   /* improve this if you want, it's mighty slow */
1401   while (walk) {
1402     LevelNameEntry *entry = walk->data;
1403
1404     if (g_pattern_spec_equal (entry->pat, pat)) {
1405       __level_name = g_slist_remove_link (__level_name, walk);
1406       g_pattern_spec_free (entry->pat);
1407       g_slice_free (LevelNameEntry, entry);
1408       g_slist_free_1 (walk);
1409       walk = __level_name;
1410     }
1411   }
1412   g_mutex_unlock (&__level_name_mutex);
1413   g_pattern_spec_free (pat);
1414   gst_debug_reset_all_thresholds ();
1415 }
1416
1417 GstDebugCategory *
1418 _gst_debug_category_new (const gchar * name, guint color,
1419     const gchar * description)
1420 {
1421   GstDebugCategory *cat;
1422
1423   g_return_val_if_fail (name != NULL, NULL);
1424
1425   cat = g_slice_new (GstDebugCategory);
1426   cat->name = g_strdup (name);
1427   cat->color = color;
1428   if (description != NULL) {
1429     cat->description = g_strdup (description);
1430   } else {
1431     cat->description = g_strdup ("no description");
1432   }
1433   g_atomic_int_set (&cat->threshold, 0);
1434   gst_debug_reset_threshold (cat, NULL);
1435
1436   /* add to category list */
1437   g_mutex_lock (&__cat_mutex);
1438   __categories = g_slist_prepend (__categories, cat);
1439   g_mutex_unlock (&__cat_mutex);
1440
1441   return cat;
1442 }
1443
1444 /**
1445  * gst_debug_category_free:
1446  * @category: #GstDebugCategory to free.
1447  *
1448  * Removes and frees the category and all associated resources.
1449  */
1450 void
1451 gst_debug_category_free (GstDebugCategory * category)
1452 {
1453   if (category == NULL)
1454     return;
1455
1456   /* remove from category list */
1457   g_mutex_lock (&__cat_mutex);
1458   __categories = g_slist_remove (__categories, category);
1459   g_mutex_unlock (&__cat_mutex);
1460
1461   g_free ((gpointer) category->name);
1462   g_free ((gpointer) category->description);
1463   g_slice_free (GstDebugCategory, category);
1464 }
1465
1466 /**
1467  * gst_debug_category_set_threshold:
1468  * @category: a #GstDebugCategory to set threshold of.
1469  * @level: the #GstDebugLevel threshold to set.
1470  *
1471  * Sets the threshold of the category to the given level. Debug information will
1472  * only be output if the threshold is lower or equal to the level of the
1473  * debugging message.
1474  * <note><para>
1475  * Do not use this function in production code, because other functions may
1476  * change the threshold of categories as side effect. It is however a nice
1477  * function to use when debugging (even from gdb).
1478  * </para></note>
1479  */
1480 void
1481 gst_debug_category_set_threshold (GstDebugCategory * category,
1482     GstDebugLevel level)
1483 {
1484   g_return_if_fail (category != NULL);
1485
1486   if (level > _gst_debug_min) {
1487     _gst_debug_enabled = TRUE;
1488     _gst_debug_min = level;
1489   }
1490
1491   g_atomic_int_set (&category->threshold, level);
1492 }
1493
1494 /**
1495  * gst_debug_category_reset_threshold:
1496  * @category: a #GstDebugCategory to reset threshold of.
1497  *
1498  * Resets the threshold of the category to the default level. Debug information
1499  * will only be output if the threshold is lower or equal to the level of the
1500  * debugging message.
1501  * Use this function to set the threshold back to where it was after using
1502  * gst_debug_category_set_threshold().
1503  */
1504 void
1505 gst_debug_category_reset_threshold (GstDebugCategory * category)
1506 {
1507   gst_debug_reset_threshold (category, NULL);
1508 }
1509
1510 /**
1511  * gst_debug_category_get_threshold:
1512  * @category: a #GstDebugCategory to get threshold of.
1513  *
1514  * Returns the threshold of a #GstDebugCategory.
1515  *
1516  * Returns: the #GstDebugLevel that is used as threshold.
1517  */
1518 GstDebugLevel
1519 gst_debug_category_get_threshold (GstDebugCategory * category)
1520 {
1521   return (GstDebugLevel) g_atomic_int_get (&category->threshold);
1522 }
1523
1524 /**
1525  * gst_debug_category_get_name:
1526  * @category: a #GstDebugCategory to get name of.
1527  *
1528  * Returns the name of a debug category.
1529  *
1530  * Returns: the name of the category.
1531  */
1532 const gchar *
1533 gst_debug_category_get_name (GstDebugCategory * category)
1534 {
1535   return category->name;
1536 }
1537
1538 /**
1539  * gst_debug_category_get_color:
1540  * @category: a #GstDebugCategory to get the color of.
1541  *
1542  * Returns the color of a debug category used when printing output in this
1543  * category.
1544  *
1545  * Returns: the color of the category.
1546  */
1547 guint
1548 gst_debug_category_get_color (GstDebugCategory * category)
1549 {
1550   return category->color;
1551 }
1552
1553 /**
1554  * gst_debug_category_get_description:
1555  * @category: a #GstDebugCategory to get the description of.
1556  *
1557  * Returns the description of a debug category.
1558  *
1559  * Returns: the description of the category.
1560  */
1561 const gchar *
1562 gst_debug_category_get_description (GstDebugCategory * category)
1563 {
1564   return category->description;
1565 }
1566
1567 /**
1568  * gst_debug_get_all_categories:
1569  *
1570  * Returns a snapshot of a all categories that are currently in use . This list
1571  * may change anytime.
1572  * The caller has to free the list after use.
1573  *
1574  * Returns: (transfer container) (element-type Gst.DebugCategory): the list of
1575  *     debug categories
1576  */
1577 GSList *
1578 gst_debug_get_all_categories (void)
1579 {
1580   GSList *ret;
1581
1582   g_mutex_lock (&__cat_mutex);
1583   ret = g_slist_copy (__categories);
1584   g_mutex_unlock (&__cat_mutex);
1585
1586   return ret;
1587 }
1588
1589 GstDebugCategory *
1590 _gst_debug_get_category (const gchar * name)
1591 {
1592   GstDebugCategory *ret = NULL;
1593   GSList *node;
1594
1595   for (node = __categories; node; node = g_slist_next (node)) {
1596     ret = (GstDebugCategory *) node->data;
1597     if (!strcmp (name, ret->name)) {
1598       return ret;
1599     }
1600   }
1601   return NULL;
1602 }
1603
1604 static gboolean
1605 parse_debug_category (gchar * str, const gchar ** category)
1606 {
1607   if (!str)
1608     return FALSE;
1609
1610   /* works in place */
1611   g_strstrip (str);
1612
1613   if (str[0] != '\0') {
1614     *category = str;
1615     return TRUE;
1616   }
1617
1618   return FALSE;
1619 }
1620
1621 static gboolean
1622 parse_debug_level (gchar * str, GstDebugLevel * level)
1623 {
1624   if (!str)
1625     return FALSE;
1626
1627   /* works in place */
1628   g_strstrip (str);
1629
1630   if (str[0] != '\0' && str[1] == '\0'
1631       && str[0] >= '0' && str[0] < '0' + GST_LEVEL_COUNT) {
1632     *level = (GstDebugLevel) (str[0] - '0');
1633     return TRUE;
1634   }
1635
1636   return FALSE;
1637 }
1638
1639 /**
1640  * gst_debug_set_threshold_from_string:
1641  * @list: comma-separated list of "category:level" pairs to be used
1642  *     as debug logging levels
1643  * @reset: %TRUE to clear all previously-set debug levels before setting
1644  *     new thresholds
1645  * %FALSE if adding the threshold described by @list to the one already set.
1646  *
1647  * Sets the debug logging wanted in the same form as with the GST_DEBUG
1648  * environment variable. You can use wildcards such as '*', but note that
1649  * the order matters when you use wild cards, e.g. "foosrc:6,*src:3,*:2" sets
1650  * everything to log level 2.
1651  *
1652  * Since: 1.2.0
1653  */
1654 void
1655 gst_debug_set_threshold_from_string (const gchar * list, gboolean reset)
1656 {
1657   gchar **split;
1658   gchar **walk;
1659
1660   g_assert (list);
1661
1662   if (reset == TRUE)
1663     gst_debug_set_default_threshold (0);
1664
1665   split = g_strsplit (list, ",", 0);
1666
1667   for (walk = split; *walk; walk++) {
1668     if (strchr (*walk, ':')) {
1669       gchar **values = g_strsplit (*walk, ":", 2);
1670
1671       if (values[0] && values[1]) {
1672         GstDebugLevel level;
1673         const gchar *category;
1674
1675         if (parse_debug_category (values[0], &category)
1676             && parse_debug_level (values[1], &level))
1677           gst_debug_set_threshold_for_name (category, level);
1678       }
1679
1680       g_strfreev (values);
1681     } else {
1682       GstDebugLevel level;
1683
1684       if (parse_debug_level (*walk, &level))
1685         gst_debug_set_default_threshold (level);
1686     }
1687   }
1688
1689   g_strfreev (split);
1690 }
1691
1692 /*** FUNCTION POINTERS ********************************************************/
1693
1694 static GHashTable *__gst_function_pointers;     /* NULL */
1695 static GMutex __dbg_functions_mutex;
1696
1697 /* This function MUST NOT return NULL */
1698 const gchar *
1699 _gst_debug_nameof_funcptr (GstDebugFuncPtr func)
1700 {
1701   gchar *ptrname;
1702
1703 #ifdef HAVE_DLADDR
1704   Dl_info dl_info;
1705 #endif
1706
1707   if (G_UNLIKELY (func == NULL))
1708     return "(NULL)";
1709
1710   g_mutex_lock (&__dbg_functions_mutex);
1711   if (G_LIKELY (__gst_function_pointers)) {
1712     ptrname = g_hash_table_lookup (__gst_function_pointers, (gpointer) func);
1713     g_mutex_unlock (&__dbg_functions_mutex);
1714     if (G_LIKELY (ptrname))
1715       return ptrname;
1716   } else {
1717     g_mutex_unlock (&__dbg_functions_mutex);
1718   }
1719   /* we need to create an entry in the hash table for this one so we don't leak
1720    * the name */
1721 #ifdef HAVE_DLADDR
1722   if (dladdr ((gpointer) func, &dl_info) && dl_info.dli_sname) {
1723     gchar *name = g_strdup (dl_info.dli_sname);
1724
1725     _gst_debug_register_funcptr (func, name);
1726     return name;
1727   } else
1728 #endif
1729   {
1730     gchar *name = g_strdup_printf ("%p", (gpointer) func);
1731
1732     _gst_debug_register_funcptr (func, name);
1733     return name;
1734   }
1735 }
1736
1737 void
1738 _gst_debug_register_funcptr (GstDebugFuncPtr func, const gchar * ptrname)
1739 {
1740   gpointer ptr = (gpointer) func;
1741
1742   g_mutex_lock (&__dbg_functions_mutex);
1743
1744   if (!__gst_function_pointers)
1745     __gst_function_pointers = g_hash_table_new (g_direct_hash, g_direct_equal);
1746   if (!g_hash_table_lookup (__gst_function_pointers, ptr))
1747     g_hash_table_insert (__gst_function_pointers, ptr, (gpointer) ptrname);
1748
1749   g_mutex_unlock (&__dbg_functions_mutex);
1750 }
1751
1752 /*** PRINTF EXTENSIONS ********************************************************/
1753
1754 #ifdef GST_USING_PRINTF_EXTENSION
1755 static int
1756 _gst_info_printf_extension_ptr (FILE * stream, const struct printf_info *info,
1757     const void *const *args)
1758 {
1759   char *buffer;
1760   int len;
1761   void *ptr;
1762
1763   buffer = NULL;
1764   ptr = *(void **) args[0];
1765
1766   buffer = gst_debug_print_object (ptr);
1767   len = fprintf (stream, "%*s", (info->left ? -info->width : info->width),
1768       buffer);
1769
1770   g_free (buffer);
1771   return len;
1772 }
1773
1774 static int
1775 _gst_info_printf_extension_segment (FILE * stream,
1776     const struct printf_info *info, const void *const *args)
1777 {
1778   char *buffer;
1779   int len;
1780   void *ptr;
1781
1782   buffer = NULL;
1783   ptr = *(void **) args[0];
1784
1785   buffer = gst_debug_print_segment (ptr);
1786   len = fprintf (stream, "%*s", (info->left ? -info->width : info->width),
1787       buffer);
1788
1789   g_free (buffer);
1790   return len;
1791 }
1792
1793 #ifdef HAVE_REGISTER_PRINTF_SPECIFIER
1794 static int
1795 _gst_info_printf_extension_arginfo (const struct printf_info *info, size_t n,
1796     int *argtypes, int *size)
1797 #else
1798 static int
1799 _gst_info_printf_extension_arginfo (const struct printf_info *info, size_t n,
1800     int *argtypes)
1801 #endif
1802 {
1803   if (n > 0) {
1804     argtypes[0] = PA_POINTER;
1805 #ifdef HAVE_REGISTER_PRINTF_SPECIFIER
1806     *size = sizeof (gpointer);
1807 #endif
1808   }
1809   return 1;
1810 }
1811 #endif /* GST_USING_PRINTF_EXTENSION */
1812
1813 static void
1814 gst_info_dump_mem_line (gchar * linebuf, gsize linebuf_size,
1815     const guint8 * mem, gsize mem_offset, gsize mem_size)
1816 {
1817   gchar hexstr[50], ascstr[18], digitstr[4];
1818
1819   if (mem_size > 16)
1820     mem_size = 16;
1821
1822   hexstr[0] = '\0';
1823   ascstr[0] = '\0';
1824
1825   if (mem != NULL) {
1826     guint i = 0;
1827
1828     mem += mem_offset;
1829     while (i < mem_size) {
1830       ascstr[i] = (g_ascii_isprint (mem[i])) ? mem[i] : '.';
1831       g_snprintf (digitstr, sizeof (digitstr), "%02x ", mem[i]);
1832       g_strlcat (hexstr, digitstr, sizeof (hexstr));
1833       ++i;
1834     }
1835     ascstr[i] = '\0';
1836   }
1837
1838   g_snprintf (linebuf, linebuf_size, "%08x: %-48.48s %-16.16s",
1839       (guint) mem_offset, hexstr, ascstr);
1840 }
1841
1842 void
1843 _gst_debug_dump_mem (GstDebugCategory * cat, const gchar * file,
1844     const gchar * func, gint line, GObject * obj, const gchar * msg,
1845     const guint8 * data, guint length)
1846 {
1847   guint off = 0;
1848
1849   gst_debug_log ((cat), GST_LEVEL_MEMDUMP, file, func, line, obj, "--------"
1850       "-------------------------------------------------------------------");
1851
1852   if (msg != NULL && *msg != '\0') {
1853     gst_debug_log ((cat), GST_LEVEL_MEMDUMP, file, func, line, obj, "%s", msg);
1854   }
1855
1856   while (off < length) {
1857     gchar buf[128];
1858
1859     /* gst_info_dump_mem_line will process 16 bytes at most */
1860     gst_info_dump_mem_line (buf, sizeof (buf), data, off, length - off);
1861     gst_debug_log (cat, GST_LEVEL_MEMDUMP, file, func, line, obj, "%s", buf);
1862     off += 16;
1863   }
1864
1865   gst_debug_log ((cat), GST_LEVEL_MEMDUMP, file, func, line, obj, "--------"
1866       "-------------------------------------------------------------------");
1867 }
1868
1869 #else /* !GST_DISABLE_GST_DEBUG */
1870 #ifndef GST_REMOVE_DISABLED
1871
1872 GstDebugCategory *
1873 _gst_debug_category_new (const gchar * name, guint color,
1874     const gchar * description)
1875 {
1876   return NULL;
1877 }
1878
1879 void
1880 _gst_debug_register_funcptr (GstDebugFuncPtr func, const gchar * ptrname)
1881 {
1882 }
1883
1884 /* This function MUST NOT return NULL */
1885 const gchar *
1886 _gst_debug_nameof_funcptr (GstDebugFuncPtr func)
1887 {
1888   return "(NULL)";
1889 }
1890
1891 void
1892 gst_debug_log (GstDebugCategory * category, GstDebugLevel level,
1893     const gchar * file, const gchar * function, gint line,
1894     GObject * object, const gchar * format, ...)
1895 {
1896 }
1897
1898 void
1899 gst_debug_log_valist (GstDebugCategory * category, GstDebugLevel level,
1900     const gchar * file, const gchar * function, gint line,
1901     GObject * object, const gchar * format, va_list args)
1902 {
1903 }
1904
1905 const gchar *
1906 gst_debug_message_get (GstDebugMessage * message)
1907 {
1908   return "";
1909 }
1910
1911 void
1912 gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level,
1913     const gchar * file, const gchar * function, gint line,
1914     GObject * object, GstDebugMessage * message, gpointer unused)
1915 {
1916 }
1917
1918 const gchar *
1919 gst_debug_level_get_name (GstDebugLevel level)
1920 {
1921   return "NONE";
1922 }
1923
1924 void
1925 gst_debug_add_log_function (GstLogFunction func, gpointer user_data,
1926     GDestroyNotify notify)
1927 {
1928 }
1929
1930 guint
1931 gst_debug_remove_log_function (GstLogFunction func)
1932 {
1933   return 0;
1934 }
1935
1936 guint
1937 gst_debug_remove_log_function_by_data (gpointer data)
1938 {
1939   return 0;
1940 }
1941
1942 void
1943 gst_debug_set_active (gboolean active)
1944 {
1945 }
1946
1947 gboolean
1948 gst_debug_is_active (void)
1949 {
1950   return FALSE;
1951 }
1952
1953 void
1954 gst_debug_set_colored (gboolean colored)
1955 {
1956 }
1957
1958 gboolean
1959 gst_debug_is_colored (void)
1960 {
1961   return FALSE;
1962 }
1963
1964 void
1965 gst_debug_set_threshold_from_string (const gchar * list)
1966 {
1967 }
1968
1969 void
1970 gst_debug_set_default_threshold (GstDebugLevel level)
1971 {
1972 }
1973
1974 GstDebugLevel
1975 gst_debug_get_default_threshold (void)
1976 {
1977   return GST_LEVEL_NONE;
1978 }
1979
1980 void
1981 gst_debug_set_threshold_for_name (const gchar * name, GstDebugLevel level)
1982 {
1983 }
1984
1985 void
1986 gst_debug_unset_threshold_for_name (const gchar * name)
1987 {
1988 }
1989
1990 void
1991 gst_debug_category_free (GstDebugCategory * category)
1992 {
1993 }
1994
1995 void
1996 gst_debug_category_set_threshold (GstDebugCategory * category,
1997     GstDebugLevel level)
1998 {
1999 }
2000
2001 void
2002 gst_debug_category_reset_threshold (GstDebugCategory * category)
2003 {
2004 }
2005
2006 GstDebugLevel
2007 gst_debug_category_get_threshold (GstDebugCategory * category)
2008 {
2009   return GST_LEVEL_NONE;
2010 }
2011
2012 const gchar *
2013 gst_debug_category_get_name (GstDebugCategory * category)
2014 {
2015   return "";
2016 }
2017
2018 guint
2019 gst_debug_category_get_color (GstDebugCategory * category)
2020 {
2021   return 0;
2022 }
2023
2024 const gchar *
2025 gst_debug_category_get_description (GstDebugCategory * category)
2026 {
2027   return "";
2028 }
2029
2030 GSList *
2031 gst_debug_get_all_categories (void)
2032 {
2033   return NULL;
2034 }
2035
2036 GstDebugCategory *
2037 _gst_debug_get_category (const gchar * name)
2038 {
2039   return NULL;
2040 }
2041
2042 gchar *
2043 gst_debug_construct_term_color (guint colorinfo)
2044 {
2045   return g_strdup ("00");
2046 }
2047
2048 gint
2049 gst_debug_construct_win_color (guint colorinfo)
2050 {
2051   return 0;
2052 }
2053
2054 gboolean
2055 _priv_gst_in_valgrind (void)
2056 {
2057   return FALSE;
2058 }
2059
2060 void
2061 _gst_debug_dump_mem (GstDebugCategory * cat, const gchar * file,
2062     const gchar * func, gint line, GObject * obj, const gchar * msg,
2063     const guint8 * data, guint length)
2064 {
2065 }
2066 #endif /* GST_REMOVE_DISABLED */
2067 #endif /* GST_DISABLE_GST_DEBUG */
2068
2069
2070 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
2071 /* FIXME make this thread specific */
2072 static GSList *stack_trace = NULL;
2073
2074 void
2075 __cyg_profile_func_enter (void *this_fn, void *call_site)
2076     G_GNUC_NO_INSTRUMENT;
2077      void __cyg_profile_func_enter (void *this_fn, void *call_site)
2078 {
2079   gchar *name = _gst_debug_nameof_funcptr (this_fn);
2080   gchar *site = _gst_debug_nameof_funcptr (call_site);
2081
2082   GST_CAT_DEBUG (GST_CAT_CALL_TRACE, "entering function %s from %s", name,
2083       site);
2084   stack_trace =
2085       g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)",
2086           this_fn, name, call_site, site));
2087
2088   g_free (name);
2089   g_free (site);
2090 }
2091
2092 void
2093 __cyg_profile_func_exit (void *this_fn, void *call_site)
2094     G_GNUC_NO_INSTRUMENT;
2095      void __cyg_profile_func_exit (void *this_fn, void *call_site)
2096 {
2097   gchar *name = _gst_debug_nameof_funcptr (this_fn);
2098
2099   GST_CAT_DEBUG (GST_CAT_CALL_TRACE, "leaving function %s", name);
2100   g_free (stack_trace->data);
2101   stack_trace = g_slist_delete_link (stack_trace, stack_trace);
2102
2103   g_free (name);
2104 }
2105
2106 /**
2107  * gst_debug_print_stack_trace:
2108  *
2109  * If GST_ENABLE_FUNC_INSTRUMENTATION is defined a stacktrace is available for
2110  * gstreamer code, which can be printed with this function.
2111  */
2112 void
2113 gst_debug_print_stack_trace (void)
2114 {
2115   GSList *walk = stack_trace;
2116   gint count = 0;
2117
2118   if (walk)
2119     walk = g_slist_next (walk);
2120
2121   while (walk) {
2122     gchar *name = (gchar *) walk->data;
2123
2124     g_print ("#%-2d %s\n", count++, name);
2125
2126     walk = g_slist_next (walk);
2127   }
2128 }
2129 #else
2130 void
2131 gst_debug_print_stack_trace (void)
2132 {
2133   /* nothing because it's compiled out */
2134 }
2135
2136 #endif /* GST_ENABLE_FUNC_INSTRUMENTATION */