【发布时间】:2014-03-23 18:21:36
【问题描述】:
我正在编写一个应用程序来解码MP3 帧。我很难找到标题。
MP3 标头为 32 位,以签名开头:11111111 111
在下面的内部循环中,我寻找这个签名。找到此签名后,我检索接下来的两个字节,然后将标头的后三个字节传递给自定义 MpegFrame() 类。该类验证标头的完整性并从中解析信息。 MpegFrame.isValid() 返回一个布尔值,指示帧头的有效性/完整性。如果header无效,则再次执行外层循环,再次寻找签名。
当使用CBR MP3 执行我的程序时,只找到了一些帧。应用程序报告许多无效帧。
我认为无效帧可能是由于位被跳过造成的。标头长 4 个字节。当标头被确定为无效时,我跳过所有 4 个字节并开始从接下来的四个字节中寻找签名。在以下情况下:11111111 11101101 11111111 11101001,在前两个字节中找到了标头签名,但是第三个字节包含使标头无效的错误。如果我因为确定以第一个字节开头的标头无效而跳过所有字节,我会错过以第三个字节开头的潜在标头(因为第三和第四个字节包含签名)。
我无法在InputStream 中向后搜索,所以我的问题如下:当我确定以字节 1 和 2 开头的标头无效时,如何运行以字节 2 开头的签名查找循环,而不是字节 5?
在下面的代码中,b 是考虑中的可能标头的第一个字节,b1 是第二个字节,b2 是第三个字节,b3 是第四个字节。
int bytesRead = 0;
//10 bytes of Tagv2
int j = 0;
byte[] tagv2h = new byte[10];
j = fis.read(tagv2h);
bytesRead += j;
ByteBuffer bb = ByteBuffer.wrap(new byte[]{tagv2h[6], tagv2h[7],tagv2h[8], tagv2h[9]});
bb.order(ByteOrder.BIG_ENDIAN);
int tagSize = bb.getInt();
byte[] tagv2 = new byte[tagSize];
j = fis.read(tagv2);
bytesRead += j;
while (bytesRead < MPEG_FILE.length()) {
boolean foundHeader = false;
// Seek frame
int b = 0;
int b1 = 0;
while ((b = fis.read()) > -1) {
bytesRead++;
if (b == 255) {
b1 = fis.read();
if (b1 > -1) {
bytesRead++;
if (((b1 >> 5) & 0x7) == 0x7) {
System.out.println("Found header.");
foundHeader = true;
break;
}
}
}
}
if (!foundHeader) {
continue;
}
int b2 = fis.read();
int b3 = fis.read();
MpegFrame frame = new MpegFrame(b1, b2, b3, false);
if (!frame.isValid()) {
System.out.println("Invalid header @ " + (bytesRead-4));
continue;
}
}
【问题讨论】:
标签: java loops mp3 inputstream seek