c++ - "invalid argument"用于 av_buffersrc_write_frame/av_buffersrc_add_frame

标签 c++ ffmpeg

我正在尝试使用 FFmpeg C api 创建一个过滤器来合并两个音频流。尝试遵循此处的代码:Implementing a multiple input filter graph with the Libavfilter library in Android NDK

一切似乎都很好。

但是,一旦我调用 av_buffersrc_write_frame(或 av_buffersrc_add_frame 或 av_buffersrc_add_frame_flags,这并不重要),FFmpeg 只会报告“无效参数”,而不是其他任何东西 - 一个完全无用的错误消息,因为它可能意味着一切。
哪个论点无效?这有什么不对?没有人知道。

我正在初始化图形并“抓取”缓冲区源的上下文以供以后使用,如下所示:

// Alloc filter graph
*filter_graph = avfilter_graph_alloc();
if ((*filter_graph) == NULL) {
    os::log("Error: Cannot allocate filter graph.");
    return AVERROR(ENOMEM);
}

// Building the filter string, ommitted

int result = avfilter_graph_parse2(*filter_graph, filterString.c_str(), &gis, &gos, NULL);
if (result < 0)
{
    char errorBuf[1024];
    av_make_error_string(errorBuf, 1024, result);
    log("Error: Parsing filter string: %s", errorBuf);
    return AVERROR_EXIT;
}

// Configure the graph
result = avfilter_graph_config(*filter_graph, NULL);
if (result < 0)
{
    char errorBuf[1024];
    av_make_error_string(errorBuf, 1024, result);
    log("Error: Configuring filter graph: %s", errorBuf);
    return AVERROR_EXIT;
}

// Get the buffer source and buffer sink contexts
for (unsigned int i = 0; i < (*filter_graph)->nb_filters; ++i) {
    AVFilterContext* filterContext = (*filter_graph)->filters[i];

    // The first two filters should be the abuffers
    std::string name = filterContext->name;
    if (name.find("abuffer") != name.npos && i < 2) {
        inputs[i].buffer_source_context = filterContext;
    }

    // abuffersink is the one we need to get the converted frames from
    if (name.find("abuffersink") != name.npos) {
        *buffer_sink_context = filterContext;
    }
}

初始化绝对没有错误。至少 FFmpeg 只能这样说,我认为这看起来不错:

FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] Setting 'time_base' to value '1/48000'
FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] Setting 'sample_rate' to value '48000'
FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] Setting 'sample_fmt' to value '1'
FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] Setting 'channel_layout' to value '3'
FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] Setting 'channels' to value '2'
FFMPEG: [Parsed_abuffer_0 @ 0ddfe840] tb:1/48000 samplefmt:s16 samplerate:48000 chlayout:3
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] Setting 'time_base' to value '1/44100'
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] Setting 'sample_rate' to value '44100'
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] Setting 'sample_fmt' to value '1'
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] Setting 'channel_layout' to value '3'
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] Setting 'channels' to value '2'
FFMPEG: [Parsed_abuffer_1 @ 0ddfe500] tb:1/44100 samplefmt:s16 samplerate:44100 chlayout:3
FFMPEG: [Parsed_volume_3 @ 0ddfe580] Setting 'volume' to value '2'
FFMPEG: [Parsed_aresample_4 @ 0ddfe660] Setting 'sample_rate' to value '48000'
FFMPEG: [Parsed_aformat_5 @ 0ddfe940] Setting 'sample_fmts' to value 'fltp'
FFMPEG: [Parsed_aformat_5 @ 0ddfe940] Setting 'channel_layouts' to value '3'

然后,我尝试添加一个帧(已预先解码),如下所示:

// "buffer_source_context" is one of the "inputs[i].buffer_source_context" from the code above
int result = av_buffersrc_write_frame(  buffer_source_context,
                                            input_frame);
if (result < 0) {
    char errorBuf[1024];
    av_make_error_string(errorBuf, 1024, result);
    log("Error: While adding to buffer source: %s", errorBuf);
    return AVERROR_EXIT;
}

结果就是提到的“无效参数”。

buffer_source_context 是上面代码中提到的内容之一,input_frame 也非常好。 在添加过滤代码之前,相同的帧被毫无问题地传递给编码器。

我不知道这里可能有什么错误。我在尽可能低的级别记录 FFmpeg 错误,但没有显示任何错误。我正在使用 FFmpeg 3.1.1。

最佳答案

事实证明,问题出在输入(解码器)的 AVCodecContext 的初始化上。
正如您在我的问题中看到的,缓冲过滤器的 channel_layouts 设置为 3(这意味着立体声)。该值直接取自输入的 AVCodecContext。

因此,很自然地,人们会假设从输入读取和解码的帧将在该 channel 布局中。
出于某种原因,他们不是。相反,我必须将 AVCodecContext 上的 channel_layoutrequested_channel_layout 设置为立体声 (AV_CH_LAYOUT_STEREO) 然后打开它。

最终让我得出这个结论的是吞下查看 FFmpeg 源代码的苦果(在这种特定情况下无法进行实时调试)并找到可能为该函数抛出无效参数错误的地方。< br/> 我发现很多类似的地方:

    int ch = src->channels;

    if (!ch) {
        ret = AVERROR(EINVAL);
        goto fail;
    }

所以我检查了所有候选者,最终发现 channel 布局不匹配。

如果 FFmpeg 的作者愿意花一些时间在这种情况下输出实际有用的错误消息,我就不会浪费将近两天的时间来大海捞针。

代码仍然不起作用,因为似乎一次输入多个输入会使 av_read_frame 几乎停止,但这与这个问题无关。但是问题中的代码部分总是正确的(至少我是这么认为的),错误在其他地方。

关于c++ - "invalid argument"用于 av_buffersrc_write_frame/av_buffersrc_add_frame,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41937841/

相关文章:

c++ - 按位运算符和符号类型

ffmpeg - 缺少对 FFMPEG 的依赖

ffmpeg - 使用 Cypress 时未定义 SharedArrayBuffer

ios - 如何在 iOS 中使用 ffmpeg 剪切视频?

c++ - 为什么将音频流添加到ffmpeg的libavcodec输出容器会导致崩溃?

c++ - 方法定义中的变量名称是否必须与 C++ 中的声明名称相同?

c++ - 我们如何从它的函数尝试处理程序跳回到构造函数主体?

java - 将来自 AVPacket : problems with output buffers 的字节数据提供给 MediaCodec

c++ - 使用带有模板化类参数的可变参数模板

具有抽象类指针的对象的 C++ 拷贝