/// <summary> Reads through all frames of the mp3 and populates the lowest, highest and average bitrate values. </summary> private void LoadBitrates() { long frameCount = 0; long totalBitrate = 0; using (FileStream fileStream = File.OpenRead(fileName)) { Mp3Frame frame = Mp3Frame.LoadFromStream(fileStream); // Skip over the Xing header if one exists (would otherwise cause 128 kbps first frame). XingHeader xingHeader = XingHeader.LoadXingHeader(frame); hasXingHeader = xingHeader != null; if (xingHeader != null) { for (int i = 0; i < xingHeader.Frames; ++i) { frame = Mp3Frame.LoadFromStream(fileStream); } } else { // Even if there isn't a xing header, there's still going to be a header so we'll skip it. frame = Mp3Frame.LoadFromStream(fileStream); } while (frame != null) { if (frame.SampleCount == 0) { continue; } sampleRate = (uint)frame.SampleRate; if (lowestBitrate == null || frame.BitRate < lowestBitrate) { lowestBitrate = frame.BitRate; } if (highestBitrate == null || frame.BitRate > highestBitrate) { highestBitrate = frame.BitRate; } totalBitrate += frame.BitRate; ++frameCount; try { frame = Mp3Frame.LoadFromStream(fileStream); } catch (EndOfStreamException) { break; } } } averageBitrate = totalBitrate / frameCount; }
/// <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) { // Calculated as a double to minimize rounding errors double bitRate; mp3Stream = inputStream; id3v2Tag = Id3v2Tag.ReadTag(mp3Stream); dataStartPosition = mp3Stream.Position; var mp3Frame = new Mp3Frame(mp3Stream); sampleRate = mp3Frame.SampleRate; frameLengthInBytes = mp3Frame.FrameLength; 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; } mp3DataLength = mp3Stream.Length - dataStartPosition; // try for an ID3v1 tag as well mp3Stream.Position = mp3Stream.Length - 128; var tag = new byte[128]; mp3Stream.Read(tag, 0, 3); if (tag[0] == 'T' && tag[1] == 'A' && tag[2] == 'G') { id3v1Tag = tag; mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; CreateTableOfContents(); 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; Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); decompressor = new AcmMp3FrameDecompressor(Mp3WaveFormat); // new DmoMp3FrameDecompressor(this.Mp3WaveFormat); waveFormat = decompressor.OutputFormat; 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 decompressBuffer = new byte[1152 * bytesPerSample * 2]; }
private IMp3FrameDecompressor CreateFrameDeCompressor() { if (_reader == null) { throw new ArgumentNullException(nameof(_reader)); } Id3v2Tag.ReadTag(_reader); // read tag data in from begin of stream _dataStartPosition = _reader.Position; var firstFrame = Mp3Frame.LoadFromStream(_reader); if (firstFrame == null) { throw new InvalidDataException("Invalid MP3 file - no MP3 Frames Detected"); } double bitRate = firstFrame.BitRate; var xingHeader = XingHeader.LoadXingHeader(firstFrame); // If the header exists, we can skip over it when decoding the rest of the file if (xingHeader != null) { _dataStartPosition = _reader.Position; } // workaround for a longstanding issue with some files failing to load // because they report a spurious sample rate change var secondFrame = Mp3Frame.LoadFromStream(_reader); 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; } // create a temporary MP3 format before we know the real bitrate Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); var decompressor = new AcmMp3FrameDecompressor(Mp3WaveFormat); _decompressBuffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame MaxPosition = _reader.Length - _dataStartPosition; Duration = TimeSpan.FromSeconds((double)MaxPosition / Mp3WaveFormat.AverageBytesPerSecond); return(decompressor); }
protected Mp3FileReaderBase(Stream inputStream, FrameDecompressorBuilder frameDecompressorBuilder, bool ownInputStream) { if (inputStream == null) { throw new ArgumentNullException(nameof(inputStream)); } if (frameDecompressorBuilder == null) { throw new ArgumentNullException(nameof(frameDecompressorBuilder)); } this._ownInputStream = ownInputStream; 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; } _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; _mp3DataLength -= 128; } _mp3Stream.Position = _dataStartPosition; // create a temporary MP3 format before we know the real bitrate Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); CreateTableOfContents(); _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 Mp3WaveFormat = new Mp3WaveFormat(firstFrame.SampleRate, firstFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, firstFrame.FrameLength, (int)bitRate); _decompressor = frameDecompressorBuilder(Mp3WaveFormat); WaveFormat = _decompressor.OutputFormat; _bytesPerSample = (_decompressor.OutputFormat.BitsPerSample) / 8 * _decompressor.OutputFormat.Channels; // no MP3 frames have more than 1152 samples in them _bytesPerDecodedFrame = 1152 * _bytesPerSample; // some MP3s I seem to get double _decompressBuffer = new byte[_bytesPerDecodedFrame * 2]; } catch (Exception) { if (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 Mp3Reader(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]; }