2017-01-30 5 views
1

Ich versuche FFmpeg C api zu verwenden, um einen Filter zu erstellen, um zwei Audio-Streams zusammenzuführen. Versuchen, den Code von hier zu folgen: Implementing a multiple input filter graph with the Libavfilter library in Android NDK"ungültiges Argument" für av_buffersrc_write_frame/av_buffersrc_add_frame

Alles scheint in Ordnung zu sein.

aber sobald ich av_buffersrc_write_frame nennen (oder av_buffersrc_add_frame oder av_buffersrc_add_frame_flags, spielt es keine Rolle), FFmpeg meldet nur „ungültig Argument“ und nichts anderes - eine völlig nutzlos Fehlermeldung, da es alles bedeuten könnte.
Welches Argument ist ungültig? Was ist daran falsch? Niemand weiß.

Ich Initialisierung des Graphen und die Kontexte der Pufferquellen für die spätere Verwendung wie dieses „Grabbing“:

// 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; 
    } 
} 

Es gibt absolut keine Fehler bei der Initialisierung. Wenigstens hat FFmpeg dies nur zu sagen, was ich denke, sieht gut aus:

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' 

Dann versuche ich, einen Rahmen zu addieren (das vorher decodiert worden ist) wie folgt aus:

// "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; 
} 

Und das Ergebnis ist das erwähnte "ungültige Argument".

Der buffer_source_context ist einer der aus dem obigen Code genannten und der input_frame ist auch völlig in Ordnung. Bevor der Filtercode hinzugefügt wurde, wurde derselbe Frame ohne Probleme an einen Encoder übergeben.

Ich bin ratlos, was der Fehler hier sein könnte. Ich protokolliere FFmpeg-Fehler auf der niedrigst möglichen Ebene, aber es wird kein einziger Fehler angezeigt. Ich benutze FFmpeg 3.1.1.

+0

A -1, eine enge Abstimmung, Entfernen eines Tags und kein Kommentar zu einem davon. Warum, das ist furchtbar nützlich, danke;) – TheSHEEEP

+0

Ich bin nicht ganz sicher durch das Aussehen Ihres Codes, aber sollte es nicht der 'Filterkontext' oder der 'buffer_source_context' beim Schreiben des Rahmens sein? – WLGfx

+0

Ich bin mir nicht sicher, ob ich das verstehe. AVFilterContext * ist der Typ von 'buffer_source_context'. Und Sie müssen der Pufferquelle eines Filtergraphen Frames hinzufügen, damit FFmpeg sie verarbeiten kann. Und wie ich geschrieben habe, ist 'buffer_source_context' einer der Pufferquellkontexte aus dieser Zeile: 'inputs [i] .buffer_source_context = filterContext;' – TheSHEEEP

Antwort

1

Wie sich herausstellte, war das Problem die Initialisierung des AVCodecContext der Eingänge (Decoder).
Wie Sie in meiner Frage sehen können, sind die channel_layouts der Pufferfilter auf 3 gesetzt (was Stereo bedeutet). Dieser Wert wurde direkt vom AVCodecContext der Eingänge übernommen.

Also würde man natürlich annehmen, dass Frames, die von den Eingängen gelesen und decodiert werden, in diesem Kanallayout wären.
Aus irgendeinem Grund waren sie nicht. Stattdessen musste ich sowohl channel_layout als auch requested_channel_layout über den AVCodecContext auf stereo (AV_CH_LAYOUT_STEREO) vor öffnen.

Was mich am Ende zu dieser Schlussfolgerung brachte, war die bittere Pille, den FFmpeg-Quellcode zu betrachten (Live-Debugging ist in diesem Fall nicht möglich) und die Orte zu finden, die einen ungültigen Argumentfehler für diese Funktion auslösen könnten.
Ich fand viele Orte ähnlich wie diese:

int ch = src->channels; 

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

So überprüfte ich alle Kandidaten eine Nichtübereinstimmung in den Kanal-Layouts, um endlich herauszufinden, dort war.

Wenn die FFmpeg Autoren einige Zeit verbringen würden, um tatsächlich hilfreiche Fehlermeldungen mit solchen Fällen auszugeben, hätte ich fast zwei Tage nicht die Nadel im Heuhaufen gesucht.

Code funktioniert immer noch nicht, weil scheinbar mehr als eine Eingabe auf einmal Av_read_frame fast zum Stillstand bringt, aber das hat nichts mit dieser Frage zu tun. Aber der Teil des Codes in der Frage war immer korrekt (zumindest nehme ich das an), der Fehler war woanders.

Verwandte Themen