使用libavfilter 为实时流添加滤镜

131 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

使用libavfilter 为实时流添加滤镜

添加滤镜一般是使用FFMpeg进行滤镜添加,在ffmpeg 中提供了libavfiler库来完成该操作。

而添加滤镜的基本操作如下图(引用自雷神):

在这里插入图片描述

从上图我们可以清楚的看到,滤镜的加载和解码部分几乎是完全独立的,现在我大致的用文字描述一下步骤。

  1. 注册滤镜信息。

  2. 创建滤波器主结构体,用于整合所有的滤波过程。

  3. 创建滤波器输入、输出或者其他复杂滤波。

  4. 解析字符串,并构建该字符串所描述的滤波图

  5. 提交滤波器

接下来上代码:


// 1.初始化滤波器结构体

filter_graph = avfilter_graph_alloc();

// 2.获取两个特殊的滤波器,输入和输出(buffer/buffersink)

AVFilter *buffersrc = avfilter_get_by_name("buffer");

AVFilter *buffersink = avfilter_get_by_name("buffersink");

// 3.为滤波器添加像素等配置

snprintf(args, sizeof(args),

"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",

pCodecContext->width, pCodecContext->height, AV_PIX_FMT_YUV420P,

1, 1,

16, 9);

// 4.创建输入滤波器

ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);

if (ret < 0) {

NSLog(@"创建滤镜输入失败");

return NO;

}

// 5.创建输出滤波器的配置结构体

AVBufferSinkParams *buffersink_params;

enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };

buffersink_params = av_buffersink_params_alloc();

buffersink_params->pixel_fmts = pix_fmts;

ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, buffersink_params, filter_graph);

av_free(buffersink_params);

if (ret < 0) {

NSLog(@"创建buffersink失败");

return false;

}

// 6.创建输入输出的列表(包含名称及下一个输入或者输出)

AVFilterInOut *outputs = avfilter_inout_alloc();

AVFilterInOut *inputs = avfilter_inout_alloc();

outputs->name = av_strdup("in");

outputs->filter_ctx = buffersrc_ctx;

outputs->pad_idx = 0;

outputs->next = NULL;

inputs->name = av_strdup("out");

inputs->filter_ctx = buffersink_ctx;

inputs->pad_idx = 0;

inputs->next = NULL;

// 7.解析字符串,构建滤波器

const char *filter_descr = "lutyuv='u=128:v=128'";

ret = avfilter_graph_parse(filter_graph, filter_descr, inputs, outputs, NULL);

if (ret < 0) {

NSLog(@"水印加载失败");

return NO;

}

// 8.上传滤波器

ret = avfilter_graph_config(filter_graph, NULL);

if (ret < 0) {

NSLog(@"水印连接存在错误显示");

return NO;

}

在构建完成滤波器之后,我们只需要把avcodec_receive_frame或者avcodec_decode_video2解码出来的AVFrame 添加到滤波器中,就完成了输入的动作,代码如下:


if (av_buffersrc_add_frame(buffersrc_ctx, pFrame) < 0) {

printf( "Error while feeding the filtergraph\n");

break;

}

上述操作之后,所有入队列的AVFrame数据可以通过对应的方法获取出来,代码如下:


int ret = av_buffersink_get_frame(buffersink_ctx, outFrame);

if (ret < 0) {

NSLog(@"从滤镜获取avframe 数据失败");

break;

}

至此,整个的滤波器添加工作已经完成。

本文参考资料

雷神AVFilter

滤波结构体