Visual Studio 开发(二):VS 2017配置FFmpeg开发环境一文中,我们配置好了FFmpeg的开发环境,下面我们开始边实战,边学习FFmpeg。

首先,我们要学习的就是FFmpeg的日志输出系统 。

一、FFmpeg 日志输出系统介绍

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

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

二、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, const char *fmt, ...) av_printf_format(, );

其中第一个参数指定该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

从定义中可以看出来,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()输出的级别是AV_LOG_INFO。

三、设置日志输出等级

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

函数声明如下:

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

查看函数代码实现:

static int av_log_level = AV_LOG_INFO;

可以看出,设置日志输出等级主要是操作静态全局变量av_log_level。该变量用于存储当前系统Log的级别。

四、日志输出实战

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

#include "pch.h"
#include <iostream> extern "C"{
#include "libavutil/log.h"
} int main(int argc, char* argv[]) {
av_log_set_level(AV_LOG_ERROR);
av_log(NULL, AV_LOG_INFO, "Hello World\n");
return ;
}

五、自定义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_logoutput(void* ptr, int level, const char* fmt,va_list vl){
****(省略....)
}

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

av_log_set_callback(my_logoutput);

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

#include "pch.h"
#include <iostream> extern "C"{
#include "libavutil/log.h"
} void my_logoutput(void* ptr, int level, const char* fmt, va_list vl) {
printf("Hello Log Output! Content = %s", fmt);
} int main(int argc, char* argv[]) {
av_log_set_callback(my_logoutput); // 设置自定义的日志输出方法
av_log(NULL, AV_LOG_INFO, "Hello World\n");
return ;
}

输出如下:

附:本文涉及C语言知识点 --> 函数指针。

FFmpeg开发实战(一):FFmpeg 打印日志的更多相关文章

  1. FFmpeg开发实战(三):FFmpeg 打印音视频Meta信息

    在之前使用FFmpeg命令行的时候,我们经常看到FFmpeg命令行在输出音视频文件的会打印一下文件的Meta信息,类似如图: 那么我们如何通过代码的方式输出这些Meta信息呢? FFmpeg提供了一个 ...

  2. FFmpeg开发实战(四):FFmpeg 抽取音视频的音频数据

    如何使用FFmpeg抽取音视频的音频数据,代码如下: void adts_header(char *szAdtsHeader, int dataLen); // 使用FFmpeg从视频中抽取音频 vo ...

  3. FFmpeg开发实战(五):FFmpeg 抽取音视频的视频数据

    如何使用FFmpeg抽取音视频的视频数据,代码如下: // FFmpegTest.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #include ...

  4. FFmpeg开发实战(二):FFmpeg 文件操作

    FFmpeg 提供了丰富的API供我们使用,下面我们来讲述一下文件操作相关的API: FFmpeg 删除文件:avpriv_io_delete() FFmpeg 重命名文件:avpriv_io_mov ...

  5. FFmpeg开发实战(六):使用 FFmpeg 将YUV数据编码为视频文件

    本文中实现的一个小功能是把一个YUV原始视频数据(时间序列图像)经过h264编码为视频码流,然后在使用mp4封装格式封装. 编码&封装的流程图如下: 使用ffmpeg编码流程: 1.首先使用a ...

  6. Android开发之封装log打印日志的工具类,实用logutils详细代码

    public final class LogUtil { /** all Log print on-off */ private final static boolean all = true; /* ...

  7. FFmpeg调用c语言SDK实现日志的打印

    日志文件的三大步 // 导入头文件 #include <libavutil/log.h> // 设置日志级别 av_log_set_level(AV_LOG_DEBUG); //DEBUG ...

  8. windows环境下搭建ffmpeg开发环境

           ffmpeg是一个开源.跨平台的程序库,能够使用在windows.linux等平台下,本文将简单解说windows环境下ffmpeg开发环境搭建过程,本人使用的操作系统为windows ...

  9. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

随机推荐

  1. 【java-console】如何双击运行可执行jar包及遇到依赖dll报错问题的解决办法

    如何配置双击运行可执行jar包的步骤,请移步到   这里   查看具体的操作,此处不再介绍. 本文主要解决如何处理依赖dll报错的问题解决办法. 我有一个jar包可执行文件运行需要依赖第三方的dll文 ...

  2. Java-HashMap、HashSet、hashTable

    HashMap:key:可null,重复的key对应的value会出现后面覆盖前面的情况.value:可null; 引用:数组,数组中存链表. HashSet使用HashMap的实现存储数据,所以有H ...

  3. Shell脚本- 单条命令循环执行重复工作

    关于shell for循环具体详细说明可参考:http://wiki.jikexueyuan.com/project/linux-command/chap34.html example: 分别在com ...

  4. g++ 学习笔记

    gcc and g++分别是GNU的c & c++编译器.gcc/g++在执行编译的时候一般有下面4步: 1 预处理,生成.i的文件. 命令如下:g++ -E  test.cpp 此命令只进行 ...

  5. Python:每日一题008

    题目: 判断101-200之间有多少个素数,并输出所有素数. 程序分析: 判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数. 个人思路及代码: li ...

  6. JS 变量提升与函数提升

    JS 变量提升与函数提升 JS变量提升 变量提升是指:使用var声明变量时,JS会将变量提升到所处作用域的顶部.举个简单的例子: 示例1 console.log(foo); // undefined ...

  7. Finance财务软件(自定义报表专题)

    我们可以通过存储过程自定义报表 1.在菜单中新增报表菜单,这里的代码约束为报表对应存储过程名称,配置完成成后重启客户端生效 2.在自定义模板中适配存储过程入参,这里的功能键值为存储过程名称,字段键值与 ...

  8. sql语句性能优化

    需要的准备知识 1最左前缀匹配 mysql会一直向右匹配直到遇到范围查询(>.<.between.like)就停止匹配, 对于where条件 a = 1 and b> 2 and c ...

  9. 从信息论的角度分析DNN的工作原理

    在前面的文章里,使用神经网络的任意函数拟合性结合了一点黎曼几何的坐标系变化的知识,解释了神经网络是怎样根据输入x,计算出每个分类下的能量Ei(x)的,再之后使用能量模型推算出了概率,从而展示了理论上可 ...

  10. Retrieving archetypes

    报错:Retrieving archetypes:' has encountered a problemAn internal error occurred during:"Retrievi ...