2017-01-30 3 views
1

Я пытаюсь использовать FFmpeg C api для создания фильтра для объединения двух аудиопотоков. Попытка выполнить код отсюда: Implementing a multiple input filter graph with the Libavfilter library in Android NDK«invalid argument» для av_buffersrc_write_frame/av_buffersrc_add_frame

Все, кажется, в порядке.

Однако, как только я называю 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; 
} 

И результатом является упомянутый «недопустимый аргумент».

Buff_source_context является одним из тех, что отмечены в коде выше, и input_frame отлично подходит. Перед добавлением кода фильтрации один и тот же кадр был передан вместо кодера без проблем.

Я в недоумении от того, что может быть здесь. Я регистрирую ошибки FFmpeg на минимально возможном уровне, но не отображается ни одна ошибка. Я использую FFmpeg 3.1.1.

+0

A -1, закрытое голосование, удаление тега и отсутствие комментариев к нему. Почему, это ужасно полезно, спасибо;) – TheSHEEEP

+0

Я не совсем уверен в внешности вашего кода, но разве это не «фильтрконтекст» или «buffer_source_context» при записи фрейма? – WLGfx

+0

Я не уверен, что понимаю. AVFilterContext * - это тип «buffer_source_context». И вы должны добавить кадры в источник буфера графа фильтра, чтобы FFmpeg обрабатывал их. И, как я писал, «buffer_source_context» является одним из контекстов источника буфера из этой строки: «Входы [i] .buffer_source_context = filterContext;» – TheSHEEEP

ответ

1

Как оказалось, проблема заключалась в инициализации AVCodecContext входов (декодеров).
Как вы можете видеть в моем вопросе, channel_layouts фильтров abuffer установлен на 3 (что означает стерео). Это значение было непосредственно взято из AVCodecContext входов.

Таким образом, можно предположить, что кадры, считанные и декодированные с входов, будут расположены в макете канала.
По какой-то причине они не были. Вместо этого мне пришлось установить channel_layout и requested_channel_layout на AVCodecContext на стерео (AV_CH_LAYOUT_STEREO) до, открыв его.

Что в итоге привело меня к такому выводу, проглотил горькую пилюлю, глядя на исходный код FFmpeg (в этом конкретном случае невозможно провести прямую отладку) и найти места, которые могли бы вызвать недопустимую ошибку аргумента для этой функции.
я нашел много мест, подобных этому:

int ch = src->channels; 

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

Так я проверил всех кандидатов, чтобы окончательно выяснить, существует несоответствие в макетах канала.

Если авторам FFmpeg было бы посвящено некоторое время для вывода действительно полезных сообщений об ошибках с такими случаями, я бы не потерял почти два дня, ища иглу в стоге сена.

Код по-прежнему не работает, поскольку, казалось бы, наличие более одного входа сразу же обрабатывает av_read_frame почти до упора, но это не связано с этим вопросом. Но часть кода в вопросе всегда была правильной (по крайней мере, я предполагаю, что), ошибка была где-то в другом месте.

Смежные вопросы