2

JLayer を使用して MP3 をデコードし、PCM データとして保存しています。ただし、使用する MP3 ファイルに関係なく、インデックス 443 の ArrayIndexOutOfBoudnsException が常に発生します。これは特定の MP3 でのみ発生すると聞いていますが、再生するすべての MP3 のすべてのフレームで発生しています。

private short[] getPCM(Header frameHeader, Bitstream bs) {
    short[] pcm = null;
    try {
        Decoder d = new Decoder();
        SampleBuffer buffer = (SampleBuffer) d.decodeFrame(frameHeader, bs);
        pcm = buffer.getBuffer();
    } catch (ArrayIndexOutOfBoundsException | DecoderException e) {
        System.err.println("JLayer, stap it");
    }
    return pcm;
}

メソッドは次のコードで呼び出されます。

while ((frameHeader = bs.readFrame()) != null) {
    short[] pcm = getPCM(frameHeader, bs);

    for(short i : pcm){
        try {
            os.write(i);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }       
}

スタックトレース:

java.lang.ArrayIndexOutOfBoundsException: 433
at javazoom.jl.decoder.Bitstream.get_bits(Unknown Source)
at javazoom.jl.decoder.LayerIIIDecoder.decode(Unknown Source)
at javazoom.jl.decoder.LayerIIIDecoder.decodeFrame(Unknown Source)
at javazoom.jl.decoder.Decoder.decodeFrame(Unknown Source)
at com.dentonposs.Canvas.getPCM(Canvas.java:70)
at com.dentonposs.Canvas.paintComponent(Canvas.java:48)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$700(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
4

2 に答える 2

1

Bitstream.closeFrame()各呼び出しの間に呼び出す必要がありますreadFrame()-そう

while ((frameHeader = bs.readFrame()) != null) {
    short[] pcm = getPCM(frameHeader, bs);

    bs.closeFrame();

    .. more ..
于 2013-11-11T11:21:54.187 に答える
1

見た目から、デコーダーに同じフレームを何度もデコードさせようとしています。それは機能しません。BitStream には、フレームをデコードした後に無効になる内部状態 (次に読み取るビットへのポインター) があります。この例外は、バッファ容量を超えて読み取ろうとしていることを示しています。

各フレームに対して一度だけ decodeFrame() を呼び出す必要があります。

編集:スタックトレースには、実際にデータを読み取った場所は表示されません。例外はコンポーネントのペイント メソッド内にあるため、別のスレッドまたは別の場所でフレームを読み取ることを前提としています。

また、getPCM() メソッドを見ると、そのコードは機能しません。フレームごとに新しいデコーダー インスタンスを作成することはできません。デコーダーには必要な内部状態が多く、前​​のフレームに依存するため、単純に機能しません。デコーダーは 1 回だけ作成し、すべてのフレームで再利用する必要があります。

javazoom.jl.player.Player のソースを見てください - play(int) メソッドで適切な再生ループを示しています (数行の長さですが、そこに示されている呼び出し順序に従う必要があります。デコーダーおよびデコーダーが保持するオブジェクト内の適切な状態を破棄します)。

于 2013-11-10T20:05:17.523 に答える