public static int XingHeaderOffset(MpegVersion version, MpegChannelMode channelMode) { if (version == MpegVersion.One) { if (channelMode == MpegChannelMode.SingleChannel) { return(0x15); } else { return(0x24); } } else { if (channelMode == MpegChannelMode.SingleChannel) { return(0x0D); } else { return(0x15); } } }
public Granule() { IsUsed = false; Version = 0; Uncompressed = new UncompressedSampleFrame(); ChannelInfo = new List <ChannelInfo>(); }
static int CalculateSideInfoLength(MpegVersion mpegVersion, int channels) { if (channels == 1) { return(mpegVersion == MpegVersion.One ? 17 : 9); } return(mpegVersion == MpegVersion.One ? 32 : 17); }
static int ParseSampleRate(ReadOnlySpan <byte> data, MpegVersion mpegVersion) { var column = (data[2] >> 2) & 0b00000011; if (column == 0b00000011) { throw new AudioInvalidException("Not a valid MPEG header."); } return(_sampleRateTable[
static int ParseBitRate(ReadOnlySpan <byte> data, MpegVersion mpegVersion) { var column = (data[2] >> 4) & 0b00001111; if (column == 0b00001111) { throw new AudioInvalidException("Not a valid MPEG header."); } return(_bitRateTable[mpegVersion == MpegVersion.One ? 0 : 1, column]); }
public void AddFrame( MpegVersion version, MpegLayer layer, bool hasCRC, int frameSizeOffset, int frameSize) { Add(new Mp3Frame(BuildFrame( version, layer, hasCRC, frameSizeOffset, frameSize))); }
////////////////////////////////////////////////////////////////////////// // public methods ////////////////////////////////////////////////////////////////////////// public MpegProperties (MpegFile file, ReadStyle style) : base (style) { this.file = file; duration = TimeSpan.Zero; //bitrate = 0; //sample_rate = 0; //channels = 0; version = MpegVersion.One; //layer = 0; channel_mode = MpegChannelMode.Stereo; //is_copyrighted = false; //is_original = false; Read(); }
////////////////////////////////////////////////////////////////////////// // public methods ////////////////////////////////////////////////////////////////////////// public MpegProperties(MpegFile file, ReadStyle style) : base(style) { this.file = file; duration = TimeSpan.Zero; //bitrate = 0; //sample_rate = 0; //channels = 0; version = MpegVersion.One; //layer = 0; channel_mode = MpegChannelMode.Stereo; //is_copyrighted = false; //is_original = false; Read(); }
public void AddFreeFrame( MpegVersion version, MpegLayer layer, bool hasCRC, int frameSizeOffset, int frameSize) { byte[] buf = BuildFrame( version, layer, hasCRC, frameSizeOffset, frameSize); buf[2] &= 0x0F; Add(new Mp3Frame(buf)); }
private void GetVersion(params bool[] twoBits) { if (twoBits[0] && twoBits[1]) { this.mpegVersion = MpegVersion.MpegVersion1; } else if (twoBits[0] && !twoBits[1]) { this.mpegVersion = MpegVersion.MpegVersion2; } else if (!twoBits[0] && twoBits[1]) { this.mpegVersion = MpegVersion.Reserved; } else if (!twoBits[0] && !twoBits[1]) { this.mpegVersion = MpegVersion.MpegVersion25; } }
private static int GetSamplesPerFrame(MpegVersion mpegVersion, MpegLayer mpegLayer) { int tmpSamplesPerFrame = 0; switch (mpegVersion) { // MPEG-1 case MpegVersion.Mpeg1: if (mpegLayer == MpegLayer.Layer1) { tmpSamplesPerFrame = 384; } else if (mpegLayer == MpegLayer.Layer2 || mpegLayer == MpegLayer.Layer3) { tmpSamplesPerFrame = 1152; } break; // MPEG-2/2.5 case MpegVersion.Mpeg2: case MpegVersion.Mpeg25: if (mpegLayer == MpegLayer.Layer1) { tmpSamplesPerFrame = 384; } else if (mpegLayer == MpegLayer.Layer2) { tmpSamplesPerFrame = 1152; } else if (mpegLayer == MpegLayer.Layer3) { tmpSamplesPerFrame = 576; } break; } // end switch (ID) return(tmpSamplesPerFrame); }
private static int?GetFreqency(byte three, MpegVersion version) { int basevalue = 0; if (CompBit(three, 5, 2, false, false)) { basevalue = 11025; } if (CompBit(three, 5, 2, false, true)) { basevalue = 12000; } if (CompBit(three, 5, 2, true, false)) { basevalue = 8000; } if (CompBit(three, 5, 2, true, true)) { basevalue = 0; } if (basevalue != 0) { if (version == MpegVersion.MPEG25) { return(basevalue); } if (version == MpegVersion.MPEG2) { return(basevalue * 2); } if (version == MpegVersion.MPEG1) { return(basevalue * 4); } } return(null); }
private void Parse(ByteVector data) { if (data.Count < 4 || data[0] != 0xff) { TagLibDebugger.Debug("Mpeg.Header.Parse() -- First byte did not match MPEG synch."); return; } uint flags = data.ToUInt(); // Check for the second byte'field part of the MPEG synch if ((flags & 0xFFE00000) != 0xFFE00000) { TagLibDebugger.Debug("Mpeg.Header.Parse() -- Second byte did not match MPEG synch."); return; } // Set the MPEG version switch ((flags >> 19) & 0x03) { case 0: version = MpegVersion.TwoPointFive; break; case 2: version = MpegVersion.Two; break; case 3: version = MpegVersion.One; break; } // Set the MPEG layer switch ((flags >> 17) & 0x03) { case 1: layer = 3; break; case 2: layer = 2; break; case 3: layer = 1; break; } protectionEnabled = ((flags >> 16) & 1) == 0; // Set the bitrate int[, ,] bitrates = new int[2, 3, 16] { { // Version 1 { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2 { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3 }, { // Version 2 or 2.5 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3 } }; int versionIndex = version == MpegVersion.One ? 0 : 1; int layerIndex = layer > 0 ? layer - 1 : 0; // The bitrate index is encoded as the first 4 bits of the 3rd byte, // index.e. 1111xxxx int i = (int)(flags >> 12) & 0x0F; bitrate = bitrates[versionIndex, layerIndex, i]; // Set the sample rate int[,] sampleRates = new int[3, 4] { { 44100, 48000, 32000, 0 }, // Version 1 { 22050, 24000, 16000, 0 }, // Version 2 { 11025, 12000, 8000, 0 } // Version 2.5 }; // The sample rate index is encoded as two bits in the 3nd byte, // index.e. xxxx11xx i = (int)(flags >> 10) & 0x03; sampleRate = sampleRates[(int)version, i]; if (sampleRate == 0) { TagLibDebugger.Debug("Mpeg.Header.Parse() -- Invalid sample rate."); return; } // The channel mode is encoded as a 2 bit value at the end of the 3nd // byte, index.e. xxxxxx11 channelMode = (MpegChannelMode)((flags >> 16) & 0x3); // TODO: Add mode extension for completeness isCopyrighted = (flags & 1) == 1; isOriginal = ((flags >> 1) & 1) == 1; // Calculate the frame length if (layer == 1) { frameLength = 24000 * 2 * bitrate / sampleRate + (IsPadded ? 1 : 0); } else { frameLength = 72000 * bitrate / sampleRate + (IsPadded ? 1 : 0); } // Now that we're done parsing, set this to be a valid frame. isValid = true; }
/// <summary>checks if the four bytes represent a valid header, /// if they are, will parse the values into local properties /// </summary> private bool IsValidHeader(byte[] headerBytes) { if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here mpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (mpegVersion == MpegVersion.Reserved) { //throw new FormatException("Unsupported MPEG Version"); return(false); } layer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (layer == MpegLayer.Reserved) { return(false); } int layerIndex = this.layer == MpegLayer.Layer1 ? 0 : this.layer == MpegLayer.Layer2 ? 1: 2; crcPresent = (headerBytes[1] & 0x01) == 0x00; int bitRateIndex = (headerBytes[2] & 0xF0) >> 4; if (bitRateIndex == 15) { // invalid index return(false); } int versionIndex = this.mpegVersion == Wave.MpegVersion.Version1 ? 0 : 1; this.bitRate = bitRates[versionIndex, layerIndex, bitRateIndex] * 1000; if (bitRate == 0) { return(false); } int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (sampleFrequencyIndex == 3) { return(false); } if (mpegVersion == MpegVersion.Version1) { sampleRate = sampleRatesVersion1[sampleFrequencyIndex]; } else if (mpegVersion == MpegVersion.Version2) { sampleRate = sampleRatesVersion2[sampleFrequencyIndex]; } else // mpegVersion == MpegVersion.Version25 { sampleRate = sampleRatesVersion25[sampleFrequencyIndex]; } bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; channelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); int channelExtension = (headerBytes[3] & 0x30) >> 4; bool copyright = (headerBytes[3] & 0x08) == 0x08; bool original = (headerBytes[3] & 0x04) == 0x04; int emphasis = (headerBytes[3] & 0x03); int nPadding = padding ? 1 : 0; this.samplesInFrame = samplesPerFrame[versionIndex, layerIndex]; int coefficient = this.samplesInFrame / 8; if (this.layer == MpegLayer.Layer1) { this.frameLengthInBytes = (coefficient * bitRate / sampleRate + nPadding) * 4; } else { frameLengthInBytes = (coefficient * bitRate) / sampleRate + nPadding; } if (this.frameLengthInBytes > MaxFrameLength) { return(false); } return(true); } return(false); }
////////////////////////////////////////////////////////////////////////// // private methods ////////////////////////////////////////////////////////////////////////// private void Read() { // Since we've likely just looked for the ID3v1 tag, start at the end of the // file where we're least likely to have to have to move the disk head. long last = file.LastFrameOffset; if (last < 0) { TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid last MPEG frame in the stream."); return; } file.Seek(last); MpegHeader last_header = new MpegHeader(file.ReadBlock(4)); long first = file.FirstFrameOffset; if (first < 0) { TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid first MPEG frame in the stream."); return; } if (!last_header.IsValid) { long pos = last; while (pos > first) { pos = file.PreviousFrameOffset(pos); if (pos < 0) { break; } file.Seek(pos); MpegHeader header = new MpegHeader(file.ReadBlock(4)); if (header.IsValid) { last_header = header; last = pos; break; } } } // Now jump back to the front of the file and read what we need from there. file.Seek(first); MpegHeader first_header = new MpegHeader(file.ReadBlock(4)); if (!first_header.IsValid || !last_header.IsValid) { TagLibDebugger.Debug("Mpeg.Properties.Read() -- Page headers were invalid."); return; } // Check for a Xing header that will help us in gathering information about a // VBR stream. int xing_header_offset = MpegXingHeader.XingHeaderOffset(first_header.Version, first_header.ChannelMode); file.Seek(first + xing_header_offset); MpegXingHeader xing_header = new MpegXingHeader(file.ReadBlock(16)); // Read the length and the bitrate from the Xing header. if (xing_header.IsValid && first_header.SampleRate > 0 && xing_header.TotalFrames > 0) { int [] block_size = { 0, 384, 1152, 1152 }; double time_per_frame = block_size [first_header.Layer]; time_per_frame = first_header.SampleRate > 0 ? time_per_frame / first_header.SampleRate : 0; duration = new TimeSpan((int)(time_per_frame * xing_header.TotalFrames) * TimeSpan.TicksPerSecond); bitrate = (int)(duration > TimeSpan.Zero ? ((xing_header.TotalSize * 8L) / duration.TotalSeconds) / 1000 : 0); } // Since there was no valid Xing header found, we hope that we're in a constant // bitrate file. // TODO: Make this more robust with audio property detection for VBR without a // Xing header. else if (first_header.FrameLength > 0 && first_header.Bitrate > 0) { int frames = (int)((last - first) / first_header.FrameLength + 1); duration = TimeSpan.FromSeconds((double)(first_header.FrameLength * frames) / (double)(first_header.Bitrate * 125) + 0.5); bitrate = first_header.Bitrate; } sample_rate = first_header.SampleRate; channels = first_header.ChannelMode == MpegChannelMode.SingleChannel ? 1 : 2; version = first_header.Version; layer = first_header.Layer; channel_mode = first_header.ChannelMode; is_copyrighted = first_header.IsCopyrighted; is_original = first_header.IsOriginal; }
/// <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); } } } }
private static int GetFrequency(MpegVersion mpegVersion, int frequencyID) { int tmpFrequency = 0; switch (mpegVersion) { // MPEG-1 case MpegVersion.Mpeg1: switch (frequencyID) { case 0: tmpFrequency = 44100; break; case 1: tmpFrequency = 48000; break; case 2: tmpFrequency = 32000; break; } // end switch (Frequency) break; // MPEG-2 case MpegVersion.Mpeg2: switch (frequencyID) { case 0: tmpFrequency = 22050; break; case 1: tmpFrequency = 24000; break; case 2: tmpFrequency = 16000; break; } // end switch (Frequency) break; // MPEG-2.5 case MpegVersion.Mpeg25: switch (frequencyID) { case 0: tmpFrequency = 11025; break; case 1: tmpFrequency = 12000; break; case 2: tmpFrequency = 8000; break; } // end switch (Frequency) break; } // end switch (ID) return tmpFrequency; }
public byte[] BuildFrame( MpegVersion version, MpegLayer layer, bool hasCRC, int frameSizeOffset, int frameSize) { byte[] buf = Slush.DomainObjects.Mp3.Test.Mp3FrameTest.BuildFrame( version, layer, hasCRC, frameSizeOffset, frameSize); if (UseRandom) { for (int i = 6; i < buf.Length; i++) { buf[i] = (byte)random.Next(); } } return buf; }
/// <summary>Reads an MP3Frame from a stream</summary> /// <remarks>http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm /// has some good info</remarks> public Mp3Frame(Stream input) { BinaryReader reader = new BinaryReader(input); // try for a header long headerStartPosition = input.Position; byte[] headerBytes = reader.ReadBytes(4); if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here mpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (mpegVersion == MpegVersion.Reserved) { throw new FormatException("Unsupported MPEG Version"); } layer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (layer != MpegLayer.Layer3) { throw new FormatException("Not an MP3"); } crcPresent = (headerBytes[1] & 0x01) == 0x00; int bitRateIndex = (headerBytes[2] & 0xF0) >> 4; bitRate = (mpegVersion == MpegVersion.Version1) ? bitRatesLayer3Version1[bitRateIndex] : bitRatesLayer3Version2[bitRateIndex]; int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (mpegVersion == MpegVersion.Version1) { sampleRate = sampleRatesVersion1[sampleFrequencyIndex]; } else if (mpegVersion == MpegVersion.Version2) { sampleRate = sampleRatesVersion2[sampleFrequencyIndex]; } else // mpegVersion == MpegVersion.Version25 { sampleRate = sampleRatesVersion25[sampleFrequencyIndex]; } bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; channelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); int channelExtension = (headerBytes[3] & 0x30) >> 4; bool copyright = (headerBytes[3] & 0x08) == 0x80; bool original = (headerBytes[3] & 0x04) == 0x80; int emphasis = (headerBytes[3] & 0x03); frameLengthInBytes = (144 * 1000 * bitRate) / sampleRate + ((padding) ? 1 : 0); } else { input.Position = headerStartPosition; throw new FormatException("Not a recognised MP3 block"); } if (crcPresent) { crc = reader.ReadInt16(); } long dataStartPosition = input.Position; input.Position = headerStartPosition; rawData = reader.ReadBytes(frameLengthInBytes); }
/// <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); } } } }
private static int GetFrequency(MpegVersion mpegVersion, int frequencyID) { int tmpFrequency = 0; switch (mpegVersion) { // MPEG-1 case MpegVersion.Mpeg1: switch (frequencyID) { case 0: tmpFrequency = 44100; break; case 1: tmpFrequency = 48000; break; case 2: tmpFrequency = 32000; break; } // end switch (Frequency) break; // MPEG-2 case MpegVersion.Mpeg2: switch (frequencyID) { case 0: tmpFrequency = 22050; break; case 1: tmpFrequency = 24000; break; case 2: tmpFrequency = 16000; break; } // end switch (Frequency) break; // MPEG-2.5 case MpegVersion.Mpeg25: switch (frequencyID) { case 0: tmpFrequency = 11025; break; case 1: tmpFrequency = 12000; break; case 2: tmpFrequency = 8000; break; } // end switch (Frequency) break; } // end switch (ID) return(tmpFrequency); }
private static int GetBitrate(MpegVersion mpegVersion, MpegLayer mpegLayer, int bitrateIndex) { return(BitrateTable[(int)mpegVersion][(int)mpegLayer - 1][bitrateIndex - 1]); }
static int GetBitRate( MpegVersion version, int layer, int index ) { if( version == MpegVersion.Version10 ) { return mpeg10bitrates[layer][index] * 1000; } else if( version == MpegVersion.Version20 || version == MpegVersion.Version25 ) { return mpeg2025bitrates[layer][index] * 1000; } throw new ArgumentException( "Unsupported version" + version ); }
static int CalculateSamplesPerFrame(MpegVersion mpegVersion) => mpegVersion == MpegVersion.One ? 1152 : 576;
static int CalculateSamplesPerFrame(MpegVersion mpegVersion) { return(mpegVersion == MpegVersion.One ? 1152 : 576); }
private static int GetBitrate(MpegVersion mpegVersion, MpegLayer mpegLayer, int bitrateIndex) { return BitrateTable[(int)mpegVersion][(int)mpegLayer - 1][bitrateIndex - 1]; }
private void GetVersion(params bool[] twoBits) { if (twoBits[0] && twoBits[1]) this.mpegVersion = MpegVersion.MpegVersion1; else if (twoBits[0] && !twoBits[1]) this.mpegVersion = MpegVersion.MpegVersion2; else if (!twoBits[0] && twoBits[1]) this.mpegVersion = MpegVersion.Reserved; else if (!twoBits[0] && !twoBits[1]) this.mpegVersion = MpegVersion.MpegVersion25; }
private static int GetSamplesPerFrame(MpegVersion mpegVersion, MpegLayer mpegLayer) { int tmpSamplesPerFrame = 0; switch (mpegVersion) { // MPEG-1 case MpegVersion.Mpeg1: if (mpegLayer == MpegLayer.Layer1) tmpSamplesPerFrame = 384; else if (mpegLayer == MpegLayer.Layer2 || mpegLayer == MpegLayer.Layer3) tmpSamplesPerFrame = 1152; break; // MPEG-2/2.5 case MpegVersion.Mpeg2: case MpegVersion.Mpeg25: if (mpegLayer == MpegLayer.Layer1) tmpSamplesPerFrame = 384; else if (mpegLayer == MpegLayer.Layer2) tmpSamplesPerFrame = 1152; else if (mpegLayer == MpegLayer.Layer3) tmpSamplesPerFrame = 576; break; } // end switch (ID) return tmpSamplesPerFrame; }
/// <summary>checks if the four bytes represent a valid header, /// if they are, will parse the values into local properties /// </summary> private bool IsValidHeader(byte[] headerBytes) { if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here mpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (mpegVersion == MpegVersion.Reserved) { //throw new FormatException("Unsupported MPEG Version"); return false; } layer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (layer == MpegLayer.Reserved) { return false; } int layerIndex = this.layer == MpegLayer.Layer1 ? 0 : this.layer == MpegLayer.Layer2 ? 1: 2; crcPresent = (headerBytes[1] & 0x01) == 0x00; int bitRateIndex = (headerBytes[2] & 0xF0) >> 4; if (bitRateIndex == 15) { // invalid index return false; } int versionIndex = this.mpegVersion == Wave.MpegVersion.Version1 ? 0 : 1; this.bitRate = bitRates[versionIndex, layerIndex, bitRateIndex] * 1000; if (bitRate == 0) { return false; } int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (sampleFrequencyIndex == 3) { return false; } if (mpegVersion == MpegVersion.Version1) sampleRate = sampleRatesVersion1[sampleFrequencyIndex]; else if (mpegVersion == MpegVersion.Version2) sampleRate = sampleRatesVersion2[sampleFrequencyIndex]; else // mpegVersion == MpegVersion.Version25 sampleRate = sampleRatesVersion25[sampleFrequencyIndex]; bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; channelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); int channelExtension = (headerBytes[3] & 0x30) >> 4; bool copyright = (headerBytes[3] & 0x08) == 0x08; bool original = (headerBytes[3] & 0x04) == 0x04; int emphasis = (headerBytes[3] & 0x03); int nPadding = padding ? 1 : 0; this.samplesInFrame = samplesPerFrame[versionIndex, layerIndex]; int coefficient = this.samplesInFrame / 8; if (this.layer == MpegLayer.Layer1) { this.frameLengthInBytes = (coefficient * bitRate / sampleRate + nPadding) * 4; } else { frameLengthInBytes = (coefficient * bitRate) / sampleRate + nPadding; } if (this.frameLengthInBytes > MaxFrameLength) { return false; } return true; } return false; }
/// <summary>Reads an MP3Frame from a stream</summary> /// <remarks>http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm /// has some good info</remarks> public Mp3Frame(Stream input) { BinaryReader reader = new BinaryReader(input); // try for a header long headerStartPosition = input.Position; byte[] headerBytes = reader.ReadBytes(4); // Added -jam to play wrapped mp3 files via RIFF headerBytes = CheckForRiff(input, reader, headerBytes); if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here mpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (mpegVersion == MpegVersion.Reserved) { throw new FormatException("Unsupported MPEG Version"); } layer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (layer != MpegLayer.Layer3) { throw new FormatException("Not an MP3"); } crcPresent = (headerBytes[1] & 0x01) == 0x00; int bitRateIndex = (headerBytes[2] & 0xF0) >> 4; bitRate = (mpegVersion == MpegVersion.Version1) ? bitRatesLayer3Version1[bitRateIndex] : bitRatesLayer3Version2[bitRateIndex]; int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (mpegVersion == MpegVersion.Version1) sampleRate = sampleRatesVersion1[sampleFrequencyIndex]; else if (mpegVersion == MpegVersion.Version2) sampleRate = sampleRatesVersion2[sampleFrequencyIndex]; else // mpegVersion == MpegVersion.Version25 sampleRate = sampleRatesVersion25[sampleFrequencyIndex]; bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; channelMode = (ChannelMode) ((headerBytes[3] & 0xC0) >> 6); int channelExtension = (headerBytes[3] & 0x30) >> 4; bool copyright = (headerBytes[3] & 0x08) == 0x80; bool original = (headerBytes[3] & 0x04) == 0x80; int emphasis = (headerBytes[3] & 0x03); frameLengthInBytes = (144 * 1000 * bitRate) / sampleRate + ((padding) ? 1 : 0); } else { input.Position = headerStartPosition; throw new FormatException("Not a recognised MP3 block"); } if (crcPresent) crc = reader.ReadInt16(); long dataStartPosition = input.Position; input.Position = headerStartPosition; rawData = reader.ReadBytes(frameLengthInBytes); }
private static int?GetBitrate(byte three, MpegVersion version, MpegLayer layer) { if (version == MpegVersion.MPEG1) { if (layer == MpegLayer.Layer1) { if (CompBit(three, 1, 4, false, false, false, false)) { return(null); } if (CompBit(three, 1, 4, false, false, false, true)) { return(32); } if (CompBit(three, 1, 4, false, false, true, false)) { return(64); } if (CompBit(three, 1, 4, false, false, true, true)) { return(96); } if (CompBit(three, 1, 4, false, true, false, false)) { return(128); } if (CompBit(three, 1, 4, false, true, false, true)) { return(160); } if (CompBit(three, 1, 4, false, true, true, false)) { return(192); } if (CompBit(three, 1, 4, false, true, true, true)) { return(224); } if (CompBit(three, 1, 4, true, false, false, false)) { return(256); } if (CompBit(three, 1, 4, true, false, false, true)) { return(288); } if (CompBit(three, 1, 4, true, false, true, false)) { return(320); } if (CompBit(three, 1, 4, true, false, true, true)) { return(352); } if (CompBit(three, 1, 4, true, true, false, false)) { return(384); } if (CompBit(three, 1, 4, true, true, false, true)) { return(416); } if (CompBit(three, 1, 4, true, true, true, false)) { return(448); } if (CompBit(three, 1, 4, true, true, true, true)) { return(null); } } else if (layer == MpegLayer.Layer2) { if (CompBit(three, 1, 4, false, false, false, false)) { return(null); } if (CompBit(three, 1, 4, false, false, false, true)) { return(32); } if (CompBit(three, 1, 4, false, false, true, false)) { return(45); } if (CompBit(three, 1, 4, false, false, true, true)) { return(56); } if (CompBit(three, 1, 4, false, true, false, false)) { return(64); } if (CompBit(three, 1, 4, false, true, false, true)) { return(80); } if (CompBit(three, 1, 4, false, true, true, false)) { return(96); } if (CompBit(three, 1, 4, false, true, true, true)) { return(112); } if (CompBit(three, 1, 4, true, false, false, false)) { return(128); } if (CompBit(three, 1, 4, true, false, false, true)) { return(160); } if (CompBit(three, 1, 4, true, false, true, false)) { return(192); } if (CompBit(three, 1, 4, true, false, true, true)) { return(224); } if (CompBit(three, 1, 4, true, true, false, false)) { return(256); } if (CompBit(three, 1, 4, true, true, false, true)) { return(320); } if (CompBit(three, 1, 4, true, true, true, false)) { return(384); } if (CompBit(three, 1, 4, true, true, true, true)) { return(null); } } else if (layer == MpegLayer.Layer3) { if (CompBit(three, 1, 4, false, false, false, false)) { return(null); } if (CompBit(three, 1, 4, false, false, false, true)) { return(32); } if (CompBit(three, 1, 4, false, false, true, false)) { return(40); } if (CompBit(three, 1, 4, false, false, true, true)) { return(45); } if (CompBit(three, 1, 4, false, true, false, false)) { return(56); } if (CompBit(three, 1, 4, false, true, false, true)) { return(64); } if (CompBit(three, 1, 4, false, true, true, false)) { return(80); } if (CompBit(three, 1, 4, false, true, true, true)) { return(96); } if (CompBit(three, 1, 4, true, false, false, false)) { return(112); } if (CompBit(three, 1, 4, true, false, false, true)) { return(128); } if (CompBit(three, 1, 4, true, false, true, false)) { return(160); } if (CompBit(three, 1, 4, true, false, true, true)) { return(192); } if (CompBit(three, 1, 4, true, true, false, false)) { return(224); } if (CompBit(three, 1, 4, true, true, false, true)) { return(256); } if (CompBit(three, 1, 4, true, true, true, false)) { return(320); } if (CompBit(three, 1, 4, true, true, true, true)) { return(null); } } } return(null); }
public static int XingHeaderOffset(MpegVersion version, MpegChannelMode channelMode) { if (version == MpegVersion.One) { if (channelMode == MpegChannelMode.SingleChannel) return 0x15; else return 0x24; } else { if (channelMode == MpegChannelMode.SingleChannel) return 0x0D; else return 0x15; } }
////////////////////////////////////////////////////////////////////////// // private methods ////////////////////////////////////////////////////////////////////////// private void Read () { // Since we've likely just looked for the ID3v1 tag, start at the end of the // file where we're least likely to have to have to move the disk head. long last = file.LastFrameOffset; if (last < 0) { TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Could not find a valid last MPEG frame in the stream."); return; } file.Seek (last); MpegHeader last_header = new MpegHeader (file.ReadBlock (4)); long first = file.FirstFrameOffset; if (first < 0) { TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Could not find a valid first MPEG frame in the stream."); return; } if(!last_header.IsValid) { long pos = last; while (pos > first) { pos = file.PreviousFrameOffset (pos); if(pos < 0) break; file.Seek (pos); MpegHeader header = new MpegHeader (file.ReadBlock (4)); if (header.IsValid) { last_header = header; last = pos; break; } } } // Now jump back to the front of the file and read what we need from there. file.Seek (first); MpegHeader first_header = new MpegHeader (file.ReadBlock (4)); if (!first_header.IsValid || !last_header.IsValid) { TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Page headers were invalid."); return; } // Check for a Xing header that will help us in gathering information about a // VBR stream. int xing_header_offset = MpegXingHeader.XingHeaderOffset (first_header.Version, first_header.ChannelMode); file.Seek (first + xing_header_offset); MpegXingHeader xing_header = new MpegXingHeader (file.ReadBlock (16)); // Read the length and the bitrate from the Xing header. if(xing_header.IsValid && first_header.SampleRate > 0 && xing_header.TotalFrames > 0) { int [] block_size = {0, 384, 1152, 1152}; double time_per_frame = block_size [first_header.Layer]; time_per_frame = first_header.SampleRate > 0 ? time_per_frame / first_header.SampleRate : 0; duration = new TimeSpan((int)(time_per_frame * xing_header.TotalFrames) * TimeSpan.TicksPerSecond); bitrate = (int) (duration > TimeSpan.Zero ? ((xing_header.TotalSize * 8L) / duration.TotalSeconds) / 1000 : 0); } // Since there was no valid Xing header found, we hope that we're in a constant // bitrate file. // TODO: Make this more robust with audio property detection for VBR without a // Xing header. else if (first_header.FrameLength > 0 && first_header.Bitrate > 0) { int frames = (int) ((last - first) / first_header.FrameLength + 1); duration = TimeSpan.FromSeconds ((double) (first_header.FrameLength * frames) / (double) (first_header.Bitrate * 125) + 0.5); bitrate = first_header.Bitrate; } sample_rate = first_header.SampleRate; channels = first_header.ChannelMode == MpegChannelMode.SingleChannel ? 1 : 2; version = first_header.Version; layer = first_header.Layer; channel_mode = first_header.ChannelMode; is_copyrighted = first_header.IsCopyrighted; is_original = first_header.IsOriginal; }