/// <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; } 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; mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (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. bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (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 // some MP3s I seem to get double decompressBuffer = new byte[1152 * bytesPerSample * 2]; }
/// <summary> /// 通过Url下载音频数据到内存流 /// </summary> /// <param name="url"></param> public Mp3NetworkStream(string url) { //需要将网络流全部读入内存中,因为网络流是不能直接查找的 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); WebResponse response = request.GetResponse(); using (Stream stream = response.GetResponseStream()) { mp3Stream = new MemoryStream(); byte[] byteBuffer = new byte[1024]; if (stream != null) { int iReadSize = stream.Read(byteBuffer, 0, byteBuffer.Length); while (iReadSize > 0) { mp3Stream.Write(byteBuffer, 0, iReadSize); iReadSize = stream.Read(byteBuffer, 0, byteBuffer.Length); } stream.Close(); stream.Dispose(); } mp3Stream.Flush(); mp3Stream.Position = 0; 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; } 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; mp3DataLength -= 128; } mp3Stream.Position = dataStartPosition; // create a temporary MP3 format before we know the real bitrate Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (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. bitRate = (mp3DataLength * 8.0 / TotalSeconds()); mp3Stream.Position = dataStartPosition; // now we know the real bitrate we can create an accurate Mp3WaveFormat = new Mp3WaveFormat(sampleRate, mp3Frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frameLengthInBytes, (int)bitRate); decompressor = CreateAcmFrameDecompressor(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]; } response.Close(); }
/// <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; 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')) { 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) { offset += 100; } if ((flags & XingHeaderOptions.VbrScale) != 0) { xingHeader.vbrScale = ReadBigEndian(frame.RawData, offset); } return(xingHeader); }