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. SQL 数据库高CPU占用语句排查

    前述 最近一个项目CPU占用非常高,在IIS内设置CPU限制后系统频繁掉线,通过任务管理器发现SQLSever数据库占用CPU达到40%--70%,对于数据库本人也就处在增删查改几个操作水平层面,这次 ...

  2. Taro button点击切换选中状态

    1.引入组件 2.state中设置选中状态 // button按钮的默认选中,0代表选中 state = { currentIndex: 0 } 3.设置class的样式,点击更改选中 selectN ...

  3. 控制请求重复提交的方法总结(Token)

    重复提交的定义: 重复提交指的是同一个请求(请求地址和请求参数都相同)在很短的时间内多次提交至服务器,从而对服务器造成不必要的资源浪费,甚至在代码不健壮的情况还会导致程序出错. 重复提交的原因或触发事 ...

  4. LR 11 代理录制步骤

    1.新一个HTTP录制,到下图步骤 按下图说明设置信息,点击update 选择rl里面的代理exe(wplus_init_wsock.exe),具体路径为下图 打开浏览器设置代理(Internet选项 ...

  5. docker--centos镜像安装tomcat jdk1.8 mysql部署java web项目

    一.下载centos7标准镜像及安装mysql5.7 在centos安装mysql5.7 二.安装jdk 1.查询可用jdk版本 yum search java|grep jdk 2.根据搜索到的jd ...

  6. Codeforces 524 解题报告

    打的很快乐的一次比赛hiahiahia, 才A掉4题rating就涨了100+ 距离比赛\(3\)天了, 由于博主实在太颓, 又补掉了\(E\)题, 到现在才发解题报告 A. 语法题, 读入输出就行了 ...

  7. [精华][推荐]CAS SSO单点登录服务端客户端学习

    1.通过下载稳定版本的方式下载cas的相关源码包,如下: 直接选择4.2.1的稳定代码即可 2.我们项目中的版本版本使用maven apereo远程库去下载 通过远程maven库下载cas-serve ...

  8. install pycurl

    error: command 'x86_64-linux-gnu-gcc' failed with exit status 1src/pycurl.h:164:28: fatal error: ope ...

  9. 【linux】工作时使用的命令

    几个基本操作: 1.查看当前文件夹下的内容: list 2.查看当前所在的文件夹:pwd 3.切换当前工作文件夹:cd 4.文件不存在时,新建文件:touch 5.创建目录:mkdir 6.删除指定的 ...

  10. Android接口Parcelable的使用

    注明:非原创,转载,原链接地址为:http://www.2cto.com/kf/201205/132814.html 和 http://www.blogjava.net/lincode/archive ...