I am writing an application to decode MP3
frames. I am having difficulty finding the headers.
An MP3
header is 32 bits and begins with the signature: 11111111 111
In the inner loop below, I look for this signature. When this signature is found, I retrieve the next two bytes and then pass the latter three bytes of the header into a custom MpegFrame()
class. The class verifies the integrity of the header and parses information from it. MpegFrame.isValid()
returns a boolean indicating the validity/integrity of the frame's header. If the header is invalid, the outer loop is executed again, and the signature is looked for again.
When executing my program with a CBR
MP3
, only some of the frames are found. The application reports many invalid frames.
I believe the invalid frames may be a result of bits being skipped. The header is 4 bytes long. When the header is determined to be invalid, I skip all 4 bytes and start seeking the signature from the next four bytes. In a case like the following: 11111111 11101101 11111111 11101001
, the header signature is found in the first two bytes, however the third byte contains an error which invalidates the header. If I skip all of the bytes because I've determined the header beginning with the first byte is invalid, I miss the pottential header starting with the third byte (as the third and fourth bytes contain a signature).
I cannot seek backwards in an InputStream
, so my question is the following: When I determine a header starting with bytes 1 and 2 to be invalid, how do I run my signature finding loop starting with byte 2, rather than byte 5?
In the below code, b
is the first byte of the possible header under consideration, b1
is the second byte, b2
is the third byte and b3
is the fourth byte.
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;
}
}