FFmpeg源码学习笔记:日志分级打印是怎么实现的


前言

上一篇博客介绍了怎么控制FFmpeg输出的调试打印信息,本文简单总结下源码中对应的关键实现,并提供了升级版的打印函数,能打印文件名/行号/函数名等信息。


一、FFmpeg的打印函数av_log

FFmpeg使用自定义的av_log进行打印,函数实现在源码libavutil/log.c文件中,能够达到的效果包括:
1、颜色显示:不同打印等级对应不同的颜色,一目了然;
2、日志分级:通过设定打印等级,可以管理输出的日志信息。
av_log函数的调用关系如下,可见最终还是调用了我们熟悉的打印函数fprintf、fputs。

├── av_log
│   ├── av_vlog
│      ├── av_log_callback
│         ├── av_log_default_callback
│            ├── format_line
│            ├── colored_fputs
│                  ├── ansi_fputs
│                     ├── fprintf
│                     ├── fputs

二、av_log的具体实现

1.颜色显示

代码如下:

static void ansi_fputs(int level, int tint, const char *str, int local_use_color)
{
	//16色方案
    if (local_use_color == 1) {
        fprintf(stderr,
                "\033[%"PRIu32";3%"PRIu32"m%s\033[0m",
                (color[level] >> 4) & 15,
                color[level] & 15,
                str);
    }
    //256色方案 
    else if (tint && use_color == 256) {
        fprintf(stderr,
                "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m",
                (color[level] >> 16) & 0xff,
                tint,
                str);
    } else if (local_use_color == 256) {
        fprintf(stderr,
                "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m",
                (color[level] >> 16) & 0xff,
                (color[level] >> 8) & 0xff,
                str);
    } else
        fputs(str, stderr);
}

这里涉及printf输出增加颜色的基础知识,有几篇参考博客介绍的很详细。
printf 彩色输出:16色输出
printf输出到终端的颜色设定:涉及256色输出
颜色(ASCII color):涉及256色输出

此处引用参考文献图片并总结如下,其中:
16色
在这里插入图片描述
典型用法为

printf("\033[1;31;40m %s \033[0m", "red");  //红色
printf("\033[1;32;40m %s \033[0m", "green"); //绿色
printf("\033[1;33;40m %s \033[0m", "yellow"); //黄色

256色
在这里插入图片描述
典型用法为:

//具体背景的160和前景的231对应什么颜色,在第3篇博客里有张色卡可以查
printf("\033[48;5;160m\033[38;5;231m背景前景修改ABCDE\033[0;0m");

2.日志分级

代码如下:

void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
{
	//打印等级大于av_log_level,直接return,这就不会输出打印了
    if (level > av_log_level)
        return;
	
	//中间省略

	//按照打印格式组织数据
    format_line(ptr, level, fmt, vl, part, &print_prefix, type);

	//中间省略

	//调用colored_fputs函数打印
    colored_fputs(type[0], 0, part[0].str);
    colored_fputs(type[1], 0, part[1].str);
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);

	//中间省略
}

其中,av_log_level是一个全局静态变量,默认等级是AV_LOG_INFO

static int av_log_level = AV_LOG_INFO;

//获取当前打印等级
int av_log_get_level(void)
{
    return av_log_level;
}

//设置当前打印等级
void av_log_set_level(int level)
{
    av_log_level = level;
}

显而易见,ffmpeg工具会通过解析命令行获取loglevel参数,进而修改代码中av_log_level的值,实现控制打印等级的目的。

三、av_log魔改版

1.打印时能显示文件名、行号、函数名

在源码libavutil/log.h中找到av_log的声明如下:

/**
 * 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 or NULL if general log.
 * @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, ...) av_printf_format(3, 4);

新增宏定义如下

#define MY_AV_LOG(avcl, level, fmt, args, ...) av_log(avcl, level, "[%12s|%12s|%4d]"fmt, __FILE__, __LINE__, __func__, ##args)

将代码中调用av_log打印的地方,使用MY_AV_LOG替换即可,如:

MY_AV_LOG(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);

总结

本文记录了FFmpeg源码中日志分级打印的实现方式,并提供了升级版的打印函数,可输出文件名/行号/函数名等信息。调试源码时能根据打印信息定位到具体位置,可以说是相当方便了。

  • 35
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值