private static FrameHeader findFrame(BufferedBinaryReader source, ref VBRData oVBR, SizeInfo sizeInfo) { byte[] headerData = new byte[4]; FrameHeader result = new FrameHeader(); source.Read(headerData, 0, 4); result.Found = isValidFrameHeader(headerData); /* * Many things can actually be found before a proper MP3 header : * - Padding with 0x55, 0xAA and even 0xFF bytes * - RIFF header declaring either MP3 or WAVE data * - Xing encoder-specific frame * - One of the above with a few "parasite" bytes before their own header * * The most solid way to deal with all of them is to "scan" the file until proper MP3 header is found. * This method may not the be fastest, but ensures audio data is actually detected, whatever garbage lies before */ if (!result.Found) { // "Quick win" for files starting with padding bytes // 4 identical bytes => MP3 starts with padding bytes => Skip padding if ((headerData[0] == headerData[1]) && (headerData[1] == headerData[2]) && (headerData[2] == headerData[3])) { // Scan the whole padding until it stops while (headerData[0] == source.ReadByte()) { ; } source.Seek(-1, SeekOrigin.Current); // If padding uses 0xFF bytes, take one step back in case MP3 header lies there if (0xFF == headerData[0]) { source.Seek(-1, SeekOrigin.Current); } source.Read(headerData, 0, 4); result.Found = isValidFrameHeader(headerData); } // Blindly look for the MP3 header if (!result.Found) { source.Seek(-4, SeekOrigin.Current); long limit = sizeInfo.ID3v2Size + (long)Math.Round((source.Length - sizeInfo.ID3v2Size) * 0.3); // Look for the beginning of the MP3 header (2nd byte is variable, so it cannot be searched that way) while (!result.Found && source.Position < limit) { while (0xFF != source.ReadByte() && source.Position < limit) { ; } source.Seek(-1, SeekOrigin.Current); source.Read(headerData, 0, 4); result.Found = isValidFrameHeader(headerData); // Valid header candidate found // => let's see if it is a legit MP3 header by using its Size descriptor to find the next header if (result.Found) { result.LoadFromByteArray(headerData); result.Position = source.Position - 4; result.Size = getFrameSize(result); byte[] nextHeaderData = new byte[4]; source.Seek(result.Position + result.Size, SeekOrigin.Begin); source.Read(nextHeaderData, 0, 4); result.Found = isValidFrameHeader(nextHeaderData); if (result.Found) { source.Seek(result.Position + 4, SeekOrigin.Begin); // Go back to header candidate position break; } else { // Restart looking for a candidate source.Seek(result.Position + 1, SeekOrigin.Begin); } } else { source.Seek(-3, SeekOrigin.Current); } } } } if (result.Found) { result.LoadFromByteArray(headerData); result.Position = source.Position - 4; // result.Xing = isXing(i + 4, Data); // Will look into it when encoder ID is needed by upper interfaces // Look for VBR signature oVBR = findVBR(source, result.Position + getVBRDeviation(result)); } return(result); }