summaryrefslogtreecommitdiff
path: root/libavutil/log.c (plain)
blob: a29668f4ccc4deb2d79f13977139cf88300c187f
1/*
2 * log functions
3 * Copyright (c) 2003 Michel Bardiaux
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * logging functions
25 */
26
27#include "config.h"
28
29#if HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#if HAVE_IO_H
33#include <io.h>
34#endif
35#include <stdarg.h>
36#include <stdlib.h>
37#include "avutil.h"
38#include "bprint.h"
39#include "common.h"
40#include "internal.h"
41#include "log.h"
42
43#if HAVE_PTHREADS
44#include <pthread.h>
45static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
46#endif
47
48#define LINE_SZ 1024
49
50#if HAVE_VALGRIND_VALGRIND_H
51#include <valgrind/valgrind.h>
52/* this is the log level at which valgrind will output a full backtrace */
53#define BACKTRACE_LOGLEVEL AV_LOG_ERROR
54#endif
55#ifdef __ANDROID__
56static int av_log_level = AV_LOG_ERROR;
57#else
58static int av_log_level = AV_LOG_INFO;
59#endif
60static int flags;
61
62#define NB_LEVELS 8
63#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
64#include <windows.h>
65static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = {
66 [AV_LOG_PANIC /8] = 12,
67 [AV_LOG_FATAL /8] = 12,
68 [AV_LOG_ERROR /8] = 12,
69 [AV_LOG_WARNING/8] = 14,
70 [AV_LOG_INFO /8] = 7,
71 [AV_LOG_VERBOSE/8] = 10,
72 [AV_LOG_DEBUG /8] = 10,
73 [AV_LOG_TRACE /8] = 8,
74 [16+AV_CLASS_CATEGORY_NA ] = 7,
75 [16+AV_CLASS_CATEGORY_INPUT ] = 13,
76 [16+AV_CLASS_CATEGORY_OUTPUT ] = 5,
77 [16+AV_CLASS_CATEGORY_MUXER ] = 13,
78 [16+AV_CLASS_CATEGORY_DEMUXER ] = 5,
79 [16+AV_CLASS_CATEGORY_ENCODER ] = 11,
80 [16+AV_CLASS_CATEGORY_DECODER ] = 3,
81 [16+AV_CLASS_CATEGORY_FILTER ] = 10,
82 [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 9,
83 [16+AV_CLASS_CATEGORY_SWSCALER ] = 7,
84 [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 7,
85 [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 13,
86 [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 5,
87 [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 13,
88 [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 5,
89 [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 13,
90 [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 5,
91};
92
93static int16_t background, attr_orig;
94static HANDLE con;
95#else
96
97static const uint32_t color[16 + AV_CLASS_CATEGORY_NB] = {
98 [AV_LOG_PANIC /8] = 52 << 16 | 196 << 8 | 0x41,
99 [AV_LOG_FATAL /8] = 208 << 8 | 0x41,
100 [AV_LOG_ERROR /8] = 196 << 8 | 0x11,
101 [AV_LOG_WARNING/8] = 226 << 8 | 0x03,
102 [AV_LOG_INFO /8] = 253 << 8 | 0x09,
103 [AV_LOG_VERBOSE/8] = 40 << 8 | 0x02,
104 [AV_LOG_DEBUG /8] = 34 << 8 | 0x02,
105 [AV_LOG_TRACE /8] = 34 << 8 | 0x07,
106 [16+AV_CLASS_CATEGORY_NA ] = 250 << 8 | 0x09,
107 [16+AV_CLASS_CATEGORY_INPUT ] = 219 << 8 | 0x15,
108 [16+AV_CLASS_CATEGORY_OUTPUT ] = 201 << 8 | 0x05,
109 [16+AV_CLASS_CATEGORY_MUXER ] = 213 << 8 | 0x15,
110 [16+AV_CLASS_CATEGORY_DEMUXER ] = 207 << 8 | 0x05,
111 [16+AV_CLASS_CATEGORY_ENCODER ] = 51 << 8 | 0x16,
112 [16+AV_CLASS_CATEGORY_DECODER ] = 39 << 8 | 0x06,
113 [16+AV_CLASS_CATEGORY_FILTER ] = 155 << 8 | 0x12,
114 [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 192 << 8 | 0x14,
115 [16+AV_CLASS_CATEGORY_SWSCALER ] = 153 << 8 | 0x14,
116 [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 147 << 8 | 0x14,
117 [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 213 << 8 | 0x15,
118 [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 207 << 8 | 0x05,
119 [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 213 << 8 | 0x15,
120 [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 207 << 8 | 0x05,
121 [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 213 << 8 | 0x15,
122 [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 207 << 8 | 0x05,
123};
124
125#endif
126
127#ifdef __ANDROID__
128
129#include <android/log.h>
130static int use_log_report = 0;
131
132
133#define FF_LOG_TAG "exFFmpeg"
134
135
136#define FF_LOG_UNKNOWN ANDROID_LOG_UNKNOWN
137#define FF_LOG_DEFAULT ANDROID_LOG_DEFAULT
138
139
140#define FF_LOG_VERBOSE ANDROID_LOG_VERBOSE
141#define FF_LOG_DEBUG ANDROID_LOG_DEBUG
142#define FF_LOG_INFO ANDROID_LOG_INFO
143#define FF_LOG_WARN ANDROID_LOG_WARN
144#define FF_LOG_ERROR ANDROID_LOG_ERROR
145#define FF_LOG_FATAL ANDROID_LOG_FATAL
146#define FF_LOG_SILENT ANDROID_LOG_SILENT
147
148#define ALOG(level, TAG, ...) ((void)__android_log_print(level, TAG, __VA_ARGS__))
149#define ALOGV(...) ALOG(FF_LOG_VERBOSE, FF_LOG_TAG, __VA_ARGS__)
150#define ALOGD(...) ALOG(FF_LOG_DEBUG, FF_LOG_TAG, __VA_ARGS__)
151#define ALOGI(...) ALOG(FF_LOG_INFO, FF_LOG_TAG, __VA_ARGS__)
152#define ALOGW(...) ALOG(FF_LOG_WARN, FF_LOG_TAG, __VA_ARGS__)
153#define ALOGE(...) ALOG(FF_LOG_ERROR, FF_LOG_TAG, __VA_ARGS__)
154
155#define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, FF_LOG_TAG, format, ##__VA_ARGS__)
156#define LOGI(format, ...) __android_log_print(ANDROID_LOG_INFO, FF_LOG_TAG, format, ##__VA_ARGS__)
157
158static void android_log_callback(void *ptr, int level, const char *fmt, va_list vl)
159{
160 if (level > av_log_get_level())
161 return;
162 int ffplv = FF_LOG_VERBOSE;
163 if (level <= AV_LOG_ERROR)
164 ffplv = FF_LOG_ERROR;
165 else if (level <= AV_LOG_WARNING)
166 ffplv = FF_LOG_WARN;
167 else if (level <= AV_LOG_INFO)
168 ffplv = FF_LOG_INFO;
169 else if (level <= AV_LOG_VERBOSE)
170 ffplv = FF_LOG_VERBOSE;
171 else
172 ffplv = FF_LOG_DEBUG;
173
174
175 va_list vl2;
176 char line[1024];
177 static int print_prefix = 1;
178
179
180 va_copy(vl2, vl);
181 // av_log_default_callback(ptr, level, fmt, vl);
182 av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
183 va_end(vl2);
184
185
186 ALOG(ffplv, FF_LOG_TAG, "%s", line);
187}
188#endif
189
190static int use_color = -1;
191
192static void check_color_terminal(void)
193{
194#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
195 CONSOLE_SCREEN_BUFFER_INFO con_info;
196 con = GetStdHandle(STD_ERROR_HANDLE);
197 use_color = (con != INVALID_HANDLE_VALUE) && !getenv("NO_COLOR") &&
198 !getenv("AV_LOG_FORCE_NOCOLOR");
199 if (use_color) {
200 GetConsoleScreenBufferInfo(con, &con_info);
201 attr_orig = con_info.wAttributes;
202 background = attr_orig & 0xF0;
203 }
204#elif HAVE_ISATTY
205 char *term = getenv("TERM");
206 use_color = !getenv("NO_COLOR") && !getenv("AV_LOG_FORCE_NOCOLOR") &&
207 (getenv("TERM") && isatty(2) || getenv("AV_LOG_FORCE_COLOR"));
208 if ( getenv("AV_LOG_FORCE_256COLOR")
209 || (term && strstr(term, "256color")))
210 use_color *= 256;
211#else
212 use_color = getenv("AV_LOG_FORCE_COLOR") && !getenv("NO_COLOR") &&
213 !getenv("AV_LOG_FORCE_NOCOLOR");
214#endif
215}
216
217static void colored_fputs(int level, int tint, const char *str)
218{
219 int local_use_color;
220 if (!*str)
221 return;
222
223 if (use_color < 0)
224 check_color_terminal();
225
226 if (level == AV_LOG_INFO/8) local_use_color = 0;
227 else local_use_color = use_color;
228
229#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
230 if (local_use_color)
231 SetConsoleTextAttribute(con, background | color[level]);
232 fputs(str, stderr);
233 if (local_use_color)
234 SetConsoleTextAttribute(con, attr_orig);
235#else
236 if (local_use_color == 1) {
237 fprintf(stderr,
238 "\033[%"PRIu32";3%"PRIu32"m%s\033[0m",
239 (color[level] >> 4) & 15,
240 color[level] & 15,
241 str);
242 } else if (tint && use_color == 256) {
243 fprintf(stderr,
244 "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m",
245 (color[level] >> 16) & 0xff,
246 tint,
247 str);
248 } else if (local_use_color == 256) {
249 fprintf(stderr,
250 "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m",
251 (color[level] >> 16) & 0xff,
252 (color[level] >> 8) & 0xff,
253 str);
254 } else
255 fputs(str, stderr);
256#endif
257
258}
259
260const char *av_default_item_name(void *ptr)
261{
262 return (*(AVClass **) ptr)->class_name;
263}
264
265AVClassCategory av_default_get_category(void *ptr)
266{
267 return (*(AVClass **) ptr)->category;
268}
269
270static void sanitize(uint8_t *line){
271 while(*line){
272 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
273 *line='?';
274 line++;
275 }
276}
277
278static int get_category(void *ptr){
279 AVClass *avc = *(AVClass **) ptr;
280 if( !avc
281 || (avc->version&0xFF)<100
282 || avc->version < (51 << 16 | 59 << 8)
283 || avc->category >= AV_CLASS_CATEGORY_NB) return AV_CLASS_CATEGORY_NA + 16;
284
285 if(avc->get_category)
286 return avc->get_category(ptr) + 16;
287
288 return avc->category + 16;
289}
290
291static const char *get_level_str(int level)
292{
293 switch (level) {
294 case AV_LOG_QUIET:
295 return "quiet";
296 case AV_LOG_DEBUG:
297 return "debug";
298 case AV_LOG_VERBOSE:
299 return "verbose";
300 case AV_LOG_INFO:
301 return "info";
302 case AV_LOG_WARNING:
303 return "warning";
304 case AV_LOG_ERROR:
305 return "error";
306 case AV_LOG_FATAL:
307 return "fatal";
308 case AV_LOG_PANIC:
309 return "panic";
310 default:
311 return "";
312 }
313}
314
315static void format_line(void *avcl, int level, const char *fmt, va_list vl,
316 AVBPrint part[4], int *print_prefix, int type[2])
317{
318 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
319 av_bprint_init(part+0, 0, 1);
320 av_bprint_init(part+1, 0, 1);
321 av_bprint_init(part+2, 0, 1);
322 av_bprint_init(part+3, 0, 65536);
323
324 if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
325 if (*print_prefix && avc) {
326 if (avc->parent_log_context_offset) {
327 AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
328 avc->parent_log_context_offset);
329 if (parent && *parent) {
330 av_bprintf(part+0, "[%s @ %p] ",
331 (*parent)->item_name(parent), parent);
332 if(type) type[0] = get_category(parent);
333 }
334 }
335 av_bprintf(part+1, "[%s @ %p] ",
336 avc->item_name(avcl), avcl);
337 if(type) type[1] = get_category(avcl);
338
339 if (flags & AV_LOG_PRINT_LEVEL)
340 av_bprintf(part+2, "[%s] ", get_level_str(level));
341 }
342
343 av_vbprintf(part+3, fmt, vl);
344
345 if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
346 char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
347 *print_prefix = lastc == '\n' || lastc == '\r';
348 }
349}
350
351void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
352 char *line, int line_size, int *print_prefix)
353{
354 av_log_format_line2(ptr, level, fmt, vl, line, line_size, print_prefix);
355}
356
357int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
358 char *line, int line_size, int *print_prefix)
359{
360 AVBPrint part[4];
361 int ret;
362
363 format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
364 ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
365 av_bprint_finalize(part+3, NULL);
366 return ret;
367}
368
369void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
370{
371 static int print_prefix = 1;
372 static int count;
373 static char prev[LINE_SZ];
374 AVBPrint part[4];
375 char line[LINE_SZ];
376 static int is_atty;
377 int type[2];
378 unsigned tint = 0;
379
380 if (level >= 0) {
381 tint = level & 0xff00;
382 level &= 0xff;
383 }
384
385 if (level > av_log_level)
386 return;
387#if HAVE_PTHREADS
388 pthread_mutex_lock(&mutex);
389#endif
390
391 format_line(ptr, level, fmt, vl, part, &print_prefix, type);
392 snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
393
394#if HAVE_ISATTY
395 if (!is_atty)
396 is_atty = isatty(2) ? 1 : -1;
397#endif
398
399 if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) &&
400 *line && line[strlen(line) - 1] != '\r'){
401 count++;
402 if (is_atty == 1)
403 fprintf(stderr, " Last message repeated %d times\r", count);
404 goto end;
405 }
406 if (count > 0) {
407 fprintf(stderr, " Last message repeated %d times\n", count);
408 count = 0;
409 }
410 strcpy(prev, line);
411 sanitize(part[0].str);
412 colored_fputs(type[0], 0, part[0].str);
413 sanitize(part[1].str);
414 colored_fputs(type[1], 0, part[1].str);
415 sanitize(part[2].str);
416 colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);
417 sanitize(part[3].str);
418 colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);
419
420#if CONFIG_VALGRIND_BACKTRACE
421 if (level <= BACKTRACE_LOGLEVEL)
422 VALGRIND_PRINTF_BACKTRACE("%s", "");
423#endif
424end:
425 av_bprint_finalize(part+3, NULL);
426#if HAVE_PTHREADS
427 pthread_mutex_unlock(&mutex);
428#endif
429}
430
431#ifdef __ANDROID__
432static void (*av_log_callback)(void*, int, const char*, va_list) =
433 android_log_callback;
434#else
435static void (*av_log_callback)(void*, int, const char*, va_list) =
436 av_log_default_callback;
437#endif
438
439
440void av_log(void* avcl, int level, const char *fmt, ...)
441{
442 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
443 va_list vl;
444 va_start(vl, fmt);
445 if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) &&
446 avc->log_level_offset_offset && level >= AV_LOG_FATAL)
447 level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset);
448 av_vlog(avcl, level, fmt, vl);
449 va_end(vl);
450}
451
452void av_vlog(void* avcl, int level, const char *fmt, va_list vl)
453{
454 void (*log_callback)(void*, int, const char*, va_list) = av_log_callback;
455 if (log_callback)
456 log_callback(avcl, level, fmt, vl);
457}
458
459int av_log_get_level(void)
460{
461 return av_log_level;
462}
463
464void av_log_set_level(int level)
465{
466 av_log_level = level;
467}
468
469void av_log_set_flags(int arg)
470{
471 flags = arg;
472}
473
474int av_log_get_flags(void)
475{
476 return flags;
477}
478
479void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
480{
481 av_log_callback = callback;
482}
483
484static void missing_feature_sample(int sample, void *avc, const char *msg,
485 va_list argument_list)
486{
487 av_vlog(avc, AV_LOG_WARNING, msg, argument_list);
488 av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg "
489 "version to the newest one from Git. If the problem still "
490 "occurs, it means that your file has a feature which has not "
491 "been implemented.\n");
492 if (sample)
493 av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample "
494 "of this file to ftp://upload.ffmpeg.org/incoming/ "
495 "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n");
496}
497
498void avpriv_request_sample(void *avc, const char *msg, ...)
499{
500 va_list argument_list;
501
502 va_start(argument_list, msg);
503 missing_feature_sample(1, avc, msg, argument_list);
504 va_end(argument_list);
505}
506
507void avpriv_report_missing_feature(void *avc, const char *msg, ...)
508{
509 va_list argument_list;
510
511 va_start(argument_list, msg);
512 missing_feature_sample(0, avc, msg, argument_list);
513 va_end(argument_list);
514}
515