我是靠谱客的博主 外向西牛,最近开发中收集的这篇文章主要介绍ffmpeg-日志系统,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

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

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 supportedn”),内部发生了什么?

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

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

整一个调用的关键部分大概就是上述那样,下面拆解分析:
av_log_default_callback—-这是一个回调函数,支持用户自定义,一般情况下都是使用源码默认的。
这个函数有一个声明AVBPrint part[4];
也就是说输出的日志信息是由四个部分组成,通常情况下,主要使用到第一部分和第四部分,也就是part[1]和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 )                            // 将指针置为无效

总结:读取可变参数的过程其实就是堆栈中,使用指针,遍历堆栈段中的参数列表

最后

以上就是外向西牛为你收集整理的ffmpeg-日志系统的全部内容,希望文章能够帮你解决ffmpeg-日志系统所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部