2011-11-03 5 views
6

私はffmpegを使用してオーディオデコーダを実装しています。 オーディオを読み込んでいても既に動作しているのにも関わらず、シーク後にバッファをクリアする方法は見つけられません。FFMPEGシークするとオーディオアーティファクトが発生する

avcodec_flush_buffersは内部バッファに影響を与えていないようです。この問題はすべてのデコーダ(mp3、aac、wma、...)で発生しますが、PCM/WAV(オーディオは圧縮されていないため、デコードするデータを保持するために内部バッファを使用しません)。

コードスニペットは単純です:

説明する
av_seek_frame(audioFilePack->avContext, audioFilePack->stream, posInTimeFrame, AVSEEK_FLAG_ANY); 
avcodec_flush_buffers(audioFilePack->avContext->streams[audioFilePack->stream]->codec); 

audioFilePack->avContext = FormatContext 
audioFilePack->stream = Stream Position (also used to read audio packets) 
audioFilePack->avContext->streams[audioFilePack->stream]->codec = CodecContext for the codec used 

私は残存オーディオを追求しないと得ることができますので、何をすべきか上の任意のアイデアを? ありがとう!

+0

いいえ、アイデアはありませんか?私はこれを引き起こしているかもしれないことについて何も考えずにほぼ2週間これを修正しようとしています...それはうまくいくのでしょうか? –

+0

ffmpeg-user公式メーリングリストにもメッセージが送信されました。まだ必要なヘルプ。 –

+0

アーティファクトをより詳細に記述できますか?彼らはクリックとポップですか? –

答えて

3

シーク機能を備えたオーディオプレーヤーを書いたことはありませんが、これは私が思っていることです。オーディオの各パケットは元の音波のスニペットにデコードされます。通常、これらのスニペットは連続的に隣接し、その結果はアーティファクトのないオーディオとして聞こえる連続波です。シークすると、ファイルの異なる部分から2つのスニペットが互いに当たるように強制します。これは一般に、耳がクリックまたはポップとして知覚する結果的な音波に不連続性を導入するか、アーティファクトを呼んでいる(私は推測している)ようにする。

ここでは具体的な例を示します。シークする前に、オーディオの最初の25パケットを再生したとしましょう。パケット25が最後のサンプルが12345であるウェーブにデコードするとします。パケット25がスピーカーにレンダリングされている間は、パケット66を探します。パケット66の最初のサンプルが-23456であるとしましょう。したがって、デジタルオーディオストリームは、シークの間に12345から-23456にジャンプする。これは巨大な不連続であり、ポップとして聞かれるでしょう。

シーク(私の例ではパケット26)を開始してオフラインバッファにデコードし、フェードアウトを適用して再生キューに入れる前に、1つの余分なパケットを取得することをお勧めします。希望の場所に移動したら、最初のパケット(私のeaxmpleで66)を取り出し、別のオフラインバッファーにデコードし、フェードインを適用して再生キューに入れます。これにより、滑らかな音波とアーチファクトフリーシークが保証されるはずです。

あなたが巧みであれば、フェードアウトやフェードインを短くしたり長くしたりすることができます。私はわずか数ミリ秒でアーティファクトを防ぐのに十分であるはずだと思います。古いパケットと新しいパケットからクロスフェードを適用することもできます。また、シーク前に最後のパケットの最後のサンプル値を書き留めておき、すぐにゼロに引き上げるのではなく、数サンプルにわたってゼロに徐々に下げるだけで十分です。これは、余分なパケットをデコードするより簡単かもしれません。

これは私の推測で、この問題の解決方法です。これは明らかに解決された問題ですので、オープンソースのオーディオプレーヤーを見て、彼らがシークをどのように実装するかを見てみることをお勧めします。 Audacity、Totem、Banshee、RhythmBox、Amarok、VLCのようなプログラムやGStreamerのようなフレームワークは、学ぶ良い例かもしれません。彼らが注目すべきテクニックを採用していることがわかったら、ここでテーマを報告してください。私は人々が彼らが何であるかを学びたいと思うだろうと思う。がんばろう!

3

これはffmpegのバグです。内部バッファがフラッシュされていないので、フラッシュした後にパケット/フレームを取得すると、先読みデータが取得されます。これは3-16-12の時点で修正されているようですので、この修正プログラムを自分で組み込むことも、ffmpegをアップグレードすることもできます。アップデートとして

http://permalink.gmane.org/gmane.comp.video.libav.devel/23455

、上記のバグは確かに問題ですが、AACを有する第二のバグは、特にあります。

5か月前の時点で、別のユーザーがこのバグを発見し、修正されたことが報告されました。 https://ffmpeg.org/trac/ffmpeg/ticket/420

この修正は、内部バッファをクリアするaacdec.cに追加されたフラッシュ関数です。 問題は、aacdec.cで定義された2つのデコーダがあり、1つだけにフラッシュ関数ポインタが与えられていることです。他の(より一般的な)デコーダを使用すると、それでも適切にクリアされません。

あなた自身をffmpegの構築するための位置にいる場合は、修正プログラムがAVCodecのff_aac_decoderの定義の下に .flush =フラッシュ、 を追加することです(ファイルの一番下にある。)

私はffmpegの人たちに知ってもらいたいので、メインブランチに含めることを願っています。

+0

元のポスターがうまくいけばこれを見るので – JHawkZZ

+0

ありがとうございました!私はそれを再コンパイルし、私の代わりの方法を放棄する...醜いが動作します... –