void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) { static int print_prefix = 1; static int count; static char prev[LINE_SZ]; AVBPrint part[4]; char line[LINE_SZ]; static int is_atty; int type[2]; unsigned tint = 0; if (level >= 0) { tint = level & 0xff00; level &= 0xff; } if (level > av_log_level) return; #if HAVE_PTHREADS pthread_mutex_lock(&mutex); #endif format_line(ptr, level, fmt, vl, part, &print_prefix, type); snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); #if HAVE_ISATTY if (!is_atty) is_atty = isatty(2) ? 1 : -1; #endif if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) && *line && line[strlen(line) - 1] != '\r'){ count++; if (is_atty == 1) fprintf(stderr, " Last message repeated %d times\r", count); goto end; } if (count > 0) { fprintf(stderr, " Last message repeated %d times\n", count); count = 0; } strcpy(prev, line); sanitize(part[0].str); colored_fputs(type[0], 0, part[0].str); sanitize(part[1].str); colored_fputs(type[1], 0, part[1].str); sanitize(part[2].str); colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str); sanitize(part[3].str); colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str); #if CONFIG_VALGRIND_BACKTRACE if (level <= BACKTRACE_LOGLEVEL) VALGRIND_PRINTF_BACKTRACE("%s", ""); #endif end: av_bprint_finalize(part+3, NULL); #if HAVE_PTHREADS pthread_mutex_unlock(&mutex); #endif } static void (*av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback; void av_log(void* avcl, int level, const char *fmt, ...) { AVClass* avc = avcl ? *(AVClass **) avcl : NULL; va_list vl; va_start(vl, fmt); if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) && avc->log_level_offset_offset && level >= AV_LOG_FATAL) level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset); av_vlog(avcl, level, fmt, vl); va_end(vl); } void av_vlog(void* avcl, int level, const char *fmt, va_list vl) { void (*log_callback)(void*, int, const char*, va_list) = av_log_callback; if (log_callback) log_callback(avcl, level, fmt, vl); }
在libavutil/bprint.h,即app
#define FF_PAD_STRUCTURE(name, size, ...) \ struct ff_pad_helper_##name { __VA_ARGS__ }; \ typedef struct name { \ __VA_ARGS__ \ char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \ } name; /** * Buffer to print data progressively * * The string buffer grows as necessary and is always 0-terminated. * The content of the string is never accessed, and thus is * encoding-agnostic and can even hold binary data. * * Small buffers are kept in the structure itself, and thus require no * memory allocation at all (unless the contents of the buffer is needed * after the structure goes out of scope). This is almost as lightweight as * declaring a local "char buf[512]". * * The length of the string can go beyond the allocated size: the buffer is * then truncated, but the functions still keep account of the actual total * length. * * In other words, buf->len can be greater than buf->size and records the * total length of what would have been to the buffer if there had been * enough memory. * * Append operations do not need to be tested for failure: if a memory * allocation fails, data stop being appended to the buffer, but the length * is still updated. This situation can be tested with * av_bprint_is_complete(). * * The size_max field determines several possible behaviours: * * size_max = -1 (= UINT_MAX) or any large value will let the buffer be * reallocated as necessary, with an amortized linear cost. * * size_max = 0 prevents writing anything to the buffer: only the total * length is computed. The write operations can then possibly be repeated in * a buffer with exactly the necessary size * (using size_init = size_max = len + 1). * * size_max = 1 is automatically replaced by the exact size available in the * structure itself, thus ensuring no dynamic memory allocation. The * internal buffer is large enough to hold a reasonable paragraph of text, * such as the current paragraph. */ FF_PAD_STRUCTURE(AVBPrint, 1024, char *str; /**< string so far */ unsigned len; /**< length so far */ unsigned size; /**< allocated memory */ unsigned size_max; /**< maximum allocated memory */ char reserved_internal_buffer[1]; )
即獲得結構體AVBPrint的定義:less
struct ff_pad_helper_AVBPrint{ char *str; /**< string so far */ unsigned len; /**< length so far */ unsigned size; /**< allocated memory */ unsigned size_max; /**< maximum allocated memory */ char reserved_internal_buffer[1]; } typedef struct AVBPrint { char *str; /**< string so far */ unsigned len; /**< length so far */ unsigned size; /**< allocated memory */ unsigned size_max; /**< maximum allocated memory */ char reserved_internal_buffer[1]; char reserved_padding[size - sizeof(struct ff_pad_helper_ AVBPrint )]; } AVBPrint
格式化日誌數據函數
static void format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix, int type[2]) { AVClass* avc = avcl ? *(AVClass **) avcl : NULL; av_bprint_init(part+0, 0, 1); av_bprint_init(part+1, 0, 1); av_bprint_init(part+2, 0, 1); av_bprint_init(part+3, 0, 65536); if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16; if (*print_prefix && avc) { if (avc->parent_log_context_offset) { AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) + avc->parent_log_context_offset); if (parent && *parent) { av_bprintf(part+0, "[%s @ %p] ", (*parent)->item_name(parent), parent); if(type) type[0] = get_category(parent); } } av_bprintf(part+1, "[%s @ %p] ", avc->item_name(avcl), avcl); if(type) type[1] = get_category(avcl); if (flags & AV_LOG_PRINT_LEVEL) av_bprintf(part+2, "[%s] ", get_level_str(level)); } av_vbprintf(part+3, fmt, vl); if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) { char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0; *print_prefix = lastc == '\n' || lastc == '\r'; } }
對於打印信息進行處理ui
static void sanitize(uint8_t *line){ while(*line){ if(*line < 0x08 || (*line > 0x0D && *line < 0x20)) *line='?'; line++; } }
以帶顏色的方式輸出到屏幕spa
static void colored_fputs(int level, int tint, const char *str) { int local_use_color; if (!*str) return; if (use_color < 0) check_color_terminal(); if (level == AV_LOG_INFO/8) local_use_color = 0; else local_use_color = use_color; #if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE if (local_use_color) SetConsoleTextAttribute(con, background | color[level]); fputs(str, stderr); if (local_use_color) SetConsoleTextAttribute(con, attr_orig); #else if (local_use_color == 1) { fprintf(stderr, "\033[%d;3%dm%s\033[0m", (color[level] >> 4) & 15, color[level] & 15, str); } else if (tint && use_color == 256) { fprintf(stderr, "\033[48;5;%dm\033[38;5;%dm%s\033[0m", (color[level] >> 16) & 0xff, tint, str); } else if (local_use_color == 256) { fprintf(stderr, "\033[48;5;%dm\033[38;5;%dm%s\033[0m", (color[level] >> 16) & 0xff, (color[level] >> 8) & 0xff, str); } else fputs(str, stderr); #endif }
static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl) { va_list vl2; char line[1024]; static int print_prefix = 1; va_copy(vl2, vl); av_log_default_callback(ptr, level, fmt, vl); av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); va_end(vl2); if (report_file_level >= level) { fputs(line, report_file); fflush(report_file); } }
註釋:日誌
1. 寫入文件時,打印數據不區分顏色code
2. 輸出到屏幕時,會根據參數決定輸出的顏色orm