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
相关文章:
ffmpeg 中 av_log 是怎样工作的?
---------------------------------------- author: hjjdebug date: 2023年 07月 27日 星期四 14:56:38 CST descriptor: ffmpeg 中 av_log 是怎样工作的? ---------------------------------------- av_log 功能其实只是添加了颜色,LOG级别,及log上下文名称,没有添加时间,函…...

HTML+CSS+JavaScript:轮播图自动播放
一、需求 轮播图如下图所示,需求是每隔一秒轮播图自动切换一次 二、代码素材 以下是缺失JS部分的代码,感兴趣的小伙伴可以先自己试着写一写 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /&…...

python 自动化数据提取之正则表达式
>>>> 前 言 我们在做接口自动化的时候,处理接口依赖的相关数据时,通常会使用正则表达式来进行提取相关的数据,今天在这边和大家聊聊如何在python中使用正则表达式。 正则表达式,又称正规表示式、正规表示法、正规…...

分布式事务之本地事务
🚀 分布式事务 🚀 🌲 AI工具、AI绘图、AI专栏 🍀 🌲 如果你想学到最前沿、最火爆的技术,赶快加入吧✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆&…...
PyTorch 初级教程:构建你的第一个神经网络
PyTorch 是一个在研究领域广泛使用的深度学习框架,提供了大量的灵活性和效率。本文将向你介绍如何使用 PyTorch 构建你的第一个神经网络。 一、安装 PyTorch 首先,我们需要安装 PyTorch。PyTorch 的安装过程很简单,你可以根据你的环境&…...

SpringBoot使用MyBatis Plus + 自动更新数据表
1、Mybatis Plus介绍 Mybatis,用过的都知道,这里不介绍,mybatis plus只是在mybatis原来的基础上做了些改进,增强了些功能,增强的功能主要为增加更多常用接口方法调用,减少xml内sql语句编写,也可…...
【设计模式】简单工厂模式
C语言实现简单的工厂模式 #include <stdio.h> #include <stdlib.h>// 图形类型枚举 typedef enum {CIRCLE,SQUARE,RECTANGLE } ShapeType;// 图形结构体 typedef struct {ShapeType type;float area; } Shape;// 创建圆形 Shape* createCircle() {Shape* circle …...
推荐系统-ALS协同过滤算法实现
从协同过滤的分类来说,ALS(Alternating Least Squares,交替最小二乘)算法属于User-Item CF,也叫做混合CF,它同时考虑了User和Item两个方面,通过数量相对少的未被观察到的隐藏因子,来…...

QT第三讲
思维导图 蜡笔小新闹钟 需求: 实现 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTime> //时间类 #include<QTimerEvent> //事件处理类 #include<QtTextToSpeech> //文本转语音类 #include<QMessageBo…...

Linux内核的I2C驱动框架详解------这应该是我目前600多篇博客中耗时最长的一篇博客
目录 1 I2C驱动整体框架图 2 I2C控制器 2.1 I2C控制器设备--I2C控制器在内核中也被看做一个设备 2.2 i2c控制器驱动程序 2.3 platform_driver结构体中的probe函数做了什么 2.3.1 疑问: i2cdev_notifier_call函数哪里来的 2.3.2 疑问:为什么有两…...

【点云处理教程】05-Python 中的点云分割
一、说明 这是我的“点云处理”教程的第 5 篇文章。“点云处理”教程对初学者友好,我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。 在上一教程中,我们看到了如何过滤点云以减少噪声或其密度。在本教程中,我们将应用一些聚…...

代码随想录算法训练营之JAVA|第十七天| 654. 最大二叉树
今天是第17天刷leetcode,立个flag,打卡60天。 算法挑战链接 654. 最大二叉树https://leetcode.cn/problems/maximum-binary-tree/description/ 第一想法 错误的想法,就不说了。 看完代码随想录之后的想法 用递归模拟真实的过程 如果我…...
C++重写函数、隐藏函数、重载函数的区别对比
目录 1.函数重载 1.1定义 1.2函数重载的规则: 1.3函数重载的作用: 2.函数重写: 2.1定义 2.2例子: 3.函数隐藏 3.1定义 3.2举个例子: 1.函数重载 1.1定义 我们在学类和对象的封装特性时学过一个词叫重载,…...
15.python设计模式【函数工厂模式】
1.知识讲解 内容:定义一个字典,在python中一切皆对象,将所有的函数进行封装,然后定一个分发函数进行分发,将原来if…else全部干掉。角色: 函数(function)函数工厂(funct…...

Redis主从复制、哨兵、cluster集群原理+实验
目录 一、Redis 主从复制 1、主从复制的作用 2、主从复制流程 3、搭建Redis 主从复制 安装Redis(所有主机) 修改Master节点Redis配置文件 修改Slave节点Redis配置文件 验证主从效果 一、Redis 主从复制 主从复制,是指将一台Redis服务器的数据&am…...
微信小程序如何实现页面传参?
前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递,下面我总结了 4 种页面方法。 路径传递 通过在url后面拼接参数,参数与路径之间使用 ? 分隔,参数键与参数值用 相连,不同参数用 & 分隔;如…...

OPC DA 客户端与服务器的那点事
C#开发OPC客户端,使用OPCDAAuto.dll。在开发过程中偶遇小坎坷,主要记录一下问题解决办法。 1、建立客户端,参考链接。建立WinFrom工程,将博客中代码全部复制即可运行: https://www.cnblogs.com/kjgagaga/p/17011730.…...

Java 错误异常介绍(Exceptions)
1、异常介绍 异常是程序执行期间发生的意外事件。它影响程序指令流,从而导致程序异常终止。 发生异常的原因有很多。其中包括: 无效的用户输入 设备故障 网络连接丢失 物理限制(磁盘内存不足) 代码错误 打开一个不可用的文…...
每日一题——旋转数组的最小数字
题目 有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这…...
SpringBoot Jackson 日期格式化统一配置
目录 1.在全局配置文件配置 2.通过JavaBean方式配置 1.在全局配置文件配置 spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT8 该配置方式仅支持 Date 类型的日期格式化,不支持LocalDate 及 LocalDateTime 的格式化。 2.通过JavaBean方式配置 …...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...