6

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

残留オーディオを探して取得できないようにするために何をすべきかについてのアイデアはありますか? ありがとう!

4

2 に答える 2

3

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

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

更新として、上記のバグは確かに問題ですが、特にAACには2番目のバグがあります。

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

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

自分でffmpegをビルドできる場合は、AVCodec ff_aac_decoderの定義の下部(ファイルの下部にあります)に.flush=flushを追加することで修正できます。

ffmpegの人たちに知らせますので、うまくいけばメインブランチに含めることができます。

于 2012-04-23T21:34:06.850 に答える
2

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

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

1つの解決策は、シークを開始する前に1つの余分なパケット(私の例ではパケット26)を取得し、オフラインバッファーでデコードし、フェードアウトを適用してから、再生キューに入れることだと思います。目的の場所を探したら、最初のパケット(私の例では66)を取得し、それを別のオフラインバッファーにデコードし、フェードインを適用して、それを再生キューに入れます。これにより、スムーズな音波とアーティファクトのないシークが保証されます。

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

これは、この問題にどのように対処できるかについての私の推測です。これは明らかに解決された問題なので、オープンソースのオーディオプレーヤーも見て、シークがどのように実装されているかを確認することをお勧めします。Audacity、Totem、Banshee、RhythmBox、Amarok、VLCなどのプログラム、またはGStreamerなどのフレームワークは学ぶのに良い例かもしれません。彼らが注目すべき技術を採用していることに気づいたら、ここでテーマについて報告してください。人々は自分が何であるかを学びたいと思うでしょう。幸運を!

于 2011-11-11T07:31:31.327 に答える