20 ffmpeg中的log分析

每个后台进程的日志很重要的,实现的文件在log.c/log.h。FFmpeg的日志在实现上有一些小细节是我以前从来没有考虑过的,譬如颜色,是否重复等。但还是很简单滴。

先上使用方式:

av_log(obj, AV_LOG_ERROR, "Value %lf for parameter '%s' out of range\n", num, name);

声明:

/**
 * @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, lower values signifying
 * higher importance.
 * @param fmt The format string (printf-compatible) that specifies how
 * subsequent arguments are converted to output.
 * @see av_vlog
 */
void av_log(void *avcl, int level, const char *fmt, ...);

avcl是指向AVClass的指针,这个和其他的日志有区别。这是为了区分打印的AVClass,但是没打印时间戳哦。level是日志级别。

#define AV_LOG_PANIC     0
#define AV_LOG_FATAL     8
#define AV_LOG_ERROR    16
#define AV_LOG_WARNING  24
#define AV_LOG_INFO     32
#define AV_LOG_VERBOSE  40
#define AV_LOG_DEBUG    48

级别越高数据越小。但是这些宏的值为什么不连续呢?在av_log中有level的运算逻辑,这谁能看懂啊。不管啦。

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)
{
    av_log_callback(avcl, level, fmt, vl);
}

void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
{
    av_log_callback = callback;
}

真正实现打印的是回调函数,回调函数是可以设置的。那就看默认的回调函数是什么呢?

av_log_default_callback是默认的回调函数。逻辑上主要三部分:是否打印,也就是level判断;后进行内容拷贝,最后进行打印。


第一部分变量声明,后进行level判断。大于av_log_level才能打印。av_log_level是可以设置的,默认的是:AV_LOG_INFO。宗旨是:级别越高的才打印。在调试的时候,需要把av_log_level设置成debug。对于debug有时打印不出来,必须在config的时候打印debug,nginx就是这样。ffmpeg好像不是哦。如果把av_log_level设置成debug后还不出现debug,则需要看一看在configure时是否需要打开debug选项了。

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[1024];
    char line[1024];
    static int is_atty;
    AVClass* avc= ptr ? *(AVClass**)ptr : NULL;
    if(level>av_log_level)
        return;
    line[0]=0;

cpy内容,最前面有AVClass的item_name。怎么没打印时间呢?FFmpeg对于觉得时间不重要的吗?

#undef fprintf
    if(print_prefix && avc) {
        if (avc->parent_log_context_offset) {
            AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset);
            if(parent && *parent){
                snprintf(line, sizeof(line), "[%s @ %p] ", (*parent)->item_name(parent), parent);
            }
        }
        snprintf(line + strlen(line), sizeof(line) - strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr);
    }

    vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl);

    print_prefix = strlen(line) && line[strlen(line)-1] == '\n';

这才真正的打印。首先判断了是否去掉重复的日志,sanitize函数对于无法打印的字符用问号来代替。colored_fputs输出带有颜色的字符。重点看看这个颜色。

    if(print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev)){
        count++;
        if(is_atty==1)
            fprintf(stderr, "    Last message repeated %d times\r", count);
        return;
    }

    if(count>0){
        fprintf(stderr, "    Last message repeated %d times\n", count);
        count=0;
    }

    strcpy(prev, line);
    sanitize(line);
    colored_fputs(av_clip(level>>3, 0, 6), line);
}

颜色打印的实现。我还第一次看这个的实现啦。分成三步:先判断是否需要user color,后set color再fputs,最后reset。

static void colored_fputs(int level, const char *str){
    if(use_color<0){
        use_color= getenv("FFMPEG_FORCE_COLOR") && !getenv("NO_COLOR") && !getenv("FFMPEG_FORCE_NOCOLOR");

    if(use_color){
        set_color(level);
    }
    fputs(str, stderr);
    if(use_color){
        reset_color();
    }
}

最后看一下set color,linux和win是不同的实现。下面的是linux的:

static const uint8_t color[]={0x41,0x41,0x11,0x03,9,9,9};
#define set_color(x)  fprintf(stderr, "\033[%d;3%dm", color[x]>>4, color[x]&15)
#define reset_color() fprintf(stderr, "\033[0m")

那这个默认的功能有了,那如果要输出到文件中呢?新版本的ffplay是可以输出到文件中的,我分析的代码是ffmpeg-0.8,没有打印到文件中。如果想输出到文件,需要重新设置日志打印函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值