FFmpeg之Filter FilterChain FilterGraph

基础

  1. filter: 数据处理器
  2. filter_chain: 链表链接链接所有的filter
  3. filter_graph:数据处理管理器
  4. 查看filter的相关事项:ffmpeg -h filter=filter_name
$ ffmpeg -h filter=crop
Filter crop
Crop the input video.
Inputs:
#0: default (video)
Outputs:
#0: default (video)
crop AVOptions:
out_w <string> ..FV..... set the width crop area expression (default "iw")
w <string> ..FV..... set the width crop area expression (default "iw")
out_h <string> ..FV..... set the height crop area expression (default "ih")
h <string> ..FV..... set the height crop area expression (default "ih")
x <string> ..FV..... set the x crop area expression (default "(in_w-out_w)/2")
y <string> ..FV..... set the y crop area expression (default "(in_h-out_h)/2")
keep_aspect <boolean> ..FV..... keep aspect ratio (default false)
exact <boolean> ..FV..... do exact cropping (default false)

初始化过滤器

创建graph

//avfilter_register_all(); // 4.0后被删除,同avdevice_regeister_all
AVFilterGraph *filter_graph = avfilter_graph_alloc();
if (!filter_graph) {
printf("failed to create filter graph\n");
return -1;
}

创建chain

编码创建

创建输入buffer

char args[512];
memset(args, 0, 512);
sprintf(args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
in_width,
in_height,
AV_PIX_FMT_YUV420P,
1,
25,
1,
1);
AVFilter *buffser_src =
avfilter_get_by_name("buffer"); // AVFilterGraph的输入源
AVFilterContext *buffer_src_ctx;
ret = avfilter_graph_create_filter(
&buffer_src_ctx, buffser_src, "in", args, NULL, filter_graph);
if (ret < 0) {
printf("failed to create filter buffersrc\n");
return -1;
}

输出buffersink

// sink filter
AVBufferSinkParams *buffer_sink_paras;
AVFilterContext *buffer_sink_ctx;
AVFilter *buffer_sink = avfilter_get_by_name("buffersink");
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
buffer_sink_paras = av_buffersink_params_alloc();
buffer_sink_paras->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&buffer_sink_ctx,
buffer_sink,
"out",
NULL,
buffer_sink_paras,
filter_graph);
if (ret < 0) {
printf("failed to create split filter\n");
return -1;
}

个人需要使用的filter

// split fitler
AVFilter *split_filter = avfilter_get_by_name("split");
AVFilterContext *split_filter_ctx;
ret = avfilter_graph_create_filter(&split_filter_ctx,
split_filter,
"split",
"outputs=2",
NULL,
filter_graph);
if (ret < 0) {
printf("failed to create split filter\n");
return -1;
}
// crop filter
AVFilter *crop_filter = avfilter_get_by_name("crop");
AVFilterContext *crop_filter_ctx;
ret = avfilter_graph_create_filter(&crop_filter_ctx,
crop_filter,
"crop",
"out_w=iw:out_h=ih/2:x=0:y=0",
NULL,
filter_graph);
if (ret < 0) {
printf("failed to create crop filter\n");
return -1;
}
// vflip filter
AVFilter *vflip_filter = avfilter_get_by_name("vflip");
AVFilterContext *vflip_filter_ctx;
ret = avfilter_graph_create_filter(
&vflip_filter_ctx, vflip_filter, "vflip", NULL, NULL, filter_graph);
if (ret < 0) {
printf("failed to create vflip filter\n");
return -1;
}
// overlap filter
AVFilter *overlay_filter = avfilter_get_by_name("overlay");
AVFilterContext *overlay_filter_ctx;
ret = avfilter_graph_create_filter(&overlay_filter_ctx,
overlay_filter,
"overlay",
"y=0:H/2",
NULL,
filter_graph);
if (ret < 0) {
printf("failed to create overlay filter\n");
return -1;
}

link需要的filters

// src filter to split filter
ret = avfilter_link(buffer_src_ctx, 0, split_filter_ctx, 0);
if (ret != 0) {
printf("failed to link src filter and split filter\n");
return -1;
}
// split filter's first pad to overlay fiilter's main pad
ret = avfilter_link(split_filter_ctx, 0, overlay_filter_ctx, 0);
if (ret != 0) {
printf("failed to link split filter's first pad and overlay filter\n");
return -1;
}
// split fitler's second pad to crop filter
ret = avfilter_link(split_filter_ctx, 1, crop_filter_ctx, 0);
if (ret != 0) {
printf("failed to link split filter's second pad and crop filter\n");
return -1;
}
// crop filter to vflip filter
ret = avfilter_link(crop_filter_ctx, 0, vflip_filter_ctx, 0);
if (ret != 0) {
printf("failed to link crop filter and vflip filter\n");
return -1;
}
// vflip filter to overlay filtes'second pad
ret = avfilter_link(vflip_filter_ctx, 0, overlay_filter_ctx, 1);
if (ret != 0) {
printf("failed to link vflip filter and overlay's second filter\n");
return -1;
}
// overlay filter to sink filter
ret = avfilter_link(overlay_filter_ctx, 0, buffer_sink_ctx, 0);
if (ret != 0) {
printf("failed to link overlay filter and sink filter\n");
return -1;
}

初始化graph

// check filter graph
ret = avfilter_graph_config(filter_graph, NULL);
if (ret < 0) {
printf("failed in filter graph\n");
return -1;
}

命令创建

初始化命令行

char filter_args[1024] = { 0 };
snprintf(
filter_args,
sizeof(filter_args),
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d[v0];" // Parsed_buffer_0
"[v0]split[main][tmp];" // Parsed_split_1
"[tmp]crop=iw:ih/2:0:0,vflip[flip];" // Parsed_crop_2 Parsed_vflip_3
"[main][flip]overlay=0:H/2[result];" // Parsed_overlay_4
"[result]buffersink", // Parsed_buffersink_5
width,
height,
format,
1,
25,
1,
1);

利用命令行初始化graph

AVFilterInOut *inputs = NULL;
AVFilterInOut *outputs = NULL;
int ret = avfilter_graph_parse2(filter_graph, filter_args, &inputs, &outputs);
if (ret < 0) {
printf("cannot parse graph\n");
return ret;
}
ret = avfilter_graph_config(filter_graph, NULL);
if (ret < 0) {
printf("cannot config graph\n");
return ret;
}

获取输入buffer和输出buffersink

mainsrc_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffer_0");
if (!mainsrc_ctx) {
printf("avfilter_graph_get_filter Parsed_buffer_0 failed\n");
return -1;
}
resultsink_ctx =
avfilter_graph_get_filter(filter_graph, "Parsed_buffersink_5");
if (!resultsink_ctx) {
printf("avfilter_graph_get_filter Parsed_buffer_5 failed\n");
return -1;
}

处理数据

向buffer中添加数据

if (av_buffersrc_add_frame(mainsrc_ctx, frame_in) < 0) {
printf("error while add frame\n");
break;
}

从buffersink中获取数据

ret = av_buffersink_get_frame(resultsink_ctx, frame_out);
if (ret < 0)
break;

其他业务

// output Y U V
if (frame_out->format == AV_PIX_FMT_YUV420P) {
for (int i = 0; i < frame_out->height; ++i)
fwrite(frame_out->data[0] + frame_out->linesize[0] * i,
1,
frame_out->width,
outFile);
for (int i = 0; i < frame_out->height / 2; ++i)
fwrite(frame_out->data[1] + frame_out->linesize[1] * i,
1,
frame_out->width / 2,
outFile);
for (int i = 0; i < frame_out->height / 2; ++i)
fwrite(frame_out->data[2] + frame_out->linesize[2] * i,
1,
frame_out->width / 2,
outFile);
}
posted @   flxx  阅读(209)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示