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); } } } }
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)); }
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)); }
/// <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; } }
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"); }
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"); }
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"); }
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)"); }
public void Compare_ThreeParameters_MaxLengthArgumentExceptions() { Assert.Throws <ArgumentOutOfRangeException>(() => ByteUtils.Compare(null, null, -1)); }
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; }
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); } } }
/// <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); } } }
/// <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); } }
/// <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); } } } }
/// <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); } }