我正在编写一个解码MP3
帧的应用程序。我很难找到标题。
MP3
标头为32位,以签名开头:11111111 111
在下面的内部循环中,我寻找这个签名。找到此签名后,我将检索接下来的两个字节,然后将标头的后三个字节传递给自定义MpegFrame()
类。该类验证标头的完整性并从中解析信息。 MpegFrame.isValid()
返回一个布尔值,表示帧头的有效性/完整性。如果标头无效,则再次执行外循环,并再次查找签名。
使用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;
}
}
答案 0 :(得分:0)
您可以将输入流包装在PushbackInputStream
中,以便可以推回一些字节并重新解析它们。
答案 1 :(得分:0)
我最终编写了一个函数来移动无效头的字节,以便可以重新解析它。我在一个循环中调用该函数,其中我基本上Seek
表示有效帧。
Seek()
返回true(存储调用Seek()
找到的最后一帧的其他位置)。 CheckHeader()
验证标头的完整性。 SkipAudioData()
读取帧的所有音频数据,将流标记放在帧的末尾。
private boolean Seek() throws IOException {
while(!(CheckHeader() && SkipAudioData())){
if(!ShiftHeader()){
return false;
}
}
return true;
}
private boolean ShiftHeader() {
try {
if (bytesRead >= MPEG_FILE.length()) {
return false;
}
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
header[0] = header[1];
header[1] = header[2];
header[2] = header[3];
try {
int b = fis.read();
if (b > -1) {
header[3] = b;
return true;
}
} catch (IOException ex) {
return false;
} catch (Exception ex) {
return false;
}
return false;
}