JLayer 总是抛出 ArrayIndexOutOfBounds 异常



我正在使用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)
您需要

在每次调用readFrame()之间调用Bitstream.closeFrame() - 所以

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

从外观上看,您正在尝试让解码器一遍又一遍地解码同一帧。这是行不通的,BitStream 具有内部状态(指向下一个要读取的位的指针),该状态在解码帧后变得无效。异常指示它尝试读取缓冲区容量。

对于每个帧,您只能调用一次 decodeFrame()。

编辑:堆栈跟踪不显示您实际读取数据的位置。由于异常在组件绘制方法中,因此我假设您在另一个线程或其他地方读取框架。

另外,查看您的getPCM()方法:该代码将永远不起作用。您不能为每个帧创建一个新的解码器实例 - 这根本不起作用,因为解码器有很多内部状态,这是必要的,并且取决于以前的帧。您只能创建一次解码器,并将其重新用于所有帧。

看看javazoom.jl.player.Player的源代码 - 它在其play(int)方法中展示了一个正确的播放循环(它只有几行长,但你必须遵守那里显示的调用顺序,否则你会破坏解码器和解码器持有的对象的正确状态)。

相关内容

  • 没有找到相关文章

最新更新