2

JLayer Java lib を使用して mp3 データ ストリームをデコードしようとしています。mp3 データの次のチャンクがネットワークから到着したときに非同期的に呼び出されるコールバックがあります。到着する各チャンクには、4 つの mp3 フレームが含まれていbyte[]ます。このデータは に渡されてshort[] decode(byte[] mp3_data)デコードされ、出力はshort[]pcm オーディオ バッファになります。バッファーはconcatArray()、すべての mp3 フレームが使い果たされるまで、メソッドを使用して while ループ内に追加されます。私が抱えている問題は、データの最初の 2 または場合によっては 3 フレームがゼロで満たされた pcm バッファを返し、最後の 2 または 1 フレームが有効な 16 ビット オーディオ値を返すことです。

   public short[] decode(byte[] mp3_data) throws IOException {

        SampleBuffer output = null;
        InputStream inputStream = new ByteArrayInputStream(mp3_data);
        short[] pcmOut = {};
        try {
            Bitstream bitstream = new Bitstream(inputStream);
            Decoder decoder = new Decoder();
            boolean done = false;
            int i = 0;
            while (! done) {
                Header frameHeader = bitstream.readFrame();
                if (frameHeader == null) {
                    done = true;
                } else {
                    output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
                    short[] next = output.getBuffer();
                    pcmOut = concatArrays(pcmOut, next);
                }

                bitstream.closeFrame();
                i++;
            }
            return pcmOut;

        } catch (BitstreamException e) {
            throw new IOException("Bitstream error: " + e);
        } catch (DecoderException e) {
            Log.w(LOG_TAG, "Decoder error", e);
        }
        return null;
    }


    short[] concatArrays(short[] A, short[] B) {

        int aLen = A.length;
        int bLen = B.length;
        short[] C= new short[aLen+bLen];

        System.arraycopy(A, 0, C, 0, aLen);
        System.arraycopy(B, 0, C, aLen, bLen);

        return C;
    }

ログ出力

Frame 0 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 1 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 2 len: 2304, First 10 samples: [-4128, -4158, -4252, -3934, -4452, -3775, -4799, -3762, -5430, -4092]
Frame 3 len: 2304, First 10 samples: [-18050, -19711, -18184, -19753, -18143, -19595, -17046, -18362, -14773, -15933]

Frame 0 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 1 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 2 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 3 len: 2304, First 10 samples: [2455, 2345, 5253, 5129, 6716, 6442, 7475, 6866, 8461, 7444]

Frame 0 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 1 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 2 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 3 len: 2304, First 10 samples: [951, 1322, 1497, 1929, 1615, 2198, 1320, 2134, 1040, 2114]

Frame 0 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 1 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 2 len: 2304, First 10 samples: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Frame 3 len: 2304, First 10 samples: [-10213, -9578, -11691, -10867, -13686, -12770, -14837, -13874, -15619, -14574]

4 フレームの mp3 チャンクごとに pcm バッファを出力すると、最初の 2 ~ 3 個のバッファがゼロで埋められていることがわかります。私の方法で明らかな問題を見ることができるJLayerの経験を持っている人はいますか?

4

2 に答える 2

3

問題は何ですか?まず、多くの mp3 は明らかに無音で始まります。第 2 に、PCM 合成の性質上、多相合成フィルター バンクを埋めるのに時間がかかるため、最初のサンプルがゼロになる可能性が非常に高く、合成フィルターは 16 のバンクですべてゼロから開始します。

10 サンプルではなく、フレーム全体を見て無音かどうかを判断します。

編集: どうやら MP3 が内部でどのように機能するかについて詳しくないので、基本について少し詳しく説明します。

MP3 フレームには、ヘッダー ワード (ビット レート、サンプル レート、およびステレオ タイプを示す) と、いくつかの制御情報が含まれています。フレームの大部分は、パックされたデータだけで構成されています。MP3 について語られるときにほとんど暗示されることとは反対に、パックされたデータはその単一のフレームに完全に属していません。フレームは、前のフレームからパックされたデータ空間を「借りる」ことができ、次のフレームに属するデータを運ぶこともできます。CBR(固定ビットレート)は、すべてのフレームが同じサイズであることを示しています、しかし、前のフレームから借用するため、特に複雑なフレームには、前のフレームからスペースを借用することにより、より多くのビットが割り当てられる場合があります (この決定は、ストリームの作成時にエンコーダーによって行われます)。VBR は、フレーム サイズを変更する可能性を追加するだけです。技術的には、CBR ストリームは、VBR よりも厳しい制限内で、フレームごとに可変量のビットを割り当てることができます。

不均等に割り当てられたフレーム データからデコードを分離するために、デコーダは、各フレームで受信したパックされたデータを「ビット リザーブ」と呼ばれる FIFO バッファに供給します。デコード パイプライン。

次に、ビット リザーブからのデータがハフマン デコードされ、複雑な計算によって処理され、時間-周波数サンプルが生成されます。それらを PCM に変換するために、それらは合成フィルターに供給されます。合成フィルターは、各時間-周波数サンプルを一定期間 (技術的にはステップ、壁時計時間はサンプルレートによって異なります)、過去の「バンク」に記憶します (各時間-周波数サンプルは複数の PCM サンプルに影響を与えます)。 、最も古いものが最新のものによって押し出されます。

このデコード パイプライン全体で、かなりのレイテンシが発生します。MP3 内を適切にシークすることは、パイプラインのレイテンシーのために自明ではなく、bitreserve 借用メカニズムによってさらに複雑になります。

于 2013-05-24T15:57:10.760 に答える
0

私は JLayer を使用して mp3 デコードで少し遊んでいますが、同じ問題に直面しています。フレームごとにゼロがたくさんあり、ゼロ以外の pcm サンプルがいくつかあります。

私は、decodeFrame() メソッドがデコードされた実際の pcm サンプルを返す必要があると思います。

このようにして、pcm サンプルの合計が必要以上になるので、すべての pcm ゼロ サンプルを取り除き、サンプルを wav 形式で書き出すことにしました。私はそれが少し「奇妙」であることを知っていますが..今では本当にあるべきように聞こえます!!

私がデコードした曲は CBR 形式で、単純化するためだけにモノチャンネルになっています。

これらのゼロはすべてビットリザーバーと関係があるのではないかと考えたので、使用されている曲と心理音響モデルが実際にそれらを必要としない場合は、ゼロに設定されています。それから私は他のテストをしました。

私が主張したことは、各レイヤー 3 フレームが 2304 pcm サンプルでデコードされた場合、モノラル ソングでは前半のみが非ゼロで、後半はすべてゼロである可能性があるということです。しかし、ステレオ mp3 を使用すると、曲の最初の部分を除いて、ほとんどすべてのサンプルが非ゼロになります。

したがって、この「問題」は、モノラルでエンコードされた mp3 でのみ発生するようです。ステレオ mp3 では、すべての正しい pcm サンプルを取得できます。モノ mp3 では、フレームごとにデコードされた pcm サンプルの前半を取得するだけで済みます。

しかし、これはオーディオ圧縮アルゴリズムのスペースの無駄ではありませんか? まだ何かを失っているのかもしれません…

これが少し役立つことを願っています...

編集

私が見ることができるように、チャンネルはフレームにインターリーブされています.2チャンネルのmp3の場合、デコードされた2304 pcmのサンプルは次のとおりです。

L[0]、R[0]、L[1]、R[1]、L[2]、R[2]、.......、L[1152]、R[1152]

ouptut wav ファイルで生成されたサウンドは、以前よりもはるかに優れたものになりました。

于 2013-06-05T10:16:37.370 に答える