gpt4 book ai didi

java - 使用 JLayer 解码流式 mp3 数据时出现问题

转载 作者:行者123 更新时间:2023-12-02 22:23:45 25 4
gpt4 key购买 nike

我正在尝试使用 JLayer java lib 来解码 mp3 数据流。我有一个回调,当下一块 mp3 数据从网络到达时,它被异步调用。到达的每个块在 byte[] 中包含 4 个 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;
}

日志输出
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 有任何经验,可以看到我的方法存在明显问题?

最佳答案

有什么问题?首先,许多 mp3 显然会以静音开始。其次,由于 PCM 合成的性质,填充多相合成滤波器组需要一段时间,因此第一个样本很可能为零,合成滤波器从其 16 个组中的所有零开始。

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

编辑:您显然不熟悉 MP3 的内部工作方式,因此我将详细介绍基础知识。

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

为了将解码与分配不均的帧数据解耦,解码器将每帧接收到的打包数据送入一个称为“位保留”的 FIFO 缓冲区,该缓冲区基本上负责记住从前一帧借用的所有数据,直到它被请求解码流水线。

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

整个解码管道引入了相当多的延迟。由于管道的延迟和比特保留借用机制的进一步复杂化,在 MP3 中正确查找并非易事。

关于java - 使用 JLayer 解码流式 mp3 数据时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16738918/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com