【版权申明】转载请附上出处链接
ffmpeg里面的av_log实现
话不多说,直接上demo:
#include <stdio.h>
#include <libavutil/log.h>
/**
* Print no output.
*/
#define AV_LOG_QUIET -8
/**
* Something went really wrong and we will crash now.
*/
#define AV_LOG_PANIC 0
/**
* Something went wrong and recovery is not possible.
* For example, no header was found for a format which depends
* on headers or an illegal combination of parameters is used.
*/
#define AV_LOG_FATAL 8
/**
* Something went wrong and cannot losslessly be recovered.
* However, not all future data is affected.
*/
#define AV_LOG_ERROR 16
/**
* Something somehow does not look correct. This may or may not
* lead to problems. An example would be the use of '-vstrict -2'.
*/
#define AV_LOG_WARNING 24
/**
* Standard information.
*/
#define AV_LOG_INFO 32
/**
* Detailed information.
*/
#define AV_LOG_VERBOSE 40
/**
* Stuff which is only useful for libav* developers.
*/
#define AV_LOG_DEBUG 48
/**
* Extremely verbose debugging, useful for libav* development.
*/
#define AV_LOG_TRACE 56
#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET)
int main(int argc, char *argv[])
{
av_log_set_level(AV_LOG_MAX_OFFSET);
av_log(NULL, AV_LOG_MAX_OFFSET, "AV_LOG_MAX_OFFSET\n");
av_log(NULL, AV_LOG_TRACE, "AV_LOG_TRACE\n");
av_log(NULL, AV_LOG_DEBUG, "AV_LOG_DEBUG\n");
av_log(NULL, AV_LOG_VERBOSE, "AV_LOG_VERBOSE\n");
av_log(NULL, AV_LOG_INFO, "AV_LOG_INFO\n");
av_log(NULL, AV_LOG_WARNING, "AV_LOG_WARNING\n");
av_log(NULL, AV_LOG_ERROR, "AV_LOG_ERROR\n");
av_log(NULL, AV_LOG_FATAL, "AV_LOG_FATAL\n");
av_log(NULL, AV_LOG_PANIC, "AV_LOG_PANIC\n");
av_log(NULL, AV_LOG_QUIET, "AV_LOG_QUIET\n");
return 0;
}
效果如下:
av_log_set_level(AV_LOG_MAX_OFFSET);
static int av_log_level = AV_LOG_INFO;
void av_log_set_level(int level)
{
av_log_level = level;
}
赋值,修改全局变量av_log_level的值,可猜测得知小于这个数时这个av_log将会被打印出来。
av_log(NULL, AV_LOG_DEBUG, "AV_LOG_DEBUG\n");
/**
* Send the specified message to the log if the level is less than or equal
* to the current av_log_level. By default, all logging messages are sent to
* stderr. This behavior can be altered by setting a different logging callback
* function.
* @see av_log_set_callback
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
* pointer to an AVClass struct.
* @param level The importance level of the message expressed using a @ref
* lavu_log_constants "Logging Constant".
* @param fmt The format string (printf-compatible) that specifies how
* subsequent arguments are converted to output.
*/
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);
}
我们把avc1=NULL代入时,函数得到进一步的精简(因为我现在还不知道avc1怎么用,所以先放着):
void av_log(void* avcl, int level, const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
av_vlog(avcl, level, fmt, vl);
va_end(vl);
}
插入小知识:va_list变量、va_start()/va_arg()/va_end()函数的讲解~
#include <stdio.h>
#include<stdarg.h>
// va_list实现不定参数C函数
void func(const char *fmt, ...)
{
va_list vl; // 定义va_list变量vl,该变量是指向可变参数的指针
char *value_str;
int value_int;
va_start(vl, fmt); // 参数1:va_list变量vl; 参数2:函数参数的最后一个可变参数变量名,即这里的fmt
value_str = va_arg(vl, char *); //参数1:va_list变量vl; 参数2:可变参数的类型,返回值即为可变参数的数值(va_arg()之后会自动加1指向下一个arg,且va_arg()从可变参数的第1个参数开始,即这里的"haha")
value_int = va_arg(vl, int);
printf("value_str=%s, value_int=%d \n", value_str, value_int);
va_end(vl); // 结束可变参数的获取
}
int main(int argc, char **argv)
{
func("第0个参数用于标识后面的参数类型顺序,供函数中的fmt使用,详情:man va_arg看示例", "haha", 100);
return 0;
}
结果为:
value_str=haha, value_int=60
回到我们的av_vlog(avcl, level, fmt, vl);
static void (*av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback;
av_vlog(void* avcl, int level, const char *fmt, va_list vl)
void (*log_callback)(void*, int, const char*, va_list) = av_log_callback;
av_log_default_callback(avcl, level, fmt, vl);
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) // 当level大于我们所设置的av_log_level,这个log将不会被显示,在这里被直接返回了。
return;
ff_mutex_lock(&mutex);
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);
ff_mutex_unlock(&mutex);
}