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> /// Creates a new ID3v2 tag from a collection of key-value pairs. /// </summary> /// <param name="tags">A collection of key-value pairs containing the tags to include in the ID3v2 tag.</param> /// <returns>A new ID3v2 tag</returns> public static Id3v2Tag Create(IEnumerable <KeyValuePair <string, string> > tags) { return(Id3v2Tag.ReadTag(CreateId3v2TagStream(tags))); }