繁体   English   中英

av_buffersrc_write_frame / av_buffersrc_add_frame 的“无效参数”

[英]"invalid argument" for av_buffersrc_write_frame / av_buffersrc_add_frame

我正在尝试使用 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 的初始化。
正如您在我的问题中看到的,abuffer 过滤器的 channel_layouts 设置为 3(这意味着立体声)。 该值直接取自输入的 AVCodecContext。

因此,自然而然地,人们会假设从输入读取和解码的帧将在该通道布局中。
出于某种原因,他们不是。 相反,我不得不同时设置channel_layoutrequested_channel_layout打开它之前的AVCodecContext立体声(AV_CH_LAYOUT_STEREO)。

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

    int ch = src->channels;

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

因此,我检查了所有候选对象,最终发现通道布局不匹配。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM