音视频系列三:ffmpeg之日志打印

阅读: 评论:0

音视频系列三:ffmpeg之日志打印

音视频系列三:ffmpeg之日志打印

title: 音视频系列三:ffmpeg之日志打印
categories:[ffmpeg]
tags:[音视频编程]
date: 2021/11/27

作者:hackett 微信公众号:加班猿

在上一篇 Visual Studio2019集成ffmpeg之hello world中,我们已经配置好visual studio的开发环境,接下来继续根据上一篇的环境来学习ffmpeg的日志打印;

日志打印对于定位问题或者寻找bug都起到决定性的作用。

一、FFmpeg 打印日志输出介绍

FFmpeg 日志输出的核心函数方法为: av_log() 。为什么说av_log()是FFmpeg中输出日志的核心函数函数?

因为我们随便打开一个FFmpeg的源代码文件(源代码文件需要去官网下载带源代码的版本),就会发现其中遍布着av_log()函数。一般情况下FFmpeg类库的源代码不允许使用printf()这种函数,所以打印的所有输出一律使用的av_log()。

二、av_log() 函数说明

av_log()的声明位于libavutillog.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 or NULL if general log.* @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);

其中第一个参数指定该log所属的结构体,例如AVFormatContext、AVCodecContext等等。第二个参数指定log的级别,第三个参数为要输出的内容,源代码中定义了如下几个级别:

/*** 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()的日志级别分别是:

AV_LOG_PANIC,AV_LOG_FATAL,AV_LOG_ERROR,AV_LOG_WARNING,AV_LOG_INFO,AV_LOG_VERBOSE,AV_LOG_DEBUG,AV_LOG_TRACE。

每个级别定义的数值代表了严重程度,数值越小代表越严重。

默认av_log()输出的级别是AV_LOG_INFO。

三、设置/获取日志输出等级

在上面,我们讲到av_log()函数是可以设置日志的内容的等级的。而对于输出的日志内容,我们也是可以设置等级的。FFmpeg提供了av_log_set_level()用于设置当前Log的级别,av_log_get_level用于获取当前Log的级别。

av_log_set_level函数声明如下:

/*** Set the log level** @see lavu_log_constants** @param level Logging level*/
void av_log_set_level(int level);

av_log_set_level函数声明如下:

/*** Get the current log level** @see lavu_log_constants** @return Current log level*/
int av_log_get_level(void);

四、日志输出实战

通过下面的代码,我们就可以理解上面讲的日志输出及设置日志输出等级的逻辑了。

#include <iostream>extern "C"{
#include "libavutil/log.h"
}int main(int argc, char* argv[]) {av_log_set_level(AV_LOG_DEBUG); //设置日志级别av_log(NULL, AV_LOG_DEBUG, "hello world log"); //打印日志printf("av_log_get_level: %dn",av_log_get_level());system("pause"); //窗口等待return 0;
}

五、自定义FFmpeg日志输出

查看ffmpeg日志的实现源码可以发现,av_log()调用了av_vlog(),av_log()调用了一个函数指针av_log_callback。av_log_callback是一个全局静态变量,定义如下所示:

static void (*av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback;

从代码中可以看出,av_log_callback指针默认指向一个函数av_log_default_callback()。av_log_default_callback()即FFmpeg默认的Log函数。

需要注意的是,这个Log函数是可以自定义的。按照指定的参数定义一个自定义的函数后,可以通过FFmpeg的另一个API函数av_log_set_callback()设定为Log函数。

查看源码,可以看到 av_log_set_callback() 的声明如下:

/*** Set the logging callback** @note The callback must be thread safe, even if the application does not use*       threads itself as some codecs are multithreaded.** @see av_log_default_callback** @param callback A logging function with a compatible signature.*/
void av_log_set_callback(void (*callback)(void*, int, const char*, va_list));

从声明中可以看出,需要指定一个参数为(void*, int, const char*, va_list),返回值为void的函数作为Log函数。

查看av_log_set_callback() 源码,可以看到此方法只是做了一个函数指针赋值的工作,代码如下:

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

这样我们可以自定义一个my_logoutput()函数作为Log的输出函数:

void my_log_printf(void* ptr, int level, const char* fmt,va_list vl){省略...
}

编辑好函数之后,使用av_log_set_callback()函数设置该函数为Log输出函数即可。

av_log_set_callback(my_log_printf);

下面是自定义日志输出的实例源码:

#include<iostream>
using namespace std;extern "C" {//包含C头文件
#include "libavutil/log.h" 
};void my_log_printf(void* ptr, int level, const char* fmt, va_list vl) {printf("my_log_printf enter! Content : %snlog level : %dn", fmt, level);
}int main(int argc, char* argv[]) {av_log_set_level(AV_LOG_DEBUG); //设置日志级别av_log_set_callback(my_log_printf);  // 设置自定义的日志输出方法av_log(NULL, AV_LOG_DEBUG, "hello world log"); //打印日志system("pause"); //窗口等待return 0;
}

如果你觉得文章还不错,可以给个"三连",文章同步到以下个人微信公众号[加班猿]

我是hackett,我们下期见

本文发布于:2024-02-03 02:14:09,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170689764947966.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:音视频   系列   日志   ffmpeg
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23