当前位置 博文首页 > wanggao的专栏:ffmpeg学习 (18)AVUtil库常见例子(AVLog、AVO
本文参考雷神博客。FFmpeg的libavutil中几种工具函数的使用方法:
AVLog是FFmpeg的日志输出工具。在FFmpeg中所有的日志输出不是通过printf()函数而是通过av_log()
函数。av_log()会最终调用fprintf(stderr,…)
函数将日志内容输出到命令行界面上。
在一些非命令行程序(MFC程序,Android程序等)中,av_log()调用的fprintf(stderr,…)就无法将日志内容显示出来了。对于这种情况,FFmpeg提供了日志回调函数av_log_set_callback()
。该函数可以指定一个自定义的日志输出函数,将日志输出到指定的位置。
下面的自定义函数custom_output()将日志输出到了“simplest_ffmpeg_log.txt”文本中。
void custom_output(void* ptr, int level, const char* fmt,va_list vl){
FILE *fp = fopen("simplest_ffmpeg_log.txt","a+");
if(fp){
vfprintf(fp,fmt,vl);
fflush(fp);
fclose(fp);
}
}
int main(int argc, char* argv[])
{
av_log_set_callback(custom_output);
return 0;
}
日志信息从重到轻分为Panic、Fatal、Error、Warning、Info、Verbose、Debug几个级别,输出到控制台的颜色也不同。下面的函数输出了几种不同级别的日志。
void test_log(){
av_register_all();
AVFormatContext *obj=NULL;
obj=avformat_alloc_context();
printf("====================================\n");
av_log(obj,AV_LOG_PANIC,"Panic: Something went really wrong and we will crash now.\n");
av_log(obj,AV_LOG_FATAL,"Fatal: Something went wrong and recovery is not possible.\n");
av_log(obj,AV_LOG_ERROR,"Error: Something went wrong and cannot losslessly be recovered.\n");
av_log(obj,AV_LOG_WARNING,"Warning: This may or may not lead to problems.\n");
av_log(obj,AV_LOG_INFO,"Info: Standard information.\n");
av_log(obj,AV_LOG_VERBOSE,"Verbose: Detailed information.\n");
av_log(obj,AV_LOG_DEBUG,"Debug: Stuff which is only useful for libav* developers.\n");
printf("====================================\n");
avformat_free_context(obj);
}
av_log函数要求第一个参数为以指向一个AVClass类型的指针,若没有可以设置为NULL。
日志输出源代码、颜色设置等,参见 FFmpeg源代码简单分析:日志输出系统(av_log()等)。
AVOption
是FFmpeg的选项设置工具。与AVOption最相关的选项设置函数就是av_opt_set()
了。AVOption的核心概念就是“根据字符串操作结构体的属性值”
有关AVOption
函数说明见 libavutil\opt.h
,对于libx264提供的codec选项可以参见libavcodec\libx264.c
。注意不同平台下不同实现option可能不尽一致。见博文 。。。。。option设置。。。。。。。。。
(1)选项设值
对于AVCodecContext
类型,可以使用成员方式访问直接设置,也可以使用av_opt_set_xxx
系列函数设置。例如下面代码中“#if”和“#else”之间代码的作用和“#else”和“#endif”之间代码的作用是一样的。
#if TEST_OPT
av_opt_set(pCodecCtx,"b","400000",0); //bitrate
//Another method
//av_opt_set_int(pCodecCtx,"b",400000,0); //bitrate
av_opt_set(pCodecCtx,"time_base","1/25",0); //time_base
av_opt_set(pCodecCtx,"bf","5",0); //max b frame
av_opt_set(pCodecCtx,"g","25",0); //gop
av_opt_set(pCodecCtx,"qmin","10",0); //qmin/qmax
av_opt_set(pCodecCtx,"qmax","51",0);
#else
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
pCodecCtx->max_b_frames=5;
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size=25;
pCodecCtx->qmin = 10;
pCodecCtx->qmax = 51;
#endif
(2)选项取值
同理,av_opt_get()
可以将结构体的属性值以字符串的形式返回回来。
// 使用 char val_str[50]; 貌似无效
char *val_str=(char *)av_malloc(50);
//preset: ultrafast, superfast, veryfast, faster, fast,
//medium, slow, slower, veryslow, placebo
av_opt_set(pCodecCtx->priv_data,"preset","slow",0);
//tune: film, animation, grain, stillimage, psnr,
//ssim, fastdecode, zerolatency
av_opt_set(pCodecCtx->priv_data,"tune","zerolatency",0);
//profile: baseline, main, high, high10, high422, high444
av_opt_set(pCodecCtx->priv_data,"profile","main",0);
//print
av_opt_get(pCodecCtx->priv_data,"preset",0,(uint8_t **)&val_str);
printf("preset val: %s\n",val_str);
av_opt_get(pCodecCtx->priv_data,"tune",0,(uint8_t **)&val_str);
printf("tune val: %s\n",val_str);
av_opt_get(pCodecCtx->priv_data,"profile",0,(uint8_t **)&val_str);
printf("profile val: %s\n",val_str);
av_free(val_str);
对于非字符串选项,如int类型,可以使用av_opt_get_int函数,其他类型类似。例如
int64_t gop;
av_opt_get_int(pCodecCtx->priv_data,"g",0,&gop);
printf("gop val: %lld\n",gop);
(3)选项查找
可以通过av_opt_find()
获取结构体中任意选项的AVOption结构体,并打印AVOption的值(亦可以通过调试查看)。
void print_opt(const AVOption *opt_test){
printf("====================================\n");
printf("Option Information:\n");
printf("[name]%s\n",opt_test->name);
printf("[help]%s\n",opt_test->help);
printf("[offset]%d\n",opt_test->offset);
switch(opt_test->type){
case AV_OPT_TYPE_INT:{
printf("[type]int\n[default]%d\n",opt_test->default_val.i64);
break;
}
case AV_OPT_TYPE_INT64:{
printf("[type]int64\n[default]%lld\n",opt_test->default_val.i64);
break;
}
case AV_OPT_TYPE_FLOAT:{
printf("[type]float\n[default]%f\n",opt_test->default_val.dbl);
break;
}
case AV_OPT_TYPE_STRING:{
printf("[type]string\n[default]%s\n",opt_test->default_val.str);
break;
}
case AV_OPT_TYPE_RATIONAL:{
printf("[type]rational\n[default]%d/%d\n",opt_test->default_val.q.num,opt_test->default_val.q.den);
break;
}
default:{
printf("[type]others\n");
break;
}
}
printf("[max val]%f\n",opt_test->max);
printf("[min val]%f\n",opt_test->min);
if(opt_test->flags&AV_OPT_FLAG_ENCODING_PARAM){
printf("Encoding param.\n");
}
if(opt_test->flags&AV_OPT_FLAG_DECODING_PARAM){
printf("Decoding param.\n");
}
if(opt_test->flags&AV_OPT_FLAG_AUDIO_PARAM){
printf("Audio param.\n");
}
if(opt_test->flags&AV_OPT_FLAG_VIDEO_PARAM){
printf("Video param.\n");
}
if(opt_test->unit!=NULL)
printf("Unit belong to:%s\n",opt_test->unit);
printf("====================================\n");
}
void test()