FFMPEG视频滤镜(一)

前言

介绍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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值