FFmpeg日志输出系统av_log的移植
av_log()
函数是FFmpeg日志输出的核心函数,在FFmpeg内部的所有打印信息全部采用的都是av_log()
接口进行打印的.
在一开始的时候,我记得ffmpeg里是无法使用printf函数的,如果你在代码里加了一句打印,那么他会屏蔽掉,但现在忘记是在什么地方限制了
av_log()
函数原型:
/**
* 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, const char *fmt, ...) av_printf_format(3, 4);
FFmpeg里的av_log()的特性:
- 引入
AVClass
,能够打印是哪个模块那个部分作出的打印,并能够影响level的值从而实现颜色的变化
level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset);
- 可控制是否颜色输出,可以根据不同打印等级,显示出不同的颜色,易于区分
第二个参数,它决定了是否输出字符串,同时还可以根据level
输出不同的颜色.
是否输出颜色由use_color控制:
use_color = 0
时: 无色彩输出;
use_color = 1
时: 有色彩输出,但此时输出的字符串背景是无色;
use_color = 256
时: 有色彩输出,但此时输出的字符串背景是可配置的;
- 可控制对重复信息的重复打印,浪费打印资源
打印级别
/**
* Print no output.
*/
#define AV_LOG_QUIET -8
/**
* Something went really wrong and we will crash now.
*/
#define AV_LOG_PANIC 0
/**
* Something went wrong and recovery is not possible.
* For example, no header was found for a format which depends
* on headers or an illegal combination of parameters is used.
*/
#define AV_LOG_FATAL 8
/**
* Something went wrong and cannot losslessly be recovered.
* However, not all future data is affected.
*/
#define AV_LOG_ERROR 16
/**
* Something somehow does not look correct. This may or may not
* lead to problems. An example would be the use of '-vstrict -2'.
*/
#define AV_LOG_WARNING 24
/**
* Standard information.
*/
#define AV_LOG_INFO 32
/**
* Detailed information.
*/
#define AV_LOG_VERBOSE 40
/**
* Stuff which is only useful for libav* developers.
*/
#define AV_LOG_DEBUG 48
/**
* Extremely verbose debugging, useful for libav* development.
*/
#define AV_LOG_TRACE 56
#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET)
从定义可以看出,不同打印等级后都有一个数值.数值越小说明越严重,系统默认的级别是AV_LOG_INFO
.
可以通过av_log_get_level()获得当前Log的级别,通过另一个函数av_log_set_level()设置当前的Log级别。
/**
* Get the current log level
*
* @see lavu_log_constants
*
* @return Current log level
*/
int av_log_get_level(void);
/**
* Set the log level
*
* @see lavu_log_constants
*
* @param level Logging level
*/
void av_log_set_level(int level);
有关av_log的介绍就到这里,详细的av_log介绍还是雷霄骅大佬写的全面,这里就不做过多介绍了.
请移步:FFmpeg源代码简单分析:日志输出系统(av_log()等)
下面主要说明如何将av_log移植出来化为自己所用的.
由于上述所说的ffmpeg
的av_log
的特性.认为不同以往的日志输出框架,比较有趣,所以这次将其移植出来进行使用以及日志框架的搭建学习.
但是在移植完之后,也不得不去思考所面临的一些问题,认为移植出来的log虽可以使用,但在某些嵌入式系统里,还是欠缺实用性.
相信看到这里的时候,你已经将上面大神雷霄骅的日志输出系统做一个简单的学习.
有关本次移植的代码已经上传至:https://github.com/Tschome/log,有需要的可以下载使用.
函数原型:
void log(void *name, int level, const char *fmt, ...) printf_format(3, 4);
- 为了区别于av_log(),移植后的代码将移除
av_
,AV_
前缀为log()
; - 为了简易使用,索性将第一个参数
AVClass
删去,直接用name
的使用字段替代.且若执行log()代码之后会发现打印信息里会有reserve
,这个字段是作为保留选项,现在还没想好如何利用好这个位置,或者说第一个参数暂做保留设计,以后有什么好的参数选项,可以再进行优化修改. - 第二个参数
level
打印等级只使用AV_LOG_PANIC
,AV_LOG_FATAL
,AV_LOG_ERROR
,AV_LOG_WARNING
,AV_LOG_INFO
,AV_LOG_VERBOSE
,AV_LOG_DEBUG
,其他等级暂无打算使用.
示例代码:
#include <stdlib.h>
#include <string.h>
#include "log.h"
#define TAG "main"
void main(int argc, char **argv)
{
log_set_flags(LOG_SKIP_REPEATED | LOG_PRINT_LEVEL);//跳过重复的信息 + 显示打印级别
log_set_level(LOG_DEBUG);
int i = 0;
//for(i = 0; i < 10; i++)
log(TAG, LOG_QUIET, "LOG_QUIET\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_PANIC, "LOG_PANIC\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_FATAL, "LOG_FATAL\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_ERROR, "LOG_ERROR\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_WARNING, "LOG_WARNING\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_INFO, "LOG_INFO\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_VERBOSE, "LOG_VERBOSE\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_DEBUG, "LOG_DEBUG\n");
//for(i = 0; i < 10; i++)
log(TAG, LOG_TRACE, "LOG_TRACE\n");
log(TAG, LOG_MAX_OFFSET, "LOG_MAX_OFFSET\n");
return;
}
测试结果:
问题:
1.在移植之后,在编译后,这个vlog()
在原先的逻辑下出现了段错误.截至目前没有找到是什么原因,遂直接调用内部的log回调函数,但这样造成的后果就是:无法自定义自己的log
函数了
所以这个问题后续也得解决
//log.c
void vlog(void *name, int level, const char *fmt, va_list vl)
{
#if 0
//原先的实现逻辑
void (*log_callback)(void*, int, const char*, va_list) = log_callback;
if (log_callback){
log_callback(name, level, fmt, vl);
}
#else
//临时的替代方案
log_default_callback(name, level, fmt, vl);
#endif
}
2.无法输出颜色效果.本次移植也依旧使用临时替代方案,后面需要使用合适的方式代替它
//log.c
static void colored_fputs(int level, int tint, const char *str)
{
int local_use_color;
if (!*str)
return;
if (use_color < 0)
check_color_terminal();
if (level == LOG_INFO/8) local_use_color = 0;
else local_use_color = use_color;
#if 1
//临时替代方案
use_color = 256;
local_use_color = 256;
#endif
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
if (con != INVALID_HANDLE_VALUE) {
if (local_use_color)
SetConsoleTextAttribute(con, background | color[level]);
win_console_puts(str);
if (local_use_color)
SetConsoleTextAttribute(con, attr_orig);
} else {
ansi_fputs(level, tint, str, local_use_color);
}
#else
ansi_fputs(level, tint, str, local_use_color);
#endif
}
本文作为本次移植的记录,内容尚简,欢迎交流指导