ffmpeg 中 av_log 是怎样工作的?

这篇具有很好参考价值的文章主要介绍了ffmpeg 中 av_log 是怎样工作的?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

----------------------------------------
author: hjjdebug
date:   2023年 07月 27日 星期四 14:56:38 CST
descriptor: ffmpeg 中 av_log 是怎样工作的?
----------------------------------------
av_log 功能其实只是添加了颜色,LOG级别,及log上下文名称,没有添加时间,函数名称,行号等信息.
就这一点就引起了血雨腥风的代码, 记得我第一次看跟不下去,太长,今天就扼要分析一下:
测试代码:

#include <libavutil/avutil.h>

int main()
{
    av_log(NULL,AV_LOG_ERROR,"hello world\n");
    return 0;
}

其调用栈
  #0  av_log_default_callback (ptr=0x0, level=16, fmt=0x555555556004 "hello world\n", vl=0x7fffffffdbd0) at libavutil/log.c:401
  #1  0x00007ffff7d0c2b5 in av_vlog (avcl=0x0, level=16, fmt=0x555555556004 "hello world\n", vl=0x7fffffffdbd0) at libavutil/log.c:432
  #2  0x00007ffff7d0c108 in av_log (avcl=0x0, level=16, fmt=0x555555556004 "hello world\n") at libavutil/log.c:411
  #3  0x000055555555516c in main () at main.c:5

 可变参数为空,所以vl 就不用考虑了. 考察关键函数av_log_default_callback


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]; //LINE_SZ 是1024, prev 是全局变量
    AVBPrint part[4];     //打印被分为4个部分, 演示代码比较简单,只关注part[3]即可,其它全为空
    char line[LINE_SZ]; //LINE_SZ 是1024
    static int is_atty;
    int type[2]; // 它代表了part0,part1的颜色,本测试中未用到
    unsigned tint = 0;

    if (level >= 0) { //AV_LOG_ERROR 值为16
        tint = level & 0xff00; //tint 为0, 字体颜色由颜色表决定,否则由tint决定
        level &= 0xff;            // level 为16
    }

    if (level > av_log_level) //av_log_level 为全局变量 32
        return;
    ff_mutex_lock(&mutex); // 上锁,使支持多线程, 这样下面的处理被锁定,只一个线程使用,不会出现乱码

    format_line(ptr, level, fmt, vl, part, &print_prefix, type); //这是关键函数,把字符串打印到4个part,2个type
    snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); //4个part 合并到line

#if HAVE_ISATTY
    if (!is_atty)
        is_atty = isatty(2) ? 1 : -1;  // is_atty 给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); //把line 保存到prev 变量,供信息是否充分比较用
    sanitize(part[0].str); //对part[0].str字符串进行健康检查,对不可打印字符用'?'替代
    colored_fputs(type[0], 0, part[0].str); //关键函数, 有level,tint和字符串
    sanitize(part[1].str);
    colored_fputs(type[1], 0, part[1].str); //处理part[1]
    sanitize(part[2].str);                    //处理part[2]
//NB_LEVELS是8, av_clip是保证level>>8 处于0-7之间的数,此例因level=0x10,level>>3=2,av_clip()后还是2
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);
    sanitize(part[3].str);                     //处理part[3]
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);
end:
    av_bprint_finalize(part+3, NULL); // 对part+3 finalize
    ff_mutex_unlock(&mutex); //释放锁
}

format_line 函数看了一眼,
4个part 都是 AVBPint 对象,是一个buffer打印对象,自己管理自己. 其结构为:
(gdb) ptype part[0]
  type = struct AVBPrint {
      char *str;
      unsigned int len;
      unsigned int size;
      unsigned int size_max;
      char reserved_internal_buffer[1];
      char reserved_padding[1000];
  }
望文生义也可以理解其意图了.

part0 保存父类名称
part1 保存类名称
part2 保存类型字符串
part3 保存我们要打印的字符串
因为我们的logctx 传的是空,所以part0,part1都为空
因为我们没有设置打印log类型标志,所以part2也为空


static void colored_fputs(int level, int tint, const char *str)
{
    int local_use_color;
    if (!*str)
        return;

    if (use_color < 0) //use_color 是全局变量,初始值是-1,所以调用
        check_color_terminal(); //通过环境变量及检测,设定use_color=256

    if (level == AV_LOG_INFO/8) local_use_color = 0; //AV_LOG_INFO 是不用颜色的0
    else                        local_use_color = use_color; //其它都使用颜色256

    ansi_fputs(level, tint, str, local_use_color); //此为真正彩色输出
}

//深入浅出系列, 发现最后出口
static void ansi_fputs(int level, int tint, const char *str, int local_use_color)
{
    if (local_use_color == 1) { //系统只支持单色(实际是16色),按此输出
        fprintf(stderr,
                "\033[%"PRIu32";3%"PRIu32"m%s\033[0m",
                (color[level] >> 4) & 15,  // 背景
                color[level] & 15,            // 前景
                str);
    } else if (tint && use_color == 256) { //系统支持256色, tint为真
        fprintf(stderr,
                "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m",
                (color[level] >> 16) & 0xff,  //背景
                tint,                //前景由tint指定
                str);
    } else if (local_use_color == 256) { //系统支持256色, tint为假
        fprintf(stderr,
                "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m",
                (color[level] >> 16) & 0xff, //背景由颜色表高位决定, 本测试走的是这路,为0
                (color[level] >> 8) & 0xff, // 前景由颜色表次高位决定, 为0xc4
                str);
    } else
        fputs(str, stderr);  //无颜色按fputs 输出, 对应AV_LOG_INFO
}

(gdb) p/x color // 关注前8个是log 颜色表
  $36 = {0x34c441, 0xd041, 0xc411, 0xe203, 0xfd09, 0x2802, 0x2202, 0x2207, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfa09, 0xdb15, 0xc905, 0xd515, 0xcf05, 0x3316, 0x2706, 0x9b12, 0xc014, 0x9914, 0x9314, 0x0 <repeats 29 times>, 0xd515, 0xcf05, 0xd515, 0xcf05, 0xd515, 0xcf05}


本测试AV_LOG_ERROR=0x10, level=0x10/2=2, 所以color[level]=0xc411文章来源地址https://www.toymoban.com/news/detail-617939.html

到了这里,关于ffmpeg 中 av_log 是怎样工作的?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ffmpeg av_parser_parse2函数分析各种码流测试程序

    ffmpeg av_parser_parse2函数分析各种码流测试程序 ---------------------------------------- author: hjjdebug date: 2023年 07月 14日 星期五 16:14:05 CST date: 曾更新过... ---------------------------------------- 测试程序见后, 可编译运行(ffmpeg v4.4) 我需要一个简单的程序,实现能跟入ffmpeg 库.了解av_parser_parse2的工

    2024年02月16日
    浏览(37)
  • 音视频从入门到精通——FFmpeg之av_image_get_buffer_size函数

    函数的作用是通过指定像素格式、图像宽、图像高来计算所需的内存大小 重点说明一个参数align:此参数是设定内存对齐的对齐数,也就是按多大的字节进行内存对齐。比如设置为1,表示按1字节对齐,那么得到的结果就是与实际的内存大小一样。再比如设置为4,表示按4字节

    2023年04月15日
    浏览(46)
  • Anaconda Prompt 怎样切换环境,工作路径,以及怎样修改默认环境和默认路径

    在win环境下安装的Anaconda,打开其提供的Anaconda Prompt窗口,默认环境为base,默认路径是你的用户名,如下图: conda activate env_name 可以切换环境 E: 切换到你的指定目录的盘符 cd 切换到你指定路径下,即可成功:   找到开始菜单的Anaconda Prompt,打开文件所在位置 右键-属性,将

    2024年02月13日
    浏览(43)
  • 技术研发一天的工作是怎样的?

    一般从早上八点开始,服务的访问量就会渐渐地升起来,初始爬坡会比较缓,大概到10点左右会走到顶峰,然后会趋向平稳波动。 作为公司的后台服务研发人员,早上到公司第一件事情就是打开监控,查看服务的各项指标是否正常,及时解决各种突发状况。 监控系统是 Prom

    2024年02月07日
    浏览(43)
  • 人工智能:会给人类未来的工作带来怎样的转变?

    目录 人工智能:会给人类未来的工作带来怎样的转变? 一、了解人工智能的潜力

    2024年02月07日
    浏览(64)
  • 什么是实验室超声消泡机?工作原理是怎样的?

    超声波消泡设备也叫超声波脱气机、超声波消泡机、超声波消泡器。超声波在液体中产生空化作用,使得液体中溶解的气体(如:空气)不断凝聚,成为很细小的气泡,最后成为球状气泡脱离液体表面,从而达到液体脱气、液体消泡的目的。 实验室超声消泡机工作原理: 超声波从声

    2024年02月07日
    浏览(37)
  • 【人工智能】AI 人工智能:会给人类未来的工作带来怎样的转变?

    0. 前言 人工智能(AI)将对人类未来的工作产生深刻的影响,这些转变具体可以分为以下几点: 自动化与智能优化 : 人工智能可以实现自动化,从而提高工作效率。许多脑力和体力密集型的任务将不再需要人工完成,劳动力可用于更高级别的任务。 生产力增长 : 随着AI的广泛

    2024年02月08日
    浏览(67)
  • ffmpeg get_bits() 函数是如何工作的.

    /*  * 本测试程序用来说明 GetBitContext 是什么?  *  get_bits() 函数是如何工作的.  *  author: hjjdebug  *  date:   2023年 07月 13日 星期四 16:42:45 CST  */ GetBitContext 是如下定义的, 没有什么特别之处,指明了数据指针buffer,size_in_bits. typedef struct GetBitContext {     const uint8_t *buffer, *buffer_

    2024年02月16日
    浏览(80)
  • 数据分析师真实的工作是怎样的?看完他的一天,才明白为什么别人比你挣得多

    如果你认为数据分析师只能跑数据,那可千错万错了,数据分析师的真实工作究竟如何? 昨天就又双叒被支付宝的账单刷屏了。在这个大数据时代,通过数据,不仅可以分析消费行为,还可以分析一个人社交媒体及在互联网中的社会影响力、知名度及社会地位,而且加上实名

    2024年02月08日
    浏览(47)
  • 【动画详解人工智能原理】Tranformer 模型中的注意力机制的工作过程是怎样的 ?一个带有注意力的 Seq2seq 模型的机制实例视频动画详细讲解

    Seq2seq 序列到序列模型是深度学习模型,在机器翻译、文本摘要和图像字幕等任务中取得了很多成功。谷歌翻译于 2016 年底开始在生产中使用此类模型。两篇开创性论文(Sutskever 等人,2014 年,Cho 等人,2014 年)对这

    2024年02月07日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包