如何将参考影片添加到代码中的ffmpeg psnr过滤器中(计算psnr)

时间:2016-10-14 11:37:26

标签: filter ffmpeg

我只想了解如何在代码中使用ffmpeg中的psnr过滤器。

我已遵循https://ffmpeg.org/ffmpeg-filters.html#psnr中所述的代码:

sprintf(args, "movie=ref_movie.avi [main];[main][ref] psnr=\"stats_file=stats.log\" [out]");
err = avfilter_graph_create_filter(&psnrCtx,  psnrFilter, "psnr", args, NULL, m_filterGraph);
if ( err < 0 ) {
    avfilter_graph_free(&m_filterGraph);
    m_filterGraph = NULL;
    return false; }

但错误信息会回复给我:

Option 'movie' not found

我也试试这个:

sprintf(args, "stats_file=stats.log");
err = avfilter_graph_create_filter(&psnrCtx,  psnrFilter, "psnr", args, NULL, m_filterGraph);
if ( err < 0 ) {
   avfilter_graph_free(&m_filterGraph);
   m_filterGraph = NULL;
   return false; }
err = avfilter_link(last_ctx, 0, psnrCtx, 0);
if ( err < 0 ) {
   avfilter_graph_free(&m_filterGraph);
   m_filterGraph = NULL;
   return false;}

...  
err = avfilter_graph_config(m_filterGraph, NULL);
if ( err < 0 ) {
   avfilter_graph_free(&m_filterGraph);
   m_filterGraph = NULL;
   return false;
}

但是错误消息返回给我:

Input pad "reference" with type video of the filter instance "psnr" of psnr not connected to any source

我在代码中搜索psnr过滤器,但没有太多关于它的信息。任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:3)

您正在使用avfilter_graph_create_filter()创建过滤器图形而不是过滤器。请改用avfilter_graph_parse2()来创建整个过滤器图表。

过滤器图形与您在ffmpeg命令行中的-filter_complex中输入的图形相同。例如,参见这个用作获取电影元素的输入字符串的示例:

ffmpeg -filter_complex 'movie=file.mpg[in];movie=ref.mpg[ref];[in][ref]psnr[out]' -map '[out]' -f null -

在解析过滤器图表之前,不要忘记调用avfilter_register_all()av_register_all(),否则电影元素将不会被注册。

完整的示例代码:

#include <assert.h>

#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavformat/avformat.h"

int main() {
    AVFilterGraph *filter_graph;
    AVFilterInOut *inputs = NULL, *outputs = NULL;
    AVFilterContext *buffersink_ctx;
    AVFrame *f;

    avfilter_register_all();
    av_register_all();

    filter_graph = avfilter_graph_alloc();
    int ret;

    ret = avfilter_graph_parse2(filter_graph,
                                "movie=file.mpg[in];"
                                "movie=ref.mpg[ref];"
                                "[in][ref]psnr[out];"
                                "[out]buffersink",
                                &inputs, &outputs);
    if (ret < 0) return ret;
    ret = avfilter_graph_config(filter_graph, NULL);
    if (ret < 0) return ret;
    buffersink_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffersink_3");
    assert(buffersink_ctx != NULL);
    f = av_frame_alloc();

    for (;;) {
        ret = av_buffersink_get_frame(buffersink_ctx, f);
        if (ret < 0) break;
        av_frame_unref(f);
    }

    av_frame_free(&f);
    avfilter_graph_free(&filter_graph);

    return 0;
}

要从循环内的f中提取每帧PSN值,请使用以下内容:

static void parse_psnr(AVFrame *f) {
    AVDictionary *metadata = av_frame_get_metadata(f);
    float psnr[4];

#define parse(a, b) \
    sscanf(av_dict_get(metadata, a, NULL, 0)->value, "%f", &b)

    parse("lavfi.psnr.psnr.y", psnr[0]);
    parse("lavfi.psnr.psnr.u", psnr[1]);
    parse("lavfi.psnr.psnr.v", psnr[2]);
    parse("lavfi.psnr.psnr_avg", psnr[3]);

}

要获取打印到stdout(序列范围的PSNR)的最终值,可以使用av_log_set_callback()设置日志回调并适当地解析字符串。