/// <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; Mp3Frame mp3Frame = Mp3Frame.LoadFromStream(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; 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; 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; this.Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); decompressor = new AcmMp3FrameDecompressor(this.Mp3WaveFormat); // new DmoMp3FrameDecompressor(this.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]; }
public Id3v2Tag Read(ByteBuffer data, bool[] ID3Flags, byte version) { int tagSize = data.Limit; byte[] b; Id3v2Tag tag = new Id3v2Tag(); //---------------------------------------------------------------------------- //Traitement en cas d'Header Etendu==true (A COMPLETER) if (version == Id3v2Tag.ID3V23 && ID3Flags[1]) ProcessExtendedHeader(data); //---------------------------------------------------------------------------- //Extraction des champs de texte int specSize = (version == Id3v2Tag.ID3V22) ? 3 : 4; for (int a = 0; a < tagSize; a++) { //Nom de la Frame b = new byte[specSize]; if(data.Remaining <= specSize) break; data.Get(b); string field = new string(System.Text.Encoding.ASCII.GetChars(b)); if (b[0] == 0) break; //La longueur du texte contenu dans la Frame int frameSize = ReadInteger(data, version); if ((frameSize > data.Remaining) || frameSize <= 0){ //ignore empty frames break; } b = new byte[ frameSize + ((version == Id3v2Tag.ID3V23) ? 2 : 0) ]; data.Get(b); if( "" != field) { Id3Frame f = CreateId3Frame(field, b, version); if(f != null) tag.Add(f); } } return tag; }
/// <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) { 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]; this.TableCreater = new Thread(this.CreateTableBackground); this.TableCreater.Priority = ThreadPriority.Highest; this.TableCreater.Start(); } catch (Exception) { if (ownInputStream) { inputStream.Dispose(); } throw; } }