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