示例#1
0
        // Returns 'true' if it still looks valid, 'false' if it doesn't
        public bool Process(byte b)
        {
            processedBytes++;
            if (skip > 0)
            {
                skip--;
                return(true);
            }
            if (state == MP3State.ID3v2)   // Check magic bytes and get ID3v2 length
            {
                if (progress < 3)
                {
                    if (b == MP3Detector.MagicStart[progress])
                    {
                        progress++;
                        return(true);
                    }
                    return(false);
                }
                else if (progress < 6)     // TODO We can perform extra verification on 'version' and 'flags' here
                {
                    progress++;
                    return(true);
                }
                else if (progress < 9)
                {
                    lengthBytes[progress - 6] = b;
                    progress++;
                    return(true);
                }
                else
                {
                    lengthBytes[progress - 6] = b;
                    progress++;

                    // Determine length
                    // This is given by the 4 length bytes, where the first bit in each of them is ignored (28 bits)
                    // Note that since ID3v2 is LE, the 'first' bit is bit 7

                    // Convert to integers in system-endian
                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(lengthBytes);
                    }
                    // Bit 0 is _never_ high in the ID3v2 size field
                    foreach (byte lb in lengthBytes)
                    {
                        if ((lb & 0b10000000) == 0b10000000)
                        {
                            return(false);
                        }
                    }

                    int[] lengthInts = new int[4];
                    lengthInts[0] = (int)lengthBytes[0];
                    lengthInts[1] = (int)lengthBytes[1];
                    lengthInts[2] = (int)lengthBytes[2];
                    lengthInts[3] = (int)lengthBytes[3];

                    // Consider the length ints to be A B C and D
                    // The length is then given by A*2^21 + B*2^14 + C^*2^7 + D
                    // We use << for powers, which gives us this expression
                    //
                    int len = lengthInts[0] * (2 << 20) + lengthInts[1] * (2 << 13) + lengthInts[2] * (2 << 6) + lengthInts[3];
                    //Console.WriteLine("ID3v2 Tag Length: {0}", len);
                    progress = 0;
                    state    = MP3State.Frame;
                    skip     = len; // -1 to account for the current byte

                    return(true);
                }
            }
            else if (state == MP3State.Frame)     // Keep parsing MP3 frame headers
            {
                if (progress < 3)
                {
                    frameBytes[progress] = b;
                    progress++;
                    return(true);
                }
                else
                {
                    frameBytes[progress] = b;
                    progress             = 0; // Reset

                    ////// Verify header

                    //string bits1 = Convert.ToString(frameBytes[0], 2);
                    //string bits2 = Convert.ToString(frameBytes[1], 2);
                    //string bits3 = Convert.ToString(frameBytes[2], 2);
                    //string bits4 = Convert.ToString(frameBytes[3], 2);
                    //Console.WriteLine("Global index: {0}", detectedStartIdx+processedBytes-1);
                    //Console.WriteLine("{0} {1} {2} {3}", bits1, bits2, bits3, bits4);
                    //Console.WriteLine("0x{0:X} 0x{1:X} 0x{2:X} 0x{3:X}", frameBytes[0], frameBytes[1], frameBytes[2], frameBytes[3]);

                    // Check frame sync
                    // First 11 bits are all 1
                    if (!(frameBytes[0] == 0xFF && (frameBytes[1] & 0b11100000) == 0b11100000))
                    {
                        if (potentiallyValid)
                        {
                            state = MP3State.ID3;
                            return(true);
                        }
                        else
                        {
                            //Console.WriteLine("Reject: sync");
                            return(false);
                        }
                    }
                    // Check version
                    // This is either 11 for v1 or 10 for v2
                    // 01 is reserved and 00 is unofficial
                    int version = (frameBytes[1] & 0b00011000) >> 3;
                    if (version != 0b11 && version != 0b10)
                    {
                        if (potentiallyValid)
                        {
                            state = MP3State.ID3;
                            return(true);
                        }
                        else
                        {
                            //Console.WriteLine("Reject: version");
                            return(false);
                        }
                    }
                    // Check layer
                    int layer = (frameBytes[1] & 0b00000110) >> 1;
                    if (layer == 0b00)   // 00 is reserved; 01, 10 and 11 are valid layers
                    {
                        if (potentiallyValid)
                        {
                            state = MP3State.ID3;
                            return(true);
                        }
                        else
                        {
                            //Console.WriteLine("Reject: layer");
                            return(false);
                        }
                    }

                    // Get bitrate index
                    byte bitrateIndex = (byte)((frameBytes[2] & 0b11110000) >> 4);
                    // Get sampling rate index
                    byte samplingIndex = (byte)((frameBytes[2] & 0b00001100) >> 2);

                    int bitrate      = MP3Detector.GetBitrate(version, layer, bitrateIndex) * 1000; // Multiply by 1000 (convert kbps -> bps)
                    int samplingRate = MP3Detector.GetSamplingRate(version, samplingIndex);
                    if (bitrate == -1)
                    {
                        if (potentiallyValid)
                        {
                            state = MP3State.ID3;
                            return(true);
                        }
                        else
                        {
                            //Console.WriteLine("Reject: bitrate");
                            return(false);
                        }
                    }
                    if (samplingRate == -1)
                    {
                        if (potentiallyValid)
                        {
                            state = MP3State.ID3;
                            return(true);
                        }
                        else
                        {
                            //Console.WriteLine("Reject: sampling");
                            //Console.WriteLine("{0} - {1}", samplingIndex, version);
                            return(false);
                        }
                    }
                    //Console.WriteLine("Got bitrate: {0}", bitrate);
                    //Console.WriteLine("Got sam: {0}", samplingRate);

                    // Get padding bit
                    // This is either 0 (not padded) or 1 (padded)
                    int paddingBit = (frameBytes[2] & 0b00000010) >> 1;
                    //Console.WriteLine("Padding: {0}", paddingBit);

                    // Compute length
                    int length;
                    if (layer == 0b11)
                    {
                        length = (12 * bitrate / samplingRate + paddingBit * 4) * 4; // 4 byte pad
                    }
                    else
                    {
                        length = 144 * bitrate / samplingRate + paddingBit; // 1 byte pad
                    }

                    //Console.WriteLine("Computed length: {0}", length);
                    skip             = length - 4;
                    potentiallyValid = true;
                    return(true);
                }
            }
            else     // MP3State.ID3;

            // NOTICE: BY THE TIME WE SWITCH HERE WE'VE ALREADY READ 4 BYTES!!!
            // Those 4 bytes were read in the 'Frame' state which was found invalid
            // Thus, we already have all the bytes needed to check for ID3v1 'TAG'

            {
                if (frameBytes[0] == 0x54 && frameBytes[1] == 0x41 && frameBytes[2] == 0x47)
                {
                    processedBytes += 123; // ID3v1 tag is always 128; -4 we already read; -1 the current byte we just read
                }
                else
                {
                    processedBytes--; // Substract 1 for the byte we just read, since it isn't used
                }

                done = true;
                return(true);
            }
        }
示例#2
0
 public PotentialMP3(int start_idx, MP3State startState)
 {
     detectedStartIdx = start_idx;
     state            = startState;
 }