使用JLayer解码流式mp3数据的问题

时间:2013-05-24 15:48:38

标签: java audio mp3 signal-processing jlayer

我试图使用JLayer java lib来解码mp3数据流。我有一个回调,当下一个mp3数据块从网络到达时,它被异步调用。每个到达的块包含4个byte[]格式的mp3帧。此数据传递到short[] decode(byte[] mp3_data)进行解码,输出为short[] pcm音频缓冲区。使用concatArray()方法将缓冲区附加到while循环内部,直到所有mp3帧都用完为止。我遇到的问题是前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;
    }

LOG OUTPUT

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有任何关系,他们可以看到我的方法明显的问题?

2 个答案:

答案 0 :(得分:3)

是什么问题?首先,很多mp3会显然以沉默开始。其次,由于PCM合成的性质,填充多相合成滤波器组需要一段时间,因此第一个样本非常可能是零,合成滤波器开始时其全部为零。银行。

查看整个帧以确定其是否为静音,而不是10个样本。

编辑:你显然不熟悉MP3内部的工作原理,所以我将详细介绍一下基础知识。

MP3帧包含标题字(讲述比特率,采样率和立体声类型)以及一些控制信息。该框架的大部分仅包含打包数据。与谈到MP3时所暗示的内容相反,打包数据并不完全属于那个单帧。帧可以从其前任“借用”打包数据空间,并且它还可以携带属于下一帧的数据。 CBR(恒定比特率)只是告诉所有帧具有相等的大小,但是由于从先前帧的借用,特别复杂的帧可以通过从前一帧中借用空间来分配更多比特(该决定)由编码器在创建流时创建)。 VBR只是增加了额外的可能性来改变帧大小,技术上CBR流已经能够为每帧分配可变数量的比特,只是在比VBR更严格的限制内。

为了将解码与不均匀分配的帧数据解耦,解码器将每帧接收到的打包数据馈送到称为“比特储备”的FIFO缓冲区,该缓冲区基本上要记住从先前帧借来的所有数据都要记住,直到它为止。请求解码管道。

然后对来自比特储备的数据进行霍夫曼解码,通过一些复杂的数学处理来产生时频采样。为了将它们转换成PCM,将它们馈入合成滤波器。合成滤波器记住固定时间段内的每个时间频率样本(技术上步骤,挂钟时间随采样率而变化)到其“银行”中的过去(每次 - 频率样本影响多个PCM样本),其中最老的样本被最新推出。

整个解码流程引入了相当多的延迟。正确地在MP3 中寻找 是非常重要的,因为管道延迟并且由于bitreserve借用机制而进一步复杂化。

答案 1 :(得分:0)

我使用JLayer进行了一些mp3解码,我只是面对同样的问题:对于每一帧我都会得到很多零,然后是几个非零的pcm样本。

我想decodeFrame()方法应该返回解码的真实pcm样本,因为它 已经处理,重新量化,霍夫曼解码,多相重新合成为我编码。

这样,总的pcm样本应该更多,所以我决定剥离所有pcm零样本,并以wav格式写出样本。我知道它有点'怪异'但是......现在听起来真的应该!! [/ p>

我解码的歌曲是CBR格式,单声道只是为了让这些东西更简单。

我认为也许所有这些零都与bit-reservoir有关,所以如果使用的歌曲和psycoacustic模型并不真正需要它们,那么它们将被设置为零。然后我做了其他测试。

我所争论的是,如果每个第3层帧在2304 pcm样本中被解码,则在单声道歌曲中可能只有前半部分非零,而秒半部分全部为零。 但是,如果我使用立体声MP3 ...几乎所有的样本都是非零的,除了很明显在歌曲的开头。

所以看起来这个'问题'只出现在单声道编码的mp3中。 使用stero 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文件听起来比以前好多了。