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. mysql设置存储中文变成问号或者乱码

    技术交流群: 816227112 问题: 解决办法: 修改my.ini  如果是my-default.ini 要重命名成my.ini 要注意顺序,有可能服务启动不起来 [mysqld] charact ...

  2. vba判断文件是否存在的两种方法(转)

    方法1. 用VBA自带的dir()判断,代码如下: 在 Microsoft Windows 中, Dir 支持多字符 (*)和单字符 (?) 的通配符来指定多重文件 Function IsFileEx ...

  3. VSCode 常用快捷键

    快捷键 基础编辑 快捷键 作用 Ctrl+X 剪切 Ctrl+C 复制 Ctrl+Shift+K 删除当前行 Ctrl+Enter 在当前行之后插入一行 Ctrl+Shift+Enter 在当前行之前 ...

  4. [转]vue跨域解决方法

      vue跨域解决方法 vue项目中,前端与后台进行数据请求或者提交的时候,如果后台没有设置跨域,前端本地调试代码的时候就会报“No 'Access-Control-Allow-Origin' hea ...

  5. 5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例

    ES5中,一共有9个Array方法 Array.prototype.indexOf Array.prototype.lastIndexOf Array.prototype.every Array.pr ...

  6. mr微博内容推荐

        第一次迭代 1 package com.laoxiao.mr.weibo; import java.io.StringReader; import org.apache.commons.lan ...

  7. springboot无法加载oracle驱动终极解决

    .ctrl+shirt+s .找到 Maven: com.oracle:ojdbc6: .找到classes 下的路径C:\Users\Administrator\.m2\repository\com ...

  8. 关于oracle 索引,收藏

    该篇文章很好,,收藏了.. https://www.cnblogs.com/liangyihui/p/5886619.html oracle 索引建立: create  bitmap/UNIQUE i ...

  9. 《Java并发编程的艺术》Java内存模型(三)

    Java内存模型 一.Java内存模型的基础 1.并发编程模型的两个关键问题: 两个关键问题,线程之间如何通信和如何同步.两种方式,共享内存和消息传递.Java里线程的通信是通过共享内存,线程的同步是 ...

  10. C# 互通操作 (二)基础知识1

    [DllImport("user32.dll", EntryPoint = "MessageBox")] public static extern int De ...