ffmpeg 日志系统av_log()
核心函数只有一个:av_log()。使用av_log()在控制台输出日志的效果如下图所示。


av_log()
av_log()是FFmpeg中输出日志的函数。随便打开一个FFmpeg的源代码文件,就会发现其中遍布着av_log()函数。一般情况下FFmpeg类库的源代码中是不允许使用printf()这种的函数的,所有的输出一律使用av_log()。
av_log()的声明位于libavutil\log.h,如下所示。
- * Send the specified message to the log if the level is less than or equal
- * to the current av_log_level. By default, all logging messages are sent to
- * stderr. This behavior can be altered by setting a different logging callback
- * function.
- * @see av_log_set_callback
- *
- * @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 expressed using a @ref
- * lavu_log_constants "Logging Constant".
- * @param fmt The format string (printf-compatible) that specifies how
- * subsequent arguments are converted to output.
- */
- void av_log(void *avcl, int level, constchar *fmt, ...) av_printf_format(3, 4);
这个函数的声明有两个地方比较特殊:
(1)函数最后一个参数是“…”
在C语言中,在函数参数数量不确定的情况下使用“…”来代表参数。例如printf()的原型定义如下
int printf (const char*, ...);
(2)它的声明后面有一个av_printf_format(3, 4)。有关这个地方还没有深入研究,网上资料中说它的作用是按照printf()的格式检查av_log()的格式。
av_log()每个字段的含义如下:
avcl:指定一个包含AVClass的结构体。
level:log的级别
fmt:和printf()一样。
由此可见,av_log()和printf()的不同主要在于前面多了两个参数。其中第一个参数指定该log所属的结构体,例如AVFormatContext、AVCodecContext等等。第二个参数指定log的级别:
有一个级别不输出任何信息,即AV_LOG_QUIET。
可以通过av_log_get_level()获得当前Log的级别,通过另一个函数av_log_set_level()设置当前的Log级别。
我们看一下H.264编码的时候libx264的Log输出的示例:

下面回到av_log()函数的源代码。它的源代码位于libavutil\log.c,如下所示。
- void av_log(void* avcl, int level, constchar *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);
- }
首先来提一下C语言函数中“…”参数的含义。与它相关还涉及到以下4个部分:
(1)va_list变量
(2)va_start()
(3)va_arg()
(4)va_end()
va_list是一个指向函数的参数的指针。va_start()用于初始化va_list变量。va_arg()用于返回可变参数。va_end()用于结束可变参数的获取。有关它们的用法可以参考一个小demo,如下所示。
- [0m"
(3)颜色对应关系如下所示:
\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" 白色
具体到编程中,printf() 颜色设置示例代码如下所示。
- int main()
- {
- printf("\e[31m Hello World. \e[0m \n"); // 红色字体
- return 0;
- }
Windows下控制台文字上色的方法
Windows下控制台颜色是通过SetConsoleTextAttribute()函数完成的。SetConsoleTextAttribute()函数的原型如下所示。
- BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);
其中2个参数的含义如下所示:
hConsoleOutput:指向控制台的句柄。
wAttributes:文本属性。
hConsoleOutput可以选择以下3种句柄:
STD_INPUT_HANDLE:标准输入的句柄
STD_OUTPUT_HANDLE:标准输出的句柄
STD_ERROR_HANDLE:标准错误的句柄
wAttributes可以控制前景色和背景色:
FOREGROUND_BLUE:字体颜色:蓝
FOREGROUND_GREEN:字体颜色:绿
FOREGROUND_RED:字体颜色:红
FOREGROUND_INTENSITY:前景色高亮显示
BACKGROUND_BLUE:背景颜色:蓝
BACKGROUND_GREEN:背景颜色:绿
BACKGROUND_RED:背景颜色:红
BACKGROUND_INTENSITY背景色高亮显示
控制台文本上色demo代码如下所示。
- #include
- #include
- int main()
- {
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);
- printf("red\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
- printf("green\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);
- printf("blue\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED|FOREGROUND_GREEN);
- printf("red+green=yellow\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED|FOREGROUND_BLUE);
- printf("red+blue=purple\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN|FOREGROUND_BLUE);
- printf("green+blue=cyan\n");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED|BACKGROUND_GREEN);
- printf("Add background\n");
- return 0;
- }
程序的运行结果如下图所示。

colored_fputs()源代码
从colored_fputs()的源代码中可以看出如下流程:
首先根据宏定义判定系统的类型,如果系统类型是Windows,那么就调用SetConsoleTextAttribute()方法设定控制台文本的颜色,然后调用fputs()将Log记录输出到stderr(注意不是stdout);
至此FFmpeg的日志输出系统的源代码就分析完毕了。
av_log() 函数
av_log(NULL, AV_LOG_DEBUG, "Hello World ! \n");
ffmpeg 日志系统av_log()的更多相关文章
- C++ 高性能无锁日志系统
服务器编程中,日志系统需要满足几个条件 .高效,日志系统不应占用太多资源 .简洁,为了一个简单的日志功能引入大量第三方代码未必值得 .线程安全,服务器中各个线程都能同时写出日志 .轮替,服务器不出故障 ...
- Atitit.日志系统slf4j的使用
Atitit.日志系统slf4j的使用 SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar ...
- Android源码——Logger日志系统
Android的Logger日志系统是基于内核中的Logger日志驱动程序实现的. 日志保存在内核空间中 缓冲区保存日志 分类方法:日志的类型 + 日志的输出量 日志类型: main ...
- 使用Slf4j集成Log4j2构建项目日志系统的完美解决方案
一.背景 最近因为公司项目性能需要,我们考虑把以前基于的log4j的日志系统重构成基于Slf4j和log4j2的日志系统,因为,使用slf4j可以很好的保证我们的日志系统具有良好的兼容性,兼容当前常见 ...
- 日志系统实战(三)-分布式跟踪的Net实现
介绍 在大型系统开发调试中,跨系统之间联调开始变得不好使了.莫名其妙一个错误爆出来了,日志虽然有记录,但到底是哪里出问题了呢? 是Ios端参数传的不对?还是A系统或B系统提供的接口导致?相信有不少人遇 ...
- 日志系统实战(一)—AOP静态注入
背景 近期在写日志系统,需要在运行时在函数内注入日志记录,并附带函数信息,这时就想到用Aop注入的方式. AOP分动态注入和静态注入两种注入的方式. 动态注入方式 利用Remoting的Context ...
- Android性能优化之UncaughtExceptionHandler定制自己的错误日志系统
前言: 每当我们app测试的时候,测试人员总是对我们说这里崩溃了,那里挂掉了!我们只能默默接受,然后尝试着重现bug,更可悲的是有时候bug很难复现,为了解决这种现状所以我们要尝试这建立一个自己的bu ...
- [Asp.net 5] Logging-其他日志系统的实现
Microsoft.Framework.Logging.NLog 使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger.ILoggerProvider.所以在当 ...
- 【转载】scribe、chukwa、kafka、flume日志系统对比
原文地址:http://www.ttlsa.com/log-system/scribe-chukwa-kafka-flume-log-system-contrast/ 1. 背景介绍许多公司的平台每天 ...
随机推荐
- iOS开发之使用UICollectionView实现美团App的分类功能【偶现大众点评App的一个小bug】
郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 游戏官方下 ...
- weblogic基本安装部署
1.3.1 安装WebLogic10(1) <JavaEE程序设计与应用开发>第1章JavaEE介绍和环境配置,本章首先介绍了JavaEE的基本理论,然后对本书将要使用的软件:JDK.服务 ...
- C基础测试
一.用指针的方法,把输入的一个字符串按逆序重新排序其字符,并输出. #include <stdio.h> #include <string.h> void main( ) { ...
- Andorid上拉加载更多的几种实现方式
1.前言 Andriod中上拉加载更多的效果随处可见,因为一次性要展现的数据太多信息量太大的话,给用户的体验就很差(加载慢,界面卡顿.流量消耗大等),而加载更多可以控制每次加载条目的数量以达到快速加载 ...
- ant-design-pro Login 组件 实现 rules 验证
1.引入组件 // 引入 ant-design-pro import Login from 'ant-design-pro/lib/Login'; /** * UserName 账号 * Passwo ...
- iOS中 最新微信支付/最全的微信支付教程具体解释 韩俊强的博客
亲们, 首先让我们来看一下微信支付的流程吧. 1. 注冊微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些參数. 2. 下载微信支付sdk 3. clien ...
- JavaScript | 对象详解
————————————————————————————————————————————————————————— 对象有哪些(导图) 内建对象 数据封装对象 Object对象 Object.prot ...
- 通过 thread dump 分析找到高CPU耗用与内存溢出的Java代码
http://heylinux.com/archives/1085.html通过 thread dump 分析找到高CPU耗用与内存溢出的Java代码 首先,要感谢我的好朋友 钊花 的经验分享. 相信 ...
- 浅析C#中 ConcurrentDictionary的实现
简单画了一张图 (灵魂画手 →_→) 如图 ConcurrentDictionary 其中有个tables 对象主要存储,而这个 tables 是一个 很多区块的 数组 ,每个区块 又是一个node的 ...
- 接收广播BroadcastReceiver
Broadcast Receiver用于接收并处理广播通知(broadcast announcements).多数的广播是系统发起的,如地域变换.电量不足.来电来信等.程序也可以播放一个广播.程序可以 ...