带有 aecho 的 FFmpeg 过滤器配置无法配置所有链接和格式 - avfilter_graph_config

问题描述

我正在按照FFMpeg的官方教程创建过滤器链。 This 教程展示了如何通过链传递数据:

它使用的过滤器链是:*(输入)->abuffer->volume-> aformat -> abuffersink ->(输出

这是我的代码 - 对不起,锅炉代码,这只是 ffmpeg 方式:(

    frame = av_frame_alloc();
    filtergraph = avfilter_graph_alloc();

    if (!frame) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not allocate memory for frame");
        return;
    }

    if (!filtergraph) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor FXProcessor! %s",av_err2str(AVERROR(ENOMEM)));
        return;
    }

    const AVFilter *abuffer;
    const AVFilter *abuffersink;
    AVFilterContext *aformat_ctx;
    const AVFilter *aformat;
    AVFilterContext *choisen_beat_fx_ctx;
    const AVFilter *choisen_beat_fx;

    /* Create the abuffer filter;
     * it will be used for Feeding the data into the graph. */
    abuffer = avfilter_get_by_name("abuffer");
    if (!abuffer) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not find the abuffer filter!");
        return;
    }
    abuffer_ctx = avfilter_graph_alloc_filter(filtergraph,abuffer,"src");
    if (!abuffer_ctx) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not allocate the abuffer_ctx instance! %s",av_err2str(AVERROR(ENOMEM)));
        return;
    }

    char ch_layout[64];
    /* Set the filter options through the AVOptions API. */
    av_get_channel_layout_string(ch_layout,sizeof(ch_layout),AV_CH_LAYOUT_STEREO);
    av_opt_set(abuffer_ctx,"channel_layout",ch_layout,AV_OPT_SEARCH_CHILDREN);
    av_opt_set(abuffer_ctx,"sample_fmt",av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT),AV_OPT_SEARCH_CHILDREN);
    av_opt_set_q(abuffer_ctx,"time_base",(AVRational) {1,defaultSampleRate},AV_OPT_SEARCH_CHILDREN);
    av_opt_set_int(abuffer_ctx,"sample_rate",defaultSampleRate,AV_OPT_SEARCH_CHILDREN);
    /* Now initialize the filter; we pass NULL options,since we have already
     * set all the options above. */

    if (avfilter_init_str(abuffer_ctx,nullptr) < 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not initialize the abuffer filter!");
        return;
    }

    // Todo: select FX's dynamically
    /* Create aecho filter. */
    if (true) {

        choisen_beat_fx = avfilter_get_by_name("volume");
        if (!choisen_beat_fx) {
            *mediaLoadPointer = Failed_TO_LOAD;
            LOGE("FXProcessor::FXProcessor Could not find the aecho filter!");
            return;
        }

        choisen_beat_fx_ctx = avfilter_graph_alloc_filter(filtergraph,choisen_beat_fx,"echo");
        if (!choisen_beat_fx_ctx) {
            *mediaLoadPointer = Failed_TO_LOAD;
            LOGE("FXProcessor::FXProcessor Could not allocate the choisen_beat_fx_ctx instance! %s",av_err2str(AVERROR(ENOMEM)));
            return;
        }

        av_opt_set    (choisen_beat_fx_ctx,"volume",AV_STRINGIFY(0.5),AV_OPT_SEARCH_CHILDREN);

        if (avfilter_init_str(choisen_beat_fx_ctx,nullptr) < 0) {
            *mediaLoadPointer = Failed_TO_LOAD;
            LOGE("FXProcessor::FXProcessor Could not initialize the choisen_beat_fx_ctx filter!");
            return;
        }
    }

    /* Create the aformat filter;
     * it ensures that the output is of the format we want. */
    aformat = avfilter_get_by_name("aformat");
    if (!aformat) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not find the aformat filter!");
        return;
    }
    aformat_ctx = avfilter_graph_alloc_filter(filtergraph,aformat,"aformat");
    if (!aformat_ctx) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not allocate the aformat instance!");
        return;
    }

    av_opt_set(aformat_ctx,"sample_fmts",AV_OPT_SEARCH_CHILDREN);
    av_opt_set_int(aformat_ctx,"sample_rates",AV_OPT_SEARCH_CHILDREN);
    av_get_channel_layout_string(ch_layout,AV_CH_LAYOUT_STEREO);
    av_opt_set(aformat_ctx,"channel_layouts",AV_OPT_SEARCH_CHILDREN);

    if (avfilter_init_str(aformat_ctx,nullptr) < 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not initialize the aformat filter!");
        return;
    }

    /* Finally create the abuffersink filter;
     * it will be used to get the filtered data out of the graph. */
    abuffersink = avfilter_get_by_name("abuffersink");
    if (!abuffersink) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not find the abuffersink filter!");
        return;
    }

    abuffersink_ctx = avfilter_graph_alloc_filter(filtergraph,abuffersink,"sink");
    if (!abuffersink_ctx) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not allocate the abuffersink instance!");
        return;
    }

    /* This filter takes no options. */
    if (avfilter_init_str(abuffersink_ctx,nullptr) < 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Could not initialize the abuffersink instance.!");
        return;
    }

    /* Connect the filters;
     * in this simple case the filters just form a linear chain. */
    if (avfilter_link(abuffer_ctx,choisen_beat_fx_ctx,0) != 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Error connecting filters.!");
        return;
    }
    if (avfilter_link(choisen_beat_fx_ctx,aformat_ctx,0) != 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Error connecting filters.!");
        return;
    }
    if (avfilter_link(aformat_ctx,abuffersink_ctx,0) != 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Error connecting filters.!");
        return;
    }

    /* Configure the graph. */
    if (avfilter_graph_config(filtergraph,nullptr) < 0) {
        *mediaLoadPointer = Failed_TO_LOAD;
        LOGE("FXProcessor::FXProcessor Error configuring the filter graph!");
        return;
    }

当链是这个代码时工作正常

  • (input) -> abuffer -> aecho-> aformat -> abuffersink -> (output)

但是,我想使用 adelay 而不是 volume 过滤器。所以我想要:

它使用的过滤器链是:*(输入)->abuffer->volume-> aformat -> abuffersink ->(输出

我在

处更改了代码
choisen_beat_fx = avfilter_get_by_name("volume");

choisen_beat_fx = avfilter_get_by_name("aecho");

删除该行

av_opt_set    (choisen_beat_fx_ctx,AV_OPT_SEARCH_CHILDREN);

一切都很顺利,直到最后一行。 avfilter_graph_config 失败并返回负值。函数文档:

avfilter_graph_config:检查有效性并配置所有链接和 图表中的格式。

所以我的猜测是我需要额外的链接来将 aecho 插入我的链?如何将 aecho 插入我的过滤器链?

解决方法

好的,问题是,我需要使用 aresample 过滤器进行编译才能使其正常工作。我重新编译,现在神奇地工作了。

这是我发现问题的方法。创建通用日志回调:

void ffmpegErrorCallback(void *ptr,int level,const char *fmt,va_list vargs) {
    LOGE("ffmpegErrorCallback Error Occurred! Err: %s",fmt);
}

av_log_set_level(AV_LOG_ERROR);
av_log_set_callback(ffmpegErrorCallback);

FFmpeg 现在会将错误记录为人类可读的消息。它告诉我它找不到 aresample 过滤器。这就是我解决问题的方法。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...