视频特效滤镜 via FFmpeg Filter

视频特效定义

视频特效(Video effects 或 Visual effects)是对每帧图像进行各种数字化处理达到的效果。如对画面的尺寸、位置、亮度及色度等参数进行处理,就可获得缩放、旋转、黑白、油画等各种效果。

常见的特效技术有:缩放、旋转、裁剪、叠加、老电影、黑白、淡入淡出、水印、去噪、慢动作、2D 转 3D 等等。

FFmpeg filter

关于 FFmpeg filter 的架构,请参考我的另一篇文章 音频特效插件 via FFmpeg

av_filter_base 类

用 FFmpeg 的 filter 开发时主要区别就是把不同的 filter description string 传到 filtergraph 中,然后设定 sink 端 prefer 的参数,其他部分几乎是一样的,所以我把 filter 的使用封装成了一个 av_filter_base 类,代码请参考 这里

av_filter_base::video_filter_init_begin 函数

创建 video source 和 sink filter。

int video_filter_init_begin(AVCodecContext *dec_ctx, AVRational stream_time_base)
{
    int hr = -1;
    m_filter_graph = avfilter_graph_alloc();
    RETURN_IF_NULL(m_filter_graph);
    
    char args[512] = {0};
    _snprintf_s(args, sizeof(args),
        "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
        dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
        stream_time_base.num, stream_time_base.den,
        dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);

    /* buffer video source: the decoded frames from the decoder will be inserted here. */
    const AVFilter *buffersrc = avfilter_get_by_name("buffer");
    hr = avfilter_graph_create_filter(&m_buffersrc_ctx, buffersrc, "in", args, NULL, m_filter_graph);
    RETURN_IF_FAILED(hr);

    /* buffer video sink: to terminate the filter chain. */
    const AVFilter *buffersink = avfilter_get_by_name("buffersink");
    hr = avfilter_graph_create_filter(&m_buffersink_ctx, buffersink, "out", NULL, NULL, m_filter_graph);
    RETURN_IF_FAILED(hr);
    
    return hr;
}

Video_filter 子类

init_opts 函数需要子类去重写,下面的例子设定了 sink filter 支持的视频格式。

class Video_filter : public av_filter_base
{
public:
    Video_filter()
        : m_enc_ctx(NULL)
    { }
    
    int init( AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, 
        AVRational stream_time_base, const char *filters_descr )
    {
        m_enc_ctx = enc_ctx;
        return av_filter_base::init(dec_ctx, stream_time_base, filters_descr);
    }
    
protected:
    virtual int init_opts()
    {
        RETURN_IF_NULL(m_enc_ctx);
        return av_opt_set_bin( m_buffersink_ctx, "pix_fmts", (uint8_t*)&m_enc_ctx->pix_fmt,
 	   	 	   sizeof(m_enc_ctx->pix_fmt), AV_OPT_SEARCH_CHILDREN );
    }
private:
    AVCodecContext* m_enc_ctx;
};

av_filter_base::filter_init_end 函数

请看 这里,一模一样。

av_filter_base::do_filter 函数

这里重载了两个 do_filter 函数,一个是通过回调函数处理每一帧,代码请看 这里;另一个是返回帧集合,代码如下:

int do_filter(AVFrame* in_frame, std::queue<AVFrame*>& out_frames)
{
    RETURN_IF_NULL(in_frame);
    int hr = -1;
    in_frame->pts = in_frame->best_effort_timestamp;

    /* push the decoded frame into the filtergraph */
    hr = av_buffersrc_add_frame_flags(m_buffersrc_ctx, in_frame, AV_BUFFERSRC_FLAG_KEEP_REF);
    RETURN_IF_FAILED(hr);

    /* pull filtered frames from the filtergraph */
    AVFrame* filt_frame = NULL;
    while (true) {
        filt_frame = av_frame_alloc();
        RETURN_IF_NULL(filt_frame);

        hr = av_buffersink_get_frame(m_buffersink_ctx, filt_frame);
        if (hr == AVERROR(EAGAIN) || hr == AVERROR_EOF)
            break;
        GOTO_IF_FAILED(hr);

        out_frames.push(filt_frame);
        filt_frame = NULL;
    }
}

其他框架的滤镜

  • 关于 DirectShow 的视频滤镜请参考 这里
  • 关于 Media Foundation 的视频滤镜请参考 这里

Blueware
EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值