FFMPEG中avfilter模块 调用流程
FFMPEG中avfilter模块 调用流程
前言
视频拼接
一、avfilter的调用流程图
二、filter的初始化
./ffmpeg -buffer_size 1024000 -i udp://@224.1.1.3:20000 -i udp://@224.1.1.3:20000 -filter_complex "[0:v]crop=900:900:10:10,scale=1920:1080[v0];[1:v]crop=900:900:10:10,scale=1920:1080[v1];[v0][v1]hstack=2[out]" -pkt_size 1316 -map [out] -f mpegts udp://@239.255.255.250:54546
AVFilterLink对应是描述符(scare:90:90)
三、两个特殊的filter
- 1.buffer filter (处理前中的数据放到这里)
- 2 buffersink filter (滤镜处理完成后放到这里)
四、初始化filter的基本过程
- 1、 创建 graph, avfilter_graph_alloc()
- 2、buffer filter 和buffersink filter
- 3、 分析filter描述符,并构造AVFilterGraph
- 4、使构建好的AVFilterGraph生效
init_filter函数实现
/*
* 初始化过滤器
*/
static int32_t init_filters(const char * filter_desc)
{
int32_t ret = 0;
const AVFilter * buffersrc = ::avfilter_get_by_name("buffer");
const AVFilter* buffersink = ::avfilter_get_by_name("buffersink");
AVFilterInOut * inputs = ::avfilter_inout_alloc();
AVFilterInOut* outputs = ::avfilter_inout_alloc();
if (!inputs)
{
printf("alloc inputs failed !!!\n");
return -1;
}
if (!outputs)
{
printf("alloc outputs failed !!!\n");
return -1;
}
char args[1024] = { 0 };
AVRational time_base = g_fmt_ctx_ptr->streams[g_video_stream_index]->time_base;
// video_size=wxh:pix_fmt=xx:time_base=xxx/xxxx:pixel_aspect=xxx/xx
snprintf(args, 1024, "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
g_codec_ctx_ptr->width, g_codec_ctx_ptr->height, g_codec_ctx_ptr->pix_fmt,
time_base.num, time_base.den,
g_codec_ctx_ptr->sample_aspect_ratio.num, g_codec_ctx_ptr->sample_aspect_ratio.den);
//
g_graph = ::avfilter_graph_alloc();
if (!g_graph)
{
printf("alloc graph failed !!!\n");
return -1;
}
//解析描述符 filter_desc
// "[0:v]crop=900:900:10:10,scale=1920:1080[v0];[1:v]crop=900:900:10:10,scale=1920:1080[v1];[v0][v1]hstack=2[out]"
// [a][b]overlay=xxxx[out]
// 输入 buffer filter 创建
// 构造input 和output
// args : 查看参数 命令 : ./ffmpeg -h filter=buffer
ret = ::avfilter_graph_create_filter(&g_buffer_ctx, buffersrc, "in", args, NULL/*buffer 用户数据*/, g_graph);
if (ret < 0)
{
printf("in -->avfilter graph create filter failed !!!");
return ret;
}
// args 参数查看: ./ffmpeg -h filter=buffersink
//buffersink AVOptions :
//pix_fmts <binary> ..FV.......set the supported pixel formats
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
// 输出buffer sink filter 创建
ret = ::avfilter_graph_create_filter(&g_buffersink_ctx, buffersink, "out", NULL, NULL/*buffer 用户数据*/, g_graph);
if (ret < 0)
{
printf("buffer sink filter graph create filter failed !!!");
return -1;
}
ret = av_opt_set_int_list((void *)g_buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
//比较奇怪
// create out
inputs->name = av_strdup("out");
inputs->filter_ctx = g_buffer_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
// outpus 构造
// create in
outputs->name = av_strdup("in");
outputs->filter_ctx = g_buffersink_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
//最重要步骤//
// create filter and add graph for filter desciption
ret = ::avfilter_graph_parse_ptr(g_graph, filter_desc, &inputs, &outputs, NULL );
//graph 生效
ret = ::avfilter_graph_config(g_graph, NULL);
if (ret < 0)
{
printf("filter graph config failed !!!\n");
return ret;
}
::avfilter_inout_free(&inputs);
::avfilter_inout_free(&outputs);
inputs = NULL;
outputs = NULL;
return 0;
}
五、使用filter步骤
- 1、 获得解码后得原始数据 PCM/YUV
- 2、 将数据添加到buffer filter中
- 3、从buffersink 中读取处理好得数据
- 4、当所有数据处理完成后, 释放资源
六、滤镜处理
/***
*解码器视频帧 滤镜处理
*/
static int filter_video(AVFrame* frame, AVFrame*filter_frame)
{
// 向filter buffer中添加视频帧
int32_t ret = ::av_buffersrc_add_frame(g_buffer_ctx, frame);
if (ret < 0)
{
printf("filter buffersrc add frame failed (%s)!!!\n", make_error_string(ret));
return ret;
}
//获取buffersink 处理完成后得数据
while (true)
{
ret = ::av_buffersink_get_frame(g_buffersink_ctx, filter_frame);
if (ret < 0)
{
//有可能buuffersink还没有处理好数据 需要继续获取得啦 ~~~~
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
// 需要释放资源啦 ~~~~
// av_frame_unref(filter_frame);
break;
}
return ret;
}
// 直接写入文件中区
do_frame(filter_frame);
av_frame_unref(filter_frame);
}
av_frame_unref(filter_frame);
}
效果图
总结
filter的demo地址:https://github.com/chensongpoixs/cmp4_box_avi_flv/tree/master/filter