/// <summary> /// Opens MP3 from a stream rather than a file /// Will not dispose of this stream itself /// </summary> /// <param name="inputStream"></param> public Mp3FileReader(Stream inputStream) { int sampleRate; int bitRate; mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; Mp3Frame mp3Frame = new Mp3Frame(mp3Stream); sampleRate = mp3Frame.SampleRate; frameLengthInBytes = mp3Frame.FrameLength; bitRate = mp3Frame.BitRate; xingHeader = XingHeader.LoadXingHeader(mp3Frame); this.length = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; byte[] tag = new byte[128]; mp3Stream.Read(tag, 0, 3); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; this.length -= 128; } mp3Stream.Position = dataStartPosition; // TODO: choose more appropriately waveFormat = new Mp3WaveFormat(sampleRate, 2, frameLengthInBytes, bitRate); }
public Mp3FileReader(Stream inputStream, Mp3FileReader.FrameDecompressorBuilder frameDecompressorBuilder) { if (inputStream == null) { throw new ArgumentNullException("inputStream"); } try { this.mp3Stream = inputStream; this.id3v2Tag = Id3v2Tag.ReadTag(this.mp3Stream); this.dataStartPosition = this.mp3Stream.Position; Mp3Frame mp3Frame = Mp3Frame.LoadFromStream(this.mp3Stream); if (mp3Frame == null) { throw new InvalidDataException("Invalid MP3 file - no MP3 Frames Detected"); } double num = (double)mp3Frame.BitRate; this.xingHeader = XingHeader.LoadXingHeader(mp3Frame); if (this.xingHeader != null) { this.dataStartPosition = this.mp3Stream.Position; } Mp3Frame mp3Frame2 = Mp3Frame.LoadFromStream(this.mp3Stream); if (mp3Frame2 != null && (mp3Frame2.SampleRate != mp3Frame.SampleRate || mp3Frame2.ChannelMode != mp3Frame.ChannelMode)) { this.dataStartPosition = mp3Frame2.FileOffset; mp3Frame = mp3Frame2; } this.mp3DataLength = this.mp3Stream.Length - this.dataStartPosition; this.mp3Stream.Position = this.mp3Stream.Length - 128L; byte[] array = new byte[128]; this.mp3Stream.Read(array, 0, 128); if (array[0] == 84 && array[1] == 65 && array[2] == 71) { this.id3v1Tag = array; this.mp3DataLength -= 128L; } this.mp3Stream.Position = this.dataStartPosition; this.Mp3WaveFormat = new Mp3WaveFormat(mp3Frame.SampleRate, (mp3Frame.ChannelMode == ChannelMode.Mono) ? 1 : 2, mp3Frame.FrameLength, (int)num); this.CreateTableOfContents(); this.tocIndex = 0; num = (double)this.mp3DataLength * 8.0 / this.TotalSeconds(); this.mp3Stream.Position = this.dataStartPosition; this.Mp3WaveFormat = new Mp3WaveFormat(mp3Frame.SampleRate, (mp3Frame.ChannelMode == ChannelMode.Mono) ? 1 : 2, mp3Frame.FrameLength, (int)num); this.decompressor = frameDecompressorBuilder(this.Mp3WaveFormat); this.waveFormat = this.decompressor.OutputFormat; this.bytesPerSample = this.decompressor.OutputFormat.BitsPerSample / 8 * this.decompressor.OutputFormat.Channels; this.decompressBuffer = new byte[1152 * this.bytesPerSample * 2]; } catch (Exception) { if (this.ownInputStream) { inputStream.Dispose(); } throw; } }
/// <summary> /// Opens MP3 from a stream rather than a file /// Will not dispose of this stream itself /// </summary> /// <param name="inputStream">The incoming stream containing MP3 data</param> /// <param name="frameDecompressorBuilder">Factory method to build a frame decompressor</param> public Mp3FileReader(Stream inputStream, FrameDecompressorBuilder frameDecompressorBuilder) { // Calculated as a double to minimize rounding errors mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; var mp3Frame = Mp3Frame.LoadFromStream(mp3Stream); sampleRate = mp3Frame.SampleRate; frameLengthInBytes = mp3Frame.FrameLength; double bitRate = mp3Frame.BitRate; xingHeader = XingHeader.LoadXingHeader(mp3Frame); // If the header exists, we can skip over it when decoding the rest of the file if (xingHeader != null) { dataStartPosition = mp3Stream.Position; } this.mp3DataLength = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; byte[] tag = new byte[128]; mp3Stream.Read(tag, 0, 3); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; this.mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate this.Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); CreateTableOfContents(); this.tocIndex = 0; // [Bit rate in Kilobits/sec] = [Length in kbits] / [time in seconds] // = [Length in bits ] / [time in milliseconds] // Note: in audio, 1 kilobit = 1000 bits. bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate this.Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); decompressor = frameDecompressorBuilder(Mp3WaveFormat); this.waveFormat = decompressor.OutputFormat; this.bytesPerSample = (decompressor.OutputFormat.BitsPerSample) / 8 * decompressor.OutputFormat.Channels; // no MP3 frames have more than 1152 samples in them // some MP3s I seem to get double this.decompressBuffer = new byte[1152 * bytesPerSample * 2]; }
/// <summary> /// Opens MP3 from a stream rather than a file /// Will not dispose of this stream itself /// </summary> /// <param name="inputStream">The incoming stream containing MP3 data</param> /// <param name="frameDecompressorBuilder">Factory method to build a frame decompressor</param> public Mp3FileReader(Stream inputStream, FrameDecompressorBuilder frameDecompressorBuilder) { // Calculated as a double to minimize rounding errors mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; var mp3Frame = Mp3Frame.LoadFromStream(mp3Stream); sampleRate = mp3Frame.SampleRate; frameLengthInBytes = mp3Frame.FrameLength; double bitRate = mp3Frame.BitRate; xingHeader = XingHeader.LoadXingHeader(mp3Frame); // If the header exists, we can skip over it when decoding the rest of the file if (xingHeader != null) dataStartPosition = mp3Stream.Position; this.mp3DataLength = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; byte[] tag = new byte[128]; mp3Stream.Read(tag, 0, 3); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; this.mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate this.Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); CreateTableOfContents(); this.tocIndex = 0; // [Bit rate in Kilobits/sec] = [Length in kbits] / [time in seconds] // = [Length in bits ] / [time in milliseconds] // Note: in audio, 1 kilobit = 1000 bits. bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate this.Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); decompressor = frameDecompressorBuilder(Mp3WaveFormat); this.waveFormat = decompressor.OutputFormat; this.bytesPerSample = (decompressor.OutputFormat.BitsPerSample) / 8 * decompressor.OutputFormat.Channels; // no MP3 frames have more than 1152 samples in them // some MP3s I seem to get double this.decompressBuffer = new byte[1152 * bytesPerSample * 2]; }
/// <summary> /// Opens MP3 from a stream rather than a file /// Will not dispose of this stream itself /// </summary> /// <param name="inputStream">The incoming stream containing MP3 data</param> /// <param name="frameDecompressorBuilder">Factory method to build a frame decompressor</param> public Mp3FileReader(Stream inputStream, FrameDecompressorBuilder frameDecompressorBuilder) { // Calculated as a double to minimize rounding errors mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; var firstFrame = Mp3Frame.LoadFromStream(mp3Stream); double bitRate = firstFrame.BitRate; xingHeader = XingHeader.LoadXingHeader(firstFrame); // If the header exists, we can skip over it when decoding the rest of the file if (xingHeader != null) dataStartPosition = mp3Stream.Position; // workaround for a longstanding issue with some files failing to load // because they report a spurious sample rate change var secondFrame = Mp3Frame.LoadFromStream(mp3Stream); if (secondFrame != null && (secondFrame.SampleRate != firstFrame.SampleRate || secondFrame.ChannelMode != firstFrame.ChannelMode)) { // assume that the first frame was some kind of VBR/LAME header that we failed to recognise properly dataStartPosition = secondFrame.FileOffset; // forget about the first frame, the second one is the first one we really care about firstFrame = secondFrame; } this.mp3DataLength = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; byte[] tag = new byte[128]; mp3Stream.Read(tag, 0, 128); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; this.mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate this.Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); CreateTableOfContents(); this.tocIndex = 0; // [Bit rate in Kilobits/sec] = [Length in kbits] / [time in seconds] // = [Length in bits ] / [time in milliseconds] // Note: in audio, 1 kilobit = 1000 bits. bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate this.Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); decompressor = frameDecompressorBuilder(Mp3WaveFormat); this.waveFormat = decompressor.OutputFormat; this.bytesPerSample = (decompressor.OutputFormat.BitsPerSample) / 8 * decompressor.OutputFormat.Channels; // no MP3 frames have more than 1152 samples in them // some MP3s I seem to get double this.decompressBuffer = new byte[1152 * bytesPerSample * 2]; }
/// <summary> /// Opens MP3 from a stream rather than a file /// Will not dispose of this stream itself /// </summary> /// <param name="inputStream">The incoming stream containing MP3 data</param> /// <param name="frameDecompressorBuilder">Factory method to build a frame decompressor</param> public Mp3FileReader(Stream inputStream, FrameDecompressorBuilder frameDecompressorBuilder) { if (inputStream == null) { throw new ArgumentNullException("inputStream"); } try { mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; var firstFrame = Mp3Frame.LoadFromStream(mp3Stream); if (firstFrame == null) { throw new InvalidDataException("Invalid MP3 file - no MP3 Frames Detected"); } double bitRate = firstFrame.BitRate; xingHeader = XingHeader.LoadXingHeader(firstFrame); // If the header exists, we can skip over it when decoding the rest of the file if (xingHeader != null) { dataStartPosition = mp3Stream.Position; } // workaround for a longstanding issue with some files failing to load // because they report a spurious sample rate change var secondFrame = Mp3Frame.LoadFromStream(mp3Stream); if (secondFrame != null && (secondFrame.SampleRate != firstFrame.SampleRate || secondFrame.ChannelMode != firstFrame.ChannelMode)) { // assume that the first frame was some kind of VBR/LAME header that we failed to recognise properly dataStartPosition = secondFrame.FileOffset; // forget about the first frame, the second one is the first one we really care about firstFrame = secondFrame; } this.mp3DataLength = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; byte[] tag = new byte[128]; mp3Stream.Read(tag, 0, 128); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; this.mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate this.Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); CreateTableOfContents(); this.tocIndex = 0; // [Bit rate in Kilobits/sec] = [Length in kbits] / [time in seconds] // = [Length in bits ] / [time in milliseconds] // Note: in audio, 1 kilobit = 1000 bits. // Calculated as a double to minimize rounding errors bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate MP3 WaveFormat this.Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); decompressor = frameDecompressorBuilder(Mp3WaveFormat); this.waveFormat = decompressor.OutputFormat; this.bytesPerSample = (decompressor.OutputFormat.BitsPerSample) / 8 * decompressor.OutputFormat.Channels; // no MP3 frames have more than 1152 samples in them this.bytesPerDecodedFrame = 1152 * bytesPerSample; // some MP3s I seem to get double this.decompressBuffer = new byte[this.bytesPerDecodedFrame * 2]; } catch (Exception) { if (ownInputStream) { inputStream.Dispose(); } throw; } }
/// <summary> /// Load Xing Header /// </summary> /// <param name="frame">Frame</param> /// <returns>Xing Header</returns> public static XingHeader LoadXingHeader(Mp3Frame frame) { XingHeader xingHeader = new XingHeader(); xingHeader.frame = frame; int offset = 0; if (frame.MpegVersion == MpegVersion.Version1) { if (frame.ChannelMode != ChannelMode.Mono) { offset = 32 + 4; } else { offset = 17 + 4; } } else if (frame.MpegVersion == MpegVersion.Version2) { if (frame.ChannelMode != ChannelMode.Mono) { offset = 17 + 4; } else { offset = 9 + 4; } } else { return(null); // throw new FormatException("Unsupported MPEG Version"); } if ((frame.RawData[offset + 0] == 'X') && (frame.RawData[offset + 1] == 'i') && (frame.RawData[offset + 2] == 'n') && (frame.RawData[offset + 3] == 'g')) { xingHeader.startOffset = offset; offset += 4; } else { return(null); } XingHeaderOptions flags = (XingHeaderOptions)ReadBigEndian(frame.RawData, offset); offset += 4; if ((flags & XingHeaderOptions.Frames) != 0) { xingHeader.framesOffset = offset; offset += 4; } if ((flags & XingHeaderOptions.Bytes) != 0) { xingHeader.bytesOffset = offset; offset += 4; } if ((flags & XingHeaderOptions.Toc) != 0) { xingHeader.tocOffset = offset; offset += 100; } if ((flags & XingHeaderOptions.VbrScale) != 0) { xingHeader.vbrScale = ReadBigEndian(frame.RawData, offset); offset += 4; } xingHeader.endOffset = offset; return(xingHeader); }
/// <summary> /// Load Xing Header /// </summary> /// <param name="frame">Frame</param> /// <returns>Xing Header</returns> // Token: 0x060003C9 RID: 969 RVA: 0x0000D1D0 File Offset: 0x0000B3D0 public static XingHeader LoadXingHeader(Mp3Frame frame) { XingHeader xingHeader = new XingHeader(); xingHeader.frame = frame; int num; if (frame.MpegVersion == MpegVersion.Version1) { if (frame.ChannelMode != ChannelMode.Mono) { num = 36; } else { num = 21; } } else { if (frame.MpegVersion != MpegVersion.Version2) { return(null); } if (frame.ChannelMode != ChannelMode.Mono) { num = 21; } else { num = 13; } } if (frame.RawData[num] == 88 && frame.RawData[num + 1] == 105 && frame.RawData[num + 2] == 110 && frame.RawData[num + 3] == 103) { xingHeader.startOffset = num; num += 4; XingHeader.XingHeaderOptions xingHeaderOptions = (XingHeader.XingHeaderOptions)XingHeader.ReadBigEndian(frame.RawData, num); num += 4; if ((xingHeaderOptions & XingHeader.XingHeaderOptions.Frames) != (XingHeader.XingHeaderOptions) 0) { xingHeader.framesOffset = num; num += 4; } if ((xingHeaderOptions & XingHeader.XingHeaderOptions.Bytes) != (XingHeader.XingHeaderOptions) 0) { xingHeader.bytesOffset = num; num += 4; } if ((xingHeaderOptions & XingHeader.XingHeaderOptions.Toc) != (XingHeader.XingHeaderOptions) 0) { xingHeader.tocOffset = num; num += 100; } if ((xingHeaderOptions & XingHeader.XingHeaderOptions.VbrScale) != (XingHeader.XingHeaderOptions) 0) { xingHeader.vbrScale = XingHeader.ReadBigEndian(frame.RawData, num); num += 4; } xingHeader.endOffset = num; return(xingHeader); } return(null); }
/// <summary> /// Load Xing Header /// </summary> /// <param name="frame">Frame</param> /// <returns>Xing Header</returns> public static XingHeader LoadXingHeader(Mp3Frame frame) { XingHeader xingHeader = new XingHeader(); xingHeader.frame = frame; int offset = 0; if (frame.MpegVersion == MpegVersion.Version1) { if (frame.ChannelMode != ChannelMode.Mono) offset = 32 + 4; else offset = 17 + 4; } else if (frame.MpegVersion == MpegVersion.Version2) { if (frame.ChannelMode != ChannelMode.Mono) offset = 17 + 4; else offset = 9 + 4; } else { return null; // throw new FormatException("Unsupported MPEG Version"); } if ((frame.RawData[offset + 0] == 'X') && (frame.RawData[offset + 1] == 'i') && (frame.RawData[offset + 2] == 'n') && (frame.RawData[offset + 3] == 'g')) { xingHeader.startOffset = offset; offset += 4; } else { return null; } XingHeaderOptions flags = (XingHeaderOptions)ReadBigEndian(frame.RawData, offset); offset += 4; if ((flags & XingHeaderOptions.Frames) != 0) { xingHeader.framesOffset = offset; offset += 4; } if ((flags & XingHeaderOptions.Bytes) != 0) { xingHeader.bytesOffset = offset; offset += 4; } if ((flags & XingHeaderOptions.Toc) != 0) { xingHeader.tocOffset = offset; offset += 100; } if ((flags & XingHeaderOptions.VbrScale) != 0) { xingHeader.vbrScale = ReadBigEndian(frame.RawData, offset); offset += 4; } xingHeader.endOffset = offset; return xingHeader; }