Example #1
0
        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);
        }