"invalid argument" av_buffersrc_write_frame/av_buffersrc_add_frame

"invalid argument" for av_buffersrc_write_frame / av_buffersrc_add_frame

本文关键字:frame buffersrc av add write invalid argument      更新时间:2023-10-16

我正在尝试使用FFmpeg C api创建一个过滤器来合并两个音频流。尝试遵循这里的代码:在Android NDK 中使用Libavfilter库实现多输入过滤器图

一切似乎都很好。

然而,一旦我调用av_buffersrc_write_frame(或av_bufffersrc_add_frame或av_bbuffersrc_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。

因此,自然地,人们会假设从输入读取和解码的帧将在该信道布局中
由于某种原因,他们没有。相反,在打开AVCodecContext之前,我必须将其上的channel_layoutrequested_channel_layout都设置为立体声(AV_CH_LAYOUT_stereo)

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

int ch = src->channels;
if (!ch) {
ret = AVERROR(EINVAL);
goto fail;
}

所以我检查了所有的候选人,最终发现频道布局不匹配。

如果FFmpeg的作者们能花一些时间在这种情况下输出真正有用的错误消息,我就不会浪费近两天的时间在大海捞针了。

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