前言
介绍FFmpeg中旋转rotate
、拼接hstack
、翻转hflip
、边缘edgedetect
视频滤镜的使用方法。
1、 旋转滤镜
1.1 名称:rotate
1.2 语法:-angle:旋转角度,-ow:输出图像宽度,-oh:输出图像高度;如:"angle=0.5*PI:ow=1920:oh=1080"
1.3 其他:若需要实时旋转图像,则需要动态创建和销毁滤镜。
1.4 示例代码
static int initFilter(AVCodecContext * codecContext0, AVCodecContext * codecContext1, double angle)
{
int ret = 0;
const AVFilter *bufSrc = NULL;
const AVFilter *rotate = NULL;
const AVFilter *bufSink = NULL;
AVFilterInOut *input = NULL;
AVFilterInOut *output = NULL;
char args[128] = {0};
if(NULL == filterGraph)
filterGraph = avfilter_graph_alloc();
else
{
return true;
}
input = avfilter_inout_alloc();
output = avfilter_inout_alloc();
bufSrc = avfilter_get_by_name("buffer");
rotate = avfilter_get_by_name("rotate");
bufSink = avfilter_get_by_name("buffersink");
if(NULL == filterGraph || NULL == input || NULL == output)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "alloc failed! :" << endl;
return false;
}
if(NULL == bufSrc || NULL == bufSink)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_get_by_name failed! :" << endl;
return false;
}
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", codecContext0->width, codecContext0->height, codecContext0->pix_fmt, 1, 25, 1, 25);
// cout << args << endl;
// src 0
ret = avfilter_graph_create_filter(&bufSrcContext[0], bufSrc, "in0", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// rotate
snprintf(args, sizeof(args), "angle=%f*PI:ow=%d:oh=%d", angle/double(180)
, codecContext0->width+20*16, codecContext0->height+40*16);
cout << args << endl;
ret = avfilter_graph_create_filter(&rotateContext, rotate, "rotate", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// sink
ret = avfilter_graph_create_filter(&bufSinkContext, bufSink, "out", NULL, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
ret = avfilter_link(bufSrcContext[0], 0, rotateContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_link(rotateContext, 0, bufSinkContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_graph_config(filterGraph, NULL);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_config failed! :" << buf << endl;
return false;
}
if(input->next) avfilter_inout_free(&input->next);
if(input )avfilter_inout_free(&input);
if(output) avfilter_inout_free(&output);
return true;
}
2、 左右拼接滤镜
2.1 名称:hstack
2.2 语法:-inputs:输出源数量;如:"inputs=2"
2.3 其他:1)拼接后尺寸会变大,为输入源尺寸的和,buffer in0 + buffer in1;2)引申:上下拼接滤镜vstack
。
2.4 示例代码
static int initFilter(AVCodecContext * codecContext0, AVCodecContext * codecContext1)
{
int ret = 0;
const AVFilter *bufSrc = NULL;
const AVFilter *hstack = NULL;
const AVFilter *bufSink = NULL;
AVFilterInOut *input = NULL;
AVFilterInOut *output = NULL;
char args[128] = {0};
if(NULL == filterGraph)
filterGraph = avfilter_graph_alloc();
else
{
return true;
}
input = avfilter_inout_alloc();
output = avfilter_inout_alloc();
bufSrc = avfilter_get_by_name("buffer");
hstack = avfilter_get_by_name("hstack");
bufSink = avfilter_get_by_name("buffersink");
if(NULL == filterGraph || NULL == input || NULL == output)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "alloc failed! :" << endl;
return false;
}
if(NULL == bufSrc || NULL == bufSink)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_get_by_name failed! :" << endl;
return false;
}
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", codecContext0->width, codecContext0->height, codecContext0->pix_fmt, 1, 25, 1, 25);
cout << args << endl;
// src 0
ret = avfilter_graph_create_filter(&bufSrcContext[0], bufSrc, "in0", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", codecContext0->width, codecContext0->height, codecContext0->pix_fmt, 1, 25, 1, 25);
cout << args << endl;
// src 1
ret = avfilter_graph_create_filter(&bufSrcContext[1], bufSrc, "in1", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// hstack
ret = avfilter_graph_create_filter(&hstackContext, hstack, "hstack", "inputs=2", NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// sink
ret = avfilter_graph_create_filter(&bufSinkContext, bufSink, "out", NULL, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
ret = avfilter_link(bufSrcContext[0], 0, hstackContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_link(bufSrcContext[1], 0, hstackContext, 1);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_link(hstackContext, 0, bufSinkContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_graph_config(filterGraph, NULL);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_config failed! :" << buf << endl;
return false;
}
if(input->next) avfilter_inout_free(&input->next);
if(input )avfilter_inout_free(&input);
if(output) avfilter_inout_free(&output);
return true;
}
3、水平翻转滤镜
3.1 名称:hflip
3.2 语法:无配置参数
3.3 其他:引申:垂直翻转滤镜vflip
3.4 示例代码
static int initFilter(AVCodecContext * codecContext0, AVCodecContext * codecContext1)
{
int ret = 0;
const AVFilter *bufSrc = NULL;
const AVFilter *hflip = NULL;
const AVFilter *bufSink = NULL;
AVFilterInOut *input = NULL;
AVFilterInOut *output = NULL;
char args[128] = {0};
if(NULL == filterGraph)
filterGraph = avfilter_graph_alloc();
else
{
return true;
}
input = avfilter_inout_alloc();
output = avfilter_inout_alloc();
bufSrc = avfilter_get_by_name("buffer");
hflip = avfilter_get_by_name("hflip");
bufSink = avfilter_get_by_name("buffersink");
if(NULL == filterGraph || NULL == input || NULL == output)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "alloc failed! :" << endl;
return false;
}
if(NULL == bufSrc || NULL == bufSink)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_get_by_name failed! :" << endl;
return false;
}
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", codecContext0->width, codecContext0->height, codecContext0->pix_fmt, 1, 25, 1, 25);
cout << args << endl;
// src 0
ret = avfilter_graph_create_filter(&bufSrcContext[0], bufSrc, "in0", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// hflip
ret = avfilter_graph_create_filter(&hflipContext, hflip, "hflip", NULL, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// sink
ret = avfilter_graph_create_filter(&bufSinkContext, bufSink, "out", NULL, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
ret = avfilter_link(bufSrcContext[0], 0, hflipContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_link(hflipContext, 0, bufSinkContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_graph_config(filterGraph, NULL);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_config failed! :" << buf << endl;
return false;
}
if(input->next) avfilter_inout_free(&input->next);
if(input )avfilter_inout_free(&input);
if(output) avfilter_inout_free(&output);
return true;
}
4、边缘检测滤镜
4.1 名称:edgedetect
4.2 语法: -low:低阈值;-high:高阈值;必须在[0,1]范围内选择低阈值和高阈值,低阈值应小于或等于高阈值。-mode:定义绘图模式,‘wires’:黑白;‘colormix’:类似油画效果,卡通效果;默认值为wires。举例:"mode=colormix:low=0.1:high=0.4"
4.3 其他:注意滤镜输出格式为GRAY8(wires)、GBR24P(colormix)而非YUV。
4.4 示例代码
static int initFilter(AVCodecContext * codecContext0, AVCodecContext * codecContext1)
{
int ret = 0;
const AVFilter *bufSrc = NULL;
const AVFilter *edgedetect = NULL;
const AVFilter *bufSink = NULL;
AVFilterInOut *input = NULL;
AVFilterInOut *output = NULL;
char args[128] = {0};
if(NULL == filterGraph)
filterGraph = avfilter_graph_alloc();
else
{
return true;
}
input = avfilter_inout_alloc();
output = avfilter_inout_alloc();
bufSrc = avfilter_get_by_name("buffer");
edgedetect = avfilter_get_by_name("edgedetect");
bufSink = avfilter_get_by_name("buffersink");
if(NULL == filterGraph || NULL == input || NULL == output)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "alloc failed! :" << endl;
return false;
}
if(NULL == bufSrc || NULL == bufSink)
{
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_get_by_name failed! :" << endl;
return false;
}
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", codecContext0->width, codecContext0->height, codecContext0->pix_fmt, 1, 25, 1, 25);
cout << args << endl;
// src 0
ret = avfilter_graph_create_filter(&bufSrcContext[0], bufSrc, "in0", args, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// edgedetect
ret = avfilter_graph_create_filter(&edgedetectContext, edgedetect, "edgedetect", "mode=colormix:low=0.1:high=0.4", NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
// sink
ret = avfilter_graph_create_filter(&bufSinkContext, bufSink, "out", NULL, NULL, filterGraph);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_create_filter failed! :" << buf << endl;
return false;
}
ret = avfilter_link(bufSrcContext[0], 0, edgedetectContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_link(edgedetectContext, 0, bufSinkContext, 0);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_link failed! :" << buf << endl;
return false;
}
ret = avfilter_graph_config(filterGraph, NULL);
if(0 > ret)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avfilter_graph_config failed! :" << buf << endl;
return false;
}
if(input->next) avfilter_inout_free(&input->next);
if(input )avfilter_inout_free(&input);
if(output) avfilter_inout_free(&output);
return true;
}