2. 在C++类中,实现ffmpeg库日志的打开
// ffmpeg_sdk.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#include "libavutil/log.h"
#ifdef __cplusplus
}
#endif
class FFmpegSDK{
public:
FFmpegSDK();
~FFmpegSDK();
public:
#define LOG_BUF_PREFIX_SIZE 512
#define LOG_BUF_SIZE 1024
static char libffmpeg_log_buf_prefix[LOG_BUF_PREFIX_SIZE];
static char libffmpeg_log_buf[LOG_BUF_SIZE];
static void libffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vl);
}
/* ffmpeg_sdk.cpp*/
char FFmpegSDK::libffmpeg_log_buf_prefix[LOG_BUF_PREFIX_SIZE];
char FFmpegSDK::libffmpeg_log_buf[LOG_BUF_SIZE];
void FFmpegSDK::libffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vl){
int cnt;
memset(libffmpeg_log_buf_prefix, 0, LOG_BUF_PREFIX_SIZE);
memset(libffmpeg_log_buf, 0, LOG_BUF_SIZE);
cnt = snprintf(libffmpeg_log_buf_prefix, LOG_BUF_PREFIX_SIZE, "%s", fmt);
cnt = vsnprintf(libffmpeg_log_buf, LOG_BUF_SIZE, libffmpeg_log_buf_prefix, vl);
printf("%s", libffmpeg_log_buf);
return;
}
int main(){
/* Init ffmpeg log */
ffmpeg_log_callback pcb_log = libffmpeg_log_callback;
av_log_set_level(AV_LOG_DEBUG);
av_log_set_flags(AV_LOG_SKIP_REPEATED);
av_log_set_callback(pcb_log);
printf("Current ffmpeg log_level = %d\n", av_log_get_level());
。。。
}
1. 在示例代码环境中打开库日志并输出
ENV:
/opt/ffmpeg/ffmpeg-3.2.4
ffmpeg的示例代码位于:/opt/ffmpeg/ffmpeg-3.2.4-examples/examples
选择原型程序: transcode_aac
1.1 如何打开日志
#include "libavutil/log.h"
static FILE *fp_log;
#define LOG_BUF_PREFIX_SIZE 512
#define LOG_BUF_SIZE 1024
static char logBufPrefix[LOG_BUF_PREFIX_SIZE];
static char logBuffer[LOG_BUF_SIZE];
static pthread_mutex_t cb_av_log_lock;
typedef void (*ffmpeg_log_callback)(void *ptr, int level, const char *fmt, va_list vl);
static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl){
FILE *fp = (FILE*)fp_log;
int cnt;
pthread_mutex_lock(&cb_av_log_lock);
cnt = snprintf(logBufPrefix, LOG_BUF_PREFIX_SIZE, "%s", fmt);
cnt = vsnprintf(logBuffer, LOG_BUF_SIZE, logBufPrefix, vl);
fprintf(fp, "%s", logBuffer);
fflush(fp);
pthread_mutex_unlock(&cb_av_log_lock);
}
int main(int argc char* argv){
// initialize log
/* Init log_callback_null */
fp_log = fopen("debug.log", "w+");
if ( NULL == fp_log){
printf("cant open log file %s\n", "debug.log");
return 0;
}
ffmpeg_log_callback fptrLog = log_callback_null;
/* END */
av_log_set_level(AV_LOG_DEBUG);
av_log_set_flags(AV_LOG_SKIP_REPEATED);
av_log_set_callback(fptrLog);
printf("Current log_level = %d\n",av_log_get_level());
...
}
1.2. Makefile修改
修改后的Makefile如下:
#####
#
INCLUDES :=../ffmpeg-3.2.4/include/
CFLAGS := -Wall -g -o0 -fPIC
CFLAGS += $(addprefix -I, $(INCLUDES))
#
FFMPEG_LIBS= avdevice \
avformat \
avfilter \
avcodec \
swresample \
swscale \
avutil \
LIBDIR := ../ffmpeg-3.2.4/lib/
LIBS := $(FFMPEG_LIBS)
LDLIBS := $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS)) -lm -lpthread -ldl -lrt
EXAMPLES= avio_dir_cmd \
avio_reading \
decoding_encoding \
demuxing_decoding \
extract_mvs \
filtering_video \
filtering_audio \
http_multiclient \
metadata \
muxing \
remuxing \
resampling_audio \
scaling_video \
transcode_aac \
transcode_aac_openliblog \
transcoding \
transcode_aac \
transcode_aac_openliblog \
transcoding \
OBJS=$(addsuffix .o,$(EXAMPLES))
.phony: all clean-test clean
all: $(OBJS) $(EXAMPLES)
clean-test:
$(RM) test*.pgm test.h264 test.mp2 test.sw test.mpg
clean: clean-test
$(RM) $(EXAMPLES) $(OBJS)
1.3. 运行命令:
./transcode_aac_openliblog ../test-samples/out-audio-1-jzaff2d9b383f94241992e4214e5dd1f5a-4-3288369-f-1514429532736-t-1514429648756.mp4 ../test-samples/transcode-aac-out-audio-1-jzaff2d9b383f94241992e4214e5dd1f5a-4-3288369-f-1514429532736-t-1514429648756.mp4
2. 原理:
先见libavutil/log.h的函数声明,从代码可见,ffmpeg库的日志使用的回调机制;
/**
* 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);
/**
* 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));
C语言的回调机制:
回调函数实现的机制是
1)定义一个回调函数;
2)提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
3)当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。