ffmpeg-日志系统

来源:互联网 发布:mac 删除文件夹的命令 编辑:程序博客网 时间:2024/06/04 01:19

一、ffmpeg的日志系统,个人感觉主要好在以下几个方面:
1.有颜色输出
2.标志输出的日志信息属于哪一个模块
3.输出信息的日志等级可控。也就是说通过控制,输出的日志信息内容会不同

二、 简单分析ffmpeg日志系统的处理机制:
2.1、 例如,当命令是-loglevel trace时,ffmpeg内部是怎样处理的?
av_log(avctx, AV_LOG_VERBOSE, “Codec not supported\n”);执行这一行代码,内部发生什么?

int main(int argc, char **argv){ .....    /*与重复信息的处理有关*/    av_log_set_flags(AV_LOG_SKIP_REPEATED);    /*解析设置loglevel的命令*/    parse_loglevel(argc, argv, options);  ..... }
void parse_loglevel(int argc, char **argv, const OptionDef *options){    /*查找匹配命令     *命令会在数组const OptionDef options[] 查找----ffmpeg_opt.c     */    int idx = locate_option(argc, argv, options, "loglevel");    const char *env;    check_options(options);    if (!idx)        idx = locate_option(argc, argv, options, "v");    /*设置loglevel命令*/    if (idx && argv[idx + 1])        opt_loglevel(NULL, "loglevel", argv[idx + 1]);    /*这里涉及到report和hide_banner的处理*/    idx = locate_option(argc, argv, options, "report");    if ((env = getenv("FFREPORT")) || idx) {        init_report(env);        if (report_file) {            int i;            fprintf(report_file, "Command line:\n");            for (i = 0; i < argc; i++) {                dump_argument(argv[i]);                fputc(i < argc - 1 ? ' ' : '\n', report_file);            }            fflush(report_file);        }    }    idx = locate_option(argc, argv, options, "hide_banner");    if (idx)        hide_banner = 1;}
为了阅读,省略部分代码int opt_loglevel(void *optctx, const char *opt, const char *arg){    /*日志等级,从上往下看,等级越靠前,代表输出信息等级高     *输出信息可控的意思就是,如果设置AV_LOG_FATAL等级,那么     *AV_LOG_DEBUG等级的日志信息不会输出;     *如果设置日志等级AV_LOG_DEBUG,     *AV_LOG_DEBUG前面等级的日志信息都会输出     */     const struct { const char *name; int level; } log_levels[] = {        { "quiet"  , AV_LOG_QUIET   },        { "panic"  , AV_LOG_PANIC   },        { "fatal"  , AV_LOG_FATAL   },        { "error"  , AV_LOG_ERROR   },        { "warning", AV_LOG_WARNING },        { "info"   , AV_LOG_INFO    },        { "verbose", AV_LOG_VERBOSE },        { "debug"  , AV_LOG_DEBUG   },        { "trace"  , AV_LOG_TRACE   },    };........     /*匹配,调用设置av_log_set_level*/    for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {        if (!strcmp(log_levels[i].name, arg)) {            av_log_set_level(log_levels[i].level);            return 0;        }    }  ....... }

这样就把日志等级给设置上了,-loglevel trace这个命令的最终结果就是执行
av_log_set_level(AV_LOG_TRACE)

从这里开始就开始进入libavutil/log.c这个文件,日志系统的处理集中在这个文件

void av_log_set_level(int level){    av_log_level = level;}av_log_level是一个全局变量

2.2、讲完了日志等级的设置,简单分析 执行 av_log(avctx, AV_LOG_VERBOSE, “Codec not supported\n”),内部发生了什么?

由于涉及的源码较多,简单的梳理调用流程,细节稍后看下面的链接 。
调用流程。从上往下依次调用

  av_log    av_vlog        av_log_default_callback  ---主要是对AVBPrint结构体的处理             format_line   --------------格式控制                 av_bprintf(part+0, "[%s @ %p"----模块信息                 av_vbprintf(part+3, fmt, vl); ---主要信息             colored_fputs  ----------给数据上色,颜色输出  

整一个调用的关键部分大概就是上述那样,下面拆解分析:
av_log_default_callback—-这是一个回调函数,支持用户自定义,一般情况下都是使用源码默认的。
这个函数有一个声明AVBPrint part[4];
也就是说输出的日志信息是由四个部分组成,通常情况下,主要使用到第一部分和第四部分,也就是part[0]和part[3]
这个函数主要是调用format_line,对AVBPrint结构体的处理。

format_line ———关键函数
对AVBPrint结构体的处理,处理AVBPrint part[4],规定日志信息的输出格式。

colored_fputs ———-给数据上色,颜色输出
/////////一般的颜色关系
\e[30m – \e[37m 设置前景色(字体颜色)
echo -e “\e[30m” 灰色
echo -e “\e[31m” 红色
echo -e “\e[32m” 绿色
echo -e “\e[33m” 黄色
echo -e “\e[34m” 蓝色
echo -e “\e[35m” 紫色
echo -e “\e[36m” 淡蓝色
echo -e “\e[37m” 白色

\e[40m – \e[47m 设置背景色
echo -e “\e[40m” 灰色
echo -e “\e[41m” 红色
echo -e “\e[42m” 绿色
echo -e “\e[43m” 黄色
echo -e “\e[44m” 蓝色
echo -e “\e[45m” 紫色
echo -e “\e[46m” 淡蓝色
echo -e “\e[47m” 白色

总结整一个日志系统的处理思路:
1. 将要打印的信息分为四部分,第四部分就是用户想要打印的信息,其他三部分就是源码为了查阅方便,自我添加额外的输出信息
2.之后就是把传进来的打印信息用stdarg这个库的接口处理好
3.给打印信息上色
4.优化,控制打印的输出内容

if (level > av_log_level)        return;

http://blog.csdn.net/leixiaohua1020/article/details/44243155 —–日志输入系统详细介绍

常用stdarg这个库接口简单说明

#define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )           //第一个可选参数地址#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址#define va_end(ap)    ( ap = (va_list)0 )                            // 将指针置为无效总结:读取可变参数的过程其实就是堆栈中,使用指针,遍历堆栈段中的参数列表
0 0
原创粉丝点击