【问题标题】:C++ - applying filter in ffmpegC ++ - 在ffmpeg中应用过滤器
【发布时间】:2015-09-18 17:12:00
【问题描述】:

我正在尝试使用 ffmpeg(最新版本)对帧进行去隔行扫描。与this问题相关,我可以用这句话得到我想要的过滤器:

AVFilter *filter = avfilter_get_by_name("yadif");

之后,我将过滤器上下文打开为:

AVFilterContext *filter_ctx;
avfilter_open(&filter_ctx, filter, NULL);

我的第一个问题是关于这个函数的。 Visual Studio 警告我 avfilter_open 已弃用。 有什么选择?

之后,我会这样做:

avfilter_init_str(filter_ctx, "yadif=1:-1");

而且总是失败。我试过“1:-1”而不是“yadif=1:-1”,但也总是失败,我应该使用什么参数?

编辑:值“1”或“2”,例如,它可以工作。调试它,我发现使用其中一个值,该函数使用mode=1mode=2。这些值的解释在这个link

然后,我有一个AVFrame *frame,这是我想要去隔行扫描的帧。当最后一句起作用时,我将启动过滤器和他的上下文。 如何将此过滤器应用于我的框架?

感谢您的帮助。

【问题讨论】:

  • 至于你的第一个问题,显然你应该使用的函数是 avfilter_graph_alloc_filter() (avfilter_open() 应该只是它的包装器)。
  • 谁能帮助我?我被这个问题困住了。我尝试了一些代码示例作为filtering_video.c,但它对我没有帮助。

标签: c++ ffmpeg


【解决方案1】:

我知道你的问题已经过去一年多了,但最近我不得不使用隔行扫描 DVB-TS 流,所以我可能可以帮助其他遇到这个问题的人。

这些 sn-ps 来自我编写的成品播放器

初始化过滤器图:

void VideoManager::init_filter_graph(AVFrame *frame) {
    if (filter_initialised) return;

    int result;

    AVFilter *buffer_src   = avfilter_get_by_name("buffer");
    AVFilter *buffer_sink  = avfilter_get_by_name("buffersink");
    AVFilterInOut *inputs  = avfilter_inout_alloc();
    AVFilterInOut *outputs = avfilter_inout_alloc();

    AVCodecContext *ctx = ffmpeg.vid_stream.context;
    char args[512];

    int frame_fix = 0; // fix bad width on some streams
    if (frame->width < 704) frame_fix = 2;
    else if (frame->width > 704) frame_fix = -16;

    snprintf(args, sizeof(args),
         "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
         frame->width + frame_fix,
         frame->height,
         frame->format,// ctx->pix_fmt,
         ctx->time_base.num,
         ctx->time_base.den,
         ctx->sample_aspect_ratio.num,
         ctx->sample_aspect_ratio.den);

    const char *description = "yadif=1:-1:0";

    LOGD("Filter: %s - Settings: %s", description, args);

    filter_graph = avfilter_graph_alloc();
    result = avfilter_graph_create_filter(&filter_src_ctx, buffer_src, "in", args, NULL, filter_graph);
    if (result < 0) {
        LOGI("Filter graph - Unable to create buffer source");
        return;
    }

    AVBufferSinkParams *params = av_buffersink_params_alloc();
    enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };

    params->pixel_fmts = pix_fmts;
    result = avfilter_graph_create_filter(&filter_sink_ctx, buffer_sink, "out", NULL, params, filter_graph);
    av_free(params);
    if (result < 0) {
        LOGI("Filter graph - Unable to create buffer sink");
        return;
    }

    inputs->name        = av_strdup("out");
    inputs->filter_ctx  = filter_sink_ctx;
    inputs->pad_idx     = 0;
    inputs->next        = NULL;

    outputs->name       = av_strdup("in");
    outputs->filter_ctx = filter_src_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

    result = avfilter_graph_parse_ptr(filter_graph, description, &inputs, &outputs, NULL);
    if (result < 0) LOGI("avfilter_graph_parse_ptr ERROR");

    result = avfilter_graph_config(filter_graph, NULL);
    if (result < 0) LOGI("avfilter_graph_config ERROR");

    filter_initialised = true;
}

在处理来自流的视频数据包时,检查它是否是隔行帧并将帧发送到过滤器。然后过滤器会将去交错的帧返回给您。

void FFMPEG::process_video_packet(AVPacket *pkt) {
    int got;
    AVFrame *frame = vid_stream.frame;
    avcodec_decode_video2(vid_stream.context, frame, &got, pkt);

    if (got) {
        if (!frame->interlaced_frame) {     // not interlaced
            Video.add_av_frame(frame, 0);
        } else {
            if (!Video.filter_initialised) {
                Video.init_filter_graph(frame);
            }

            av_buffersrc_add_frame_flags(Video.filter_src_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
            int c = 0;

            while (true) {
                AVFrame *filter_frame = ffmpeg.vid_stream.filter_frame;

                int result = av_buffersink_get_frame(Video.filter_sink_ctx, filter_frame);

                if (result == AVERROR(EAGAIN) || result == AVERROR(AVERROR_EOF)) break;
                if (result < 0) return;

                Video.add_av_frame(filter_frame, c++);
                av_frame_unref(filter_frame);
            }
        }
    }
}

希望这对任何人都有帮助,因为查找有关 ffmpeg 的信息很难。

【讨论】:

  • 谢谢,你的帖子对我帮助很大
  • 感谢您的代码,它帮了很大的忙。我的代码成功运行到 avfilter_graph_parse_ptr 函数。此时它返回 -22 并且日志显示“没有这样的过滤器:'yadif'。我已经使用 avfilter_register_all() 注册了过滤器。我查看了 FFMPEG 的构建脚本,没有显示 -disable-filters。您是否必须更改构建中的任何内容才能使过滤器为自己工作。谢谢
  • 事实证明,我必须在构建脚本中显式添加 --enable-filter=yadif。
猜你喜欢
  • 2021-06-24
  • 1970-01-01
  • 2019-07-02
  • 2011-09-05
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多