Example #1
0
        private void ParseStsdAtom(byte[] atomdata)
        {
            byte[] data_format    = new byte[4];
            byte[] encoder_vendor = new byte[4];

            int num     = ReadInt32(atomdata, 4);
            int stsdOff = 8;

            for (int i = 0; i < num; i++)
            {
                int size = ReadInt32(atomdata, stsdOff);
                stsdOff += 4;
                Buffer.BlockCopy(atomdata, stsdOff, data_format, 0, 4);

                stsdOff += 12;
                byte[] data = new byte[size - 4 - 12];
                Buffer.BlockCopy(atomdata, stsdOff, data, 0, (size - 4 - 12));
                stsdOff += (size - 4 - 12);

                Buffer.BlockCopy(data, 4, encoder_vendor, 0, 4);
                if (encoder_vendor[0] == 0)
                {
                    Frequency = ((data[16] & 0xff) << 8) + (data[17] & 0xff);
                    Channels  = (data[8] << 8) + data[9];
                    if (ByteUtils.Compare(data_format, Encoding.ASCII.GetBytes("mp4a")))
                    {
                        Codec = "AAC";
                    }
                    else
                    {
                        Codec = Encoding.UTF8.GetString(data_format);
                    }
                }
            }
        }
Example #2
0
 internal static bool IsOggVorbis(Stream stream)
 {
     // Read Ogg marker
     byte[] oggMarker = new byte[4];
     stream.Read(oggMarker, 0, 4);
     stream.Seek(-4, SeekOrigin.Current);
     return(ByteUtils.Compare(oggMarker, OGG_MARKER));
 }
Example #3
0
 internal static bool IsFlac(Stream stream)
 {
     // Read flac marker
     byte[] flacMarker = new byte[4];
     stream.Read(flacMarker, 0, 4);
     stream.Seek(-4, SeekOrigin.Current);
     return(ByteUtils.Compare(flacMarker, FLAC_MARKER));
 }
Example #4
0
        /// <summary>
        /// Gets the APEv2 tag size from a specified stream.  Returns 0 if no tag exists.
        /// </summary>
        /// <param name="stream">The stream.</param>
        public static int GetTagSize(Stream stream)
        {
            Int64 currentPosition = stream.Position;

            try
            {
                byte[] buf = new byte[32];
                stream.Seek(-32, SeekOrigin.End);
                stream.Read(buf, 0, 32);

                if (ByteUtils.Compare(buf, APETAGEX, 8) == false)
                {
                    // Skip past possible ID3v1 tag
                    stream.Seek(-128 - 32, SeekOrigin.End);
                    stream.Read(buf, 0, 32);
                    if (ByteUtils.Compare(buf, APETAGEX, 8) == false)
                    {
                        // TODO: skip past possible Lyrics3 tag
                        return(0);
                    }
                }

                // Check version
                int version = 0;
                for (int i = 8; i < 12; i++)
                {
                    version += (buf[i] << ((i - 8) * 8));
                }

                // Must be APEv2 or APEv1
                if (version != 2000 && version != 1000)
                {
                    return(0);
                }

                // Size
                int tagSize = 0;
                for (int i = 12; i < 16; i++)
                {
                    tagSize += (buf[i] << ((i - 12) * 8));
                }

                bool containsHeader = ((buf[23] >> 7) == 1);

                tagSize += (containsHeader ? 32 : 0);
                return(tagSize);
            }
            finally
            {
                stream.Position = currentPosition;
            }
        }
Example #5
0
        public void Compare_TwoParameters_Nulls()
        {
            // first parameter null
            bool result = ByteUtils.Compare(null, new byte[0]);

            Assert.That(result, Is.False, "first parameter null (1)");
            result = ByteUtils.Compare(null, new byte[] { 0xFF });
            Assert.That(result, Is.False, "first parameter null (2)");

            // second parameter null
            result = ByteUtils.Compare(new byte[0], null);
            Assert.That(result, Is.False, "second parameter null (1)");
            result = ByteUtils.Compare(new byte[] { 0xFF }, null);
            Assert.That(result, Is.False, "second parameter null (2)");

            // both parameters null
            result = ByteUtils.Compare(null, null);
            Assert.That(result, Is.True, "both parameters null");
        }
Example #6
0
        public void Compare_ThreeParameters_Nulls()
        {
            // first parameter null
            bool result = ByteUtils.Compare(null, new byte[0], 0);

            Assert.That(result, Is.False, "first parameter null, second parameter byte[0]");
            result = ByteUtils.Compare(null, new byte[] { 0xFF }, 0);
            Assert.That(result, Is.False, "first parameter null, second paramter byte[1]");

            // second parameter null
            result = ByteUtils.Compare(new byte[0], null, 0);
            Assert.That(result, Is.False, "second parameter null, first parameter byte[0]");
            result = ByteUtils.Compare(new byte[] { 0xFF }, null, 0);
            Assert.That(result, Is.False, "second parameter null, first parameter byte[1]");

            // both parameters null
            result = ByteUtils.Compare(null, null, 10);
            Assert.That(result, Is.True, "both parameters null");
        }
Example #7
0
        public void Compare_ThreeParameters()
        {
            bool result;

            // extra value in x, maxLength = 4
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, 4);
            Assert.That(result, Is.True, "extra value in x, maxLength = 4");

            // extra value in y, maxLength = 4
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 }, 4);
            Assert.That(result, Is.True, "extra value in y, maxLength = 4");

            // same length, different values, maxLength = 2
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x02 }, 3);
            Assert.That(result, Is.True, "same length, different values, maxLength = 2");

            // same length, different values, maxLength = 2
            result = ByteUtils.Compare(new[] { (byte)0x02, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, 2);
            Assert.That(result, Is.False, "same length, different values, maxLength = 2");

            // same length, different values, maxLength = 0
            result = ByteUtils.Compare(new[] { (byte)0x02, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, 0);
            Assert.That(result, Is.True, "same length, different values, maxLength = 0");

            // extra value in x, maxLength = 10
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, 10);
            Assert.That(result, Is.True, "extra value in x, maxLength = 10");

            // extra value in y, maxLength = 10
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 }, 10);
            Assert.That(result, Is.True, "extra value in y, maxLength = 10");

            // same length, different values, maxLength = 10
            result = ByteUtils.Compare(new[] { (byte)0x02, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, 10);
            Assert.That(result, Is.False, "same length, different values, maxLength = 10");

            // same reference
            byte[] sameReference = new[] { (byte)0x00, (byte)0x01 };
            result = ByteUtils.Compare(sameReference, sameReference, 100);
            Assert.That(result, Is.True, "same reference");
        }
Example #8
0
        public void Compare_TwoParameters()
        {
            // equal
            bool result = ByteUtils.Compare(new byte[0], new byte[0]);

            Assert.That(result, Is.True);

            result = ByteUtils.Compare(new[] { (byte)0xFF }, new[] { (byte)0xFF });
            Assert.That(result, Is.True);

            result = ByteUtils.Compare(new[] { (byte)0xFF, (byte)0xFE }, new[] { (byte)0xFF, (byte)0xFE });
            Assert.That(result, Is.True);

            result = ByteUtils.Compare(new[] { (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0xFF, (byte)0xFE, (byte)0x00 });
            Assert.That(result, Is.True);

            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 });
            Assert.That(result, Is.True);

            byte[] sameReference = new[] { (byte)0x00, (byte)0x01 };
            result = ByteUtils.Compare(sameReference, sameReference);
            Assert.That(result, Is.True, "same reference");

            // extra value in x
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 });
            Assert.That(result, Is.False, "extra value in x");

            // extra value in y
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x01 });
            Assert.That(result, Is.False, "extra value in y");

            // same length, different values
            result = ByteUtils.Compare(new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x02 });
            Assert.That(result, Is.False, "same length, different values (1)");

            // same length, different values
            result = ByteUtils.Compare(new[] { (byte)0x02, (byte)0xFF, (byte)0xFE, (byte)0x00 }, new[] { (byte)0x00, (byte)0xFF, (byte)0xFE, (byte)0x00 });
            Assert.That(result, Is.False, "same length, different values (2)");
        }
Example #9
0
 public void Compare_ThreeParameters_MaxLengthArgumentExceptions()
 {
     Assert.Throws <ArgumentOutOfRangeException>(() => ByteUtils.Compare(null, null, -1));
 }
Example #10
0
        private void Read(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            _keyValues.Clear();
            TotalTagSize = 0;
            TagOffset    = null;

            stream.Seek(-128 - 9, SeekOrigin.End);

            byte[] endMarker = stream.Read(9);

            if (!ByteUtils.Compare(endMarker, _lyrics200))
            {
                return;
            }
            stream.Seek(-9 - 6, SeekOrigin.Current);
            byte[] lszBytes = stream.Read(6);
            int    lsz      = GetLengthFromByteArray(lszBytes);

            if (lsz <= 11 + 3 + 5 + 1)
            {
                // invalid, lsz is too small
                return;
            }

            stream.Seek(-6 - lsz, SeekOrigin.Current);
            byte[] beginMarker = stream.Read(11);
            if (!ByteUtils.Compare(beginMarker, _lyricsBegin))
            {
                // invalid, no begin marker found
                return;
            }

            int totalRead = 0;

            while (totalRead < lsz)
            {
                byte[] fieldIDBytes = stream.Read(3);
                string fieldID      = Encoding.ASCII.GetString(fieldIDBytes);
                byte[] fszBytes     = stream.Read(5);
                int    fsz          = GetLengthFromByteArray(fszBytes);
                totalRead += 3 + 5;

                // TODO: Indicate error reading Lyrics3 tag
                if (fsz <= 0)
                {
                    break;
                }
                if ((totalRead + fsz) > lsz)
                {
                    break;
                }

                byte[] valueBytes = stream.Read(fsz);
                string value      = Encoding.ASCII.GetString(valueBytes);
                totalRead += fsz;

                SetValue(fieldID, value);
            }

            TotalTagSize = lsz + 15; // lsz + 6 bytes size + 9 bytes end identifier
            TagOffset    = stream.Length - 128 - TotalTagSize;
        }
Example #11
0
        internal void Read(Stream stream, bool readElements)
        {
            _tagSize   = 0;
            _tagOffset = 0;

            if (readElements)
            {
                _items.Clear();
            }

            int footerOffset = 0;

            byte[] buf = new byte[32];
            stream.Seek(-32, SeekOrigin.End);
            stream.Read(buf, 0, 32);

            if (ByteUtils.Compare(buf, _APETAGEX, 8) == false)
            {
                // skip past possible ID3v1 tag
                footerOffset = 128;
                stream.Seek(-128 - 32, SeekOrigin.End);
                stream.Read(buf, 0, 32);
                if (ByteUtils.Compare(buf, _APETAGEX, 8) == false)
                {
                    return;
                    // skip past possible Lyrics3 tag
                    // TODO!

                    /*CLyrics3* Lyrics3 = new CLyrics3();
                     * Lyrics3->ReadTag(fp);
                     * if (Lyrics3->TagString() != "")
                     * {
                     *  fseek(fp, 0L - Lyrics3->ExistingOffset() - 32, SEEK_END);
                     *  fread(buf, 32, 1, fp);
                     *  strcpy(tmp, buf);
                     *  tmp[8] = 0;
                     *
                     *  if (strcmp(tmp, "APETAGEX"))
                     *  {
                     *      delete Lyrics3;
                     *      return;
                     *  }
                     *
                     *  footeroffset = Lyrics3->ExistingOffset();
                     * }
                     * else
                     * {
                     *  return;
                     * }*/
                }
            }

            // Check version
            _version = 0;
            for (int i = 8; i < 12; i++)
            {
                _version += (buf[i] << ((i - 8) * 8));
            }

            // Must be APEv2 or APEv1
            if (_version != 2000 && _version != 1000)
            {
                _version = 0;
                return;
            }

            // Size
            int tagSize = 0;

            for (int i = 12; i < 16; i++)
            {
                tagSize += (buf[i] << ((i - 12) * 8));
            }

            // Elements
            int elements = 0;

            for (int i = 16; i < 20; i++)
            {
                elements += (buf[i] << ((i - 16) * 8));
            }

            bool containsHeader = ((buf[23] >> 7) == 1);

            // The other item flags are uninteresting in the context of the header/footer
            // They include:
            // - Tag contains a footer
            // - Is Header/Is Footer
            // - Item Encoding
            // - Is Read Only

            _tagSize   = tagSize + (containsHeader ? 32 : 0);
            _tagOffset = stream.Length - (footerOffset + _tagSize);

            if (readElements)
            {
                stream.Seek(0 - (footerOffset + tagSize), SeekOrigin.End);

                for (int i = 0; i < elements; i++)
                {
                    ReadField(stream);
                }
            }
        }
Example #12
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OggVorbis"/> class.
        /// </summary>
        /// <param name="path">The path.</param>
        public OggVorbis(string path)
        {
            using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                try
                {
                    int tmpID3v2Size = ID3v2.GetTagSize(stream);
                    stream.Seek(tmpID3v2Size, SeekOrigin.Begin);

                    byte[] oggMarker = stream.Read(4);
                    if (ByteUtils.Compare(oggMarker, OGG_MARKER) == false)
                    {
                        throw new InvalidDataException("OggS marker not found");
                    }

                    // Skip through Ogg page header to page_segments position
                    stream.Seek(22, SeekOrigin.Current);

                    // Skip segment_table
                    int pageSegments = stream.Read1();
                    stream.Seek(pageSegments, SeekOrigin.Current);

                    // Read vorbis header
                    int packetType = stream.Read1();
                    if (packetType != 0x01)
                    {
                        throw new InvalidDataException("Vorbis identification header not found");
                    }

                    byte[] vorbisMarker = stream.Read(6);
                    if (ByteUtils.Compare(vorbisMarker, VORBIS_MARKER) == false)
                    {
                        throw new InvalidDataException("Vorbis marker not found");
                    }

                    // Skip vorbis_version
                    stream.Seek(4, SeekOrigin.Current);

                    _channels  = stream.Read1();
                    _frequency = stream.ReadInt32LittleEndian();

                    byte[] buf  = new byte[251];
                    long   size = stream.Length;

                    // Get total number of samples
                    _samples = 0;
                    for (int index = 1; index <= 50 && _samples == 0; index++)
                    {
                        long dataIndex = size - ((251 - 10) * index) - 10;
                        stream.Seek(dataIndex, SeekOrigin.Begin);
                        stream.Read(buf, 0, 251);

                        // Get number of PCM samples from last Ogg packet header
                        for (int i = 251 - 10; i >= 0; i--)
                        {
                            bool headerFound = true;
                            for (int j = 0; j < 4; j++)
                            {
                                if (buf[i + j] != OGG_MARKER[j])
                                {
                                    headerFound = false;
                                    break;
                                }
                            }

                            if (headerFound)
                            {
                                stream.Seek(dataIndex + i + 6, SeekOrigin.Begin);
                                stream.Read(buf, 0, 8);
                                for (i = 0; i < 8; i++)
                                {
                                    _samples += buf[i] << (8 * i);
                                }
                                break;
                            }
                        }
                    }

                    if (_samples == 0)
                    {
                        throw new InvalidDataException("Could not position to last frame");
                    }

                    _totalSeconds = _samples / (decimal)_frequency;
                    _bitrate      = (size - tmpID3v2Size) / _totalSeconds / 125.0m;
                }
                catch (Exception ex)
                {
                    throw new Exception("Invalid Ogg-Vorbis file; stream may be corrupt", ex);
                }
            }
        }
Example #13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MonkeysAudio"/> class.
        /// </summary>
        /// <param name="path">The path.</param>
        public MonkeysAudio(string path)
        {
            using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                // Skip ID3v2 tag
                int tmpID3v2TagSize = ID3v2.GetTagSize(stream);
                int tmpID3v1TagSize = ID3v1.GetTagSize(stream);
                int tmpAPEv2TagSize = APEv2.GetTagSize(stream);
                stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin);

                byte[] identifier = stream.Read(4);
                if (ByteUtils.Compare(identifier, MAC_IDENTIFIER, 4) == false)
                {
                    throw new InvalidDataException("Invalid Monkey's Audio file");
                }

                byte[] buf = stream.Read(4);

                _version = buf[0] + (buf[1] << 8);
                int blocksPerFrame;
                int finalBlocks;

                if (_version >= 3980 && _version <= 3990)
                {
                    buf = stream.Read(4);
                    int descriptorLength = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
                    stream.Seek(descriptorLength - 12, SeekOrigin.Current); // skip DESCRIPTOR

                    buf = stream.Read(4);
                    _compressionLevel = buf[0] + (buf[1] << 8);

                    blocksPerFrame = stream.ReadInt32LittleEndian();
                    finalBlocks    = stream.ReadInt32LittleEndian();
                    _frames        = stream.ReadInt32LittleEndian();

                    buf = stream.Read(4);
                    // skip bits per sample
                    _channels = buf[2] + (buf[3] << 8);

                    _frequency = stream.ReadInt32LittleEndian();
                }
                else if (_version <= 3970)
                {
                    // TODO: This section needs work

                    _compressionLevel = buf[2] + (buf[3] << 8);

                    buf = stream.Read(24);

                    // skip format flags
                    _channels = buf[2] + (buf[3] << 8);

                    _frequency = buf[4] + (buf[5] << 8) + (buf[6] << 16) + (buf[7] << 32);

                    if (_version >= 3950)
                    {
                        blocksPerFrame = 73728 * 4;
                    }
                    else if (_version >= 3900 || (_version >= 3800 && _compressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))
                    {
                        blocksPerFrame = 73728;
                    }
                    else
                    {
                        blocksPerFrame = 9216;
                    }

                    // TODO: This is definitely f****d up
                    finalBlocks = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
                    _frames     = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
                }
                else
                {
                    throw new NotImplementedException(string.Format("MAC {0:0.00} not supported", _version / 1000.0));
                }

                long totalBlocks = ((_frames - 1) * blocksPerFrame) + finalBlocks;

                long totalSize = stream.Length - stream.Position - tmpAPEv2TagSize - tmpID3v1TagSize;

                _totalSeconds = totalBlocks / (decimal)_frequency;
                _bitrate      = totalSize / (_totalSeconds * 125.0m);
            }
        }
Example #14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Mpeg"/> class.
        /// </summary>
        /// <param name="path">The full path of the file.</param>
        /// <param name="calculateBitrate">if set to <c>true</c> the bitrate will be calculated before the constructor returns.</param>
        public Mpeg(string path, bool calculateBitrate)
        {
            _fileName = path;

            using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                int tmpID3v2TagSize = ID3v2.GetTagSize(stream);
                stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin);

                byte[] tmpFrameHeader = new byte[4];

                bool acceptNullSamples = false;
                while (true)
                {
                    int tmpByte = stream.ReadByte(); // keep as ReadByte
                    while (tmpByte != 0xFF && tmpByte != -1)
                    {
                        tmpByte = stream.ReadByte(); // keep as ReadByte
                    }

                    if (tmpByte == -1)
                    {
                        if (acceptNullSamples)
                        {
                            throw new InvalidDataException(string.Format("'{0}': Can't find frame sync", path));
                        }
                        stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin);
                        acceptNullSamples = true;
                        continue;
                    }

                    tmpFrameHeader[0] = (byte)tmpByte;

                    // Get frame header
                    if (stream.Read(tmpFrameHeader, 1, 3) != 3)
                    {
                        throw new InvalidDataException(string.Format("'{0}': Invalid MPEG file; end of stream reached", path));
                    }

                    // No sync
                    if ((tmpFrameHeader[1] >> 5) != 0x07 ||
                        ((tmpFrameHeader[1] >> 1) & 0x03) == 0) // 2/18/05 - ignore reserved layer
                    {
                        stream.Seek(-3, SeekOrigin.Current);
                    }
                    else if (tmpFrameHeader[1] == 0xFF ||
                             ((tmpFrameHeader[1] >> 3) & 0x03) == 1) // 2/19/05 - more bad data
                    {
                        stream.Seek(-3, SeekOrigin.Current);
                    }
                    else
                    {
                        int tmpMpegID    = (tmpFrameHeader[1] >> 3) & 0x03;
                        int tmpLayerNum  = (tmpFrameHeader[1] >> 1) & 0x03;
                        int tmpFrequency = GetFrequency((MpegVersion)tmpMpegID, (tmpFrameHeader[2] >> 2) & 0x03);

                        // Check for invalid frequency
                        if (tmpFrequency == 0)
                        {
                            stream.Seek(-3, SeekOrigin.Current);
                            continue;
                        }

                        int tmpSamplesPerFrame = GetSamplesPerFrame((MpegVersion)tmpMpegID, (MpegLayer)tmpLayerNum);

                        int    tmpUsesPadding    = (tmpFrameHeader[2] >> 1) & 0x01;
                        double tmpFrameSizeConst = 125.0 * tmpSamplesPerFrame / tmpFrequency;
                        int    tmpPaddingSize    = (tmpLayerNum == 3 ? 4 : 1);
                        int    tmpBitrateIndex   = tmpFrameHeader[2] >> 4;

                        // Check for invalid values
                        if (tmpBitrateIndex < 1 || tmpBitrateIndex > 14 || tmpLayerNum == 0)
                        {
                            stream.Seek(-3, SeekOrigin.Current);
                            continue;
                        }

                        int tmpFrameBitrate = GetBitrate((MpegVersion)tmpMpegID, (MpegLayer)tmpLayerNum, tmpBitrateIndex);
                        int tmpFrameSize    = (int)(tmpFrameBitrate * tmpFrameSizeConst) + (tmpUsesPadding * tmpPaddingSize);
                        _headerOffset = stream.Position - 4;

                        if (tmpFrameSize < 8)
                        {
                            stream.Seek(-3, SeekOrigin.Current);
                            continue;
                        }

                        // 7/21/05 - Check for 0x00 or 0xFF at end of last frame
                        // this sucks for tracks that start with silence
                        if (_headerOffset >= 1 && !acceptNullSamples) // if (ftell(fp) >= 5)
                        {
                            stream.Seek(-5, SeekOrigin.Current);
                            byte tmpLastByte = stream.Read1();
                            stream.Seek(4, SeekOrigin.Current);

                            if (tmpFrameBitrate != 320 && (tmpLastByte == 0x00 || tmpLastByte == 0xFF))
                            {
                                // 7/31/05
                                // may be a valid frame - skip its contents to prevent false sync
                                long tmpNewPosition = _headerOffset + tmpFrameSize;
                                if (tmpFrameSize == 0)
                                {
                                    tmpNewPosition++;
                                }
                                stream.Seek(tmpNewPosition, SeekOrigin.Begin);
                                continue;
                            }
                        }

                        /*if (BR == 0 || FrameSizeConst == 0)
                         * {
                         *  startpos = HeaderOffset+1;
                         *  fseek(fp, startpos, SEEK_SET);
                         *  continue;
                         * }*/

                        stream.Seek(_headerOffset + tmpFrameSize, SeekOrigin.Begin);
                        if (stream.Read1() == 0xFF)
                        {
                            fh1 = stream.Read1();
                            fh2 = stream.Read1();

                            if (tmpFrameHeader[1] == fh1 &&
                                (tmpFrameHeader[2] & 0x0D) == (fh2 & 0x0D))
                            {
                                // header found
                                break;
                            }
                        }

                        stream.Seek(_headerOffset + 1, SeekOrigin.Begin);
                        continue;
                    }
                }

                _mpegVersion = (MpegVersion)((tmpFrameHeader[1] >> 3) & 0x03);
                _mpegLayer   = (MpegLayer)((tmpFrameHeader[1] >> 1) & 0x03);
                _frequency   = GetFrequency(_mpegVersion, (tmpFrameHeader[2] >> 2) & 0x03);
                if (_frequency == 0)
                {
                    throw new InvalidDataException(String.Format("'{0}'; cannot determine frequency", path));
                }

                _isPrivate        = ((tmpFrameHeader[2] & 0x01) == 0x01);
                _samplesPerFrame  = GetSamplesPerFrame(_mpegVersion, _mpegLayer);
                _frameSizeConst   = 125.0 * _samplesPerFrame / _frequency;
                _paddingSizeConst = (_mpegLayer == MpegLayer.Layer1 ? 4 : 1);
                _isCopyright      = (((tmpFrameHeader[3] >> 3) & 0x01) == 0x01);
                _isOriginal       = (((tmpFrameHeader[3] >> 2) & 0x01) == 0x01);
                //tmpModeExtension = (FH[3] >> 4) & 0x03; // not interested, only used in joint-stereo
                //_mpegEmphasis = (MpegEmphasis)(tmpFrameHeader[3] & 0x03);

                if ((tmpFrameHeader[3] >> 6) == 3)
                {
                    _channels = 1;                                // Single Channel
                }
                else
                {
                    _channels = 2;
                }

                // Read LAME Info Tag
                bool tmpHasLameInfoTag = false;

                stream.Seek(tmpID3v2TagSize + 36, SeekOrigin.Begin);
                Byte[] buf = stream.Read(4);

                if (ByteUtils.Compare(buf, INFO_MARKER)) // CBR
                {
                    tmpHasLameInfoTag = true;
                    _isVBR            = false;
                }
                else if (ByteUtils.Compare(buf, XING_MARKER)) // VBR
                {
                    tmpHasLameInfoTag = true;
                    _isVBR            = true;
                }

                if (tmpHasLameInfoTag)
                {
                    stream.Seek(4, SeekOrigin.Current);
                    int  tmpFrames = stream.ReadInt32();
                    uint tmpBytes  = (uint)stream.ReadInt32();

                    if (tmpFrames > 256 && tmpBytes > 50000)
                    {
                        decimal tmpBitrate = tmpBytes / 125.0m / (tmpFrames * _samplesPerFrame / (decimal)_frequency);
                        if (tmpBitrate <= 320 && tmpBitrate >= 32)
                        {
                            _frames       = tmpFrames;
                            _bitrate      = tmpBitrate;
                            _totalSeconds = (tmpBytes / 125.0m) / _bitrate;
                        }
                    }
                }

                // TODO: Take these 2 lines out

                /*fs.Position = 0;
                 * CalculateBitrate(fs, null);*/

                if (calculateBitrate)
                {
                    if (_bitrate == 0 || _isVBR == null || _frames == 0 || _totalSeconds == 0)
                    {
                        stream.Position = 0;
                        CalculateBitrate(stream, null);
                    }
                }
            }
        }
Example #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Flac"/> class.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        public Flac(string path)
        {
            try
            {
                using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // Skip ID3v2 tag
                    int tmpID3v2TagSize = ID3v2.GetTagSize(stream);
                    int tmpID3v1TagSize = ID3v1.GetTagSize(stream);
                    int tmpAPEv2TagSize = APEv2.GetTagSize(stream);
                    stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin);

                    // Read flac marker
                    byte[] flacMarker = new Byte[4];
                    stream.Read(flacMarker, 0, 4);
                    if (ByteUtils.Compare(flacMarker, FLAC_MARKER) == false)
                    {
                        throw new InvalidDataException("No header found");
                    }

                    // skip frame header and stuff we're not interested in
                    stream.Seek(14, SeekOrigin.Current);

                    byte[] buf = stream.Read(8);

                    _frequency = (buf[0] << 12) + (buf[1] << 4) + (buf[2] >> 4);
                    _channels  = ((buf[2] >> 1) & 0x03) + 1;
                    _samples   = ((buf[3] & 0x0F) << 32) + (buf[4] << 24) +
                                 (buf[5] << 16) + (buf[6] << 8) + buf[7];

                    _totalSeconds = _samples / (decimal)_frequency;

                    // Find first sync
                    // TODO: There's probably a better way to do this.. also an embedded PICTURE might
                    // cause a false sync. Not high priority since it will only cause a slight error
                    // in bitrate calculation if a false sync is found.
                    int c = stream.ReadByte(); // keep as ReadByte
                    while (c != -1)
                    {
                        if (c == 0xFF)
                        {
                            c = stream.ReadByte(); // keep as ReadByte
                            if (c >= 0xF8 && c <= 0xFB)
                            {
                                break;
                            }
                        }
                        else
                        {
                            c = stream.ReadByte(); // keep as ReadByte
                        }
                    }

                    if (c == -1)
                    {
                        throw new InvalidDataException("No sync found");
                    }

                    long startaudio = stream.Position;
                    long totalsize  = stream.Length - startaudio - tmpAPEv2TagSize - tmpID3v1TagSize;
                    _bitrate = totalsize / (_totalSeconds * 125);
                }
            }
            catch (InvalidDataException ex)
            {
                throw new InvalidDataException(String.Format("Cannot read FLAC file '{0}'", path), ex);
            }
        }