前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FFmpeg filter浅析--下篇

FFmpeg filter浅析--下篇

作者头像
雪月清
发布2022-11-19 10:14:30
6960
发布2022-11-19 10:14:30
举报
文章被收录于专栏:雪月清的随笔雪月清的随笔

在之前的两篇文章中,我们熟悉了FFmpeg filter的基本概念,命令行用法和关键结构体、API使用流程

FFmpeg filter浅析--上篇

FFmpeg filter浅析--中篇

本篇文章我们在之前的Demo演示工程中通过调用libavfilter相关API来实现drawgrid filter效果

(实际敲一遍代码对自己的理解和记忆是非常有帮助的)

先通过命令行演示一下最终要实现的效果:3x3的白色网格

代码的实现并不复杂,在原有视频解码链路中添加filter初始化和后处理的流程即可,流程图如下

初始化filters

代码语言:javascript
复制
void VideoDecoder::initFilters() {
    const AVFilter *bufferSrc = avfilter_get_by_name("buffer");
    const AVFilter *bufferSink = avfilter_get_by_name("buffersink");

    mFilterOutputs = avfilter_inout_alloc();
    mFilterInputs = avfilter_inout_alloc();
    mFilterGraph = avfilter_graph_alloc();
    if (!mFilterOutputs || !mFilterInputs || !mFilterGraph) {
        LOGE("initFilters failed")
        return;
    }

    int ret;
    do {
        char args[512];
        snprintf(args, sizeof(args),
                 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
                 mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt,
                 mTimeBase.num, mTimeBase.den,
                 mCodecContext->sample_aspect_ratio.num, mCodecContext->sample_aspect_ratio.den);
        LOGI("avfilter_graph_create_filter, args: %s", args)
        ret = avfilter_graph_create_filter(&mBufferScrCtx, bufferSrc, "in", args, nullptr, mFilterGraph);
        if (ret < 0) {
            LOGE("Cannot create buffer source, ret: %d", ret)
            break;
        }

        ret = avfilter_graph_create_filter(&mBufferSinkCtx, bufferSink, "out", nullptr, nullptr, mFilterGraph);
        if (ret < 0) {
            LOGE("Cannot create buffer sink, ret: %d", ret)
            break;
        }

        enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
        ret = av_opt_set_int_list(mBufferSinkCtx, "pix_fmts", pix_fmts,
                                  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
        if(ret < 0) {
            LOGE("set output pixel format failed, err=%d", ret);
            break;
        }

        mFilterOutputs->name = av_strdup("in");
        mFilterOutputs->filter_ctx = mBufferScrCtx;
        mFilterOutputs->pad_idx = 0;
        mFilterOutputs->next = nullptr;

        mFilterInputs->name = av_strdup("out");
        mFilterInputs->filter_ctx = mBufferSinkCtx;
        mFilterInputs->pad_idx = 0;
        mFilterInputs->next = nullptr;

        // ffmpeg -h filter=drawgrid
        std::string filterDesc = "drawgrid=w=iw/3:h=ih/3:t=2:c=white@0.5";
        ret = avfilter_graph_parse_ptr(mFilterGraph, filterDesc.c_str(), &mFilterInputs, &mFilterOutputs, nullptr);
        LOGI("avfilter_graph_parse_ptr, ret: %d", ret)
        if (ret < 0) {
            break;
        }

        ret = avfilter_graph_config(mFilterGraph, nullptr);
        LOGI("avfilter_graph_config, ret: %d", ret)
    } while (false);

    if (ret < 0) {
        avfilter_inout_free(&mFilterInputs);
        mFilterInputs = nullptr;
        avfilter_inout_free(&mFilterOutputs);
        mFilterOutputs = nullptr;

        mBufferScrCtx = nullptr;
        mBufferSinkCtx = nullptr;

        avfilter_graph_free(&mFilterGraph);
        mFilterGraph = nullptr;
        LOGE("initFilters failed, clean ctx")
    }
}

filter处理

代码语言:javascript
复制
// send decode frame to filter graph
int ret = av_buffersrc_add_frame_flags(mBufferScrCtx, mAvFrame, AV_BUFFERSRC_FLAG_KEEP_REF);
LOGI("av_buffersrc_add_frame_flags, ret: %d", ret)

// get filter frame from filter graph
ret = av_buffersink_get_frame(mBufferSinkCtx, mFilterAvFrame);
LOGI("av_buffersink_get_frame, ret: %d, format: %d", ret, mFilterAvFrame->format)

再贴一下之前文章发过的FFmpeg过滤器整体处理流程图

Demo运行效果如下

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 雪月清的随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档