/// <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 bool IsWaveformatEqual(Mp3Frame frame) { //TODO : fix function. somehow it doesn't work 100% ... //hence return false so it always re-inits backend return false; Mp3WaveFormat new_mp3Format = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate); if (waveFormat.GetType() != new_mp3Format.GetType()) return false; Mp3WaveFormat CurrentFormat = (Mp3WaveFormat)waveFormat; if( CurrentFormat.SampleRate == new_mp3Format.SampleRate && CurrentFormat.Channels == new_mp3Format.Channels && CurrentFormat.BitsPerSample == new_mp3Format.BitsPerSample && CurrentFormat.AverageBytesPerSecond == new_mp3Format.AverageBytesPerSecond && CurrentFormat.blockSize == new_mp3Format.blockSize && CurrentFormat.ExtraSize == new_mp3Format.ExtraSize) { return true; } else { return false; } }
public void CanParseMp3FrameOffsetByN(int offset) { byte[] validMp3Frame = constructValidMp3Frame(); byte[] offsetBuffer = new byte[offset + validMp3Frame.Length]; Array.Copy(validMp3Frame, 0, offsetBuffer, offset, validMp3Frame.Length); MemoryStream ms = new MemoryStream(validMp3Frame); Mp3Frame frame = new Mp3Frame(ms); }
public static IMp3FrameDecompressor CreateFrameDecompressor(Mp3Frame frame) { WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate ); return new AcmMp3FrameDecompressor(waveFormat); }
public int DecompressFrame(Mp3Frame frame, byte[] dest, int destOffset) { Array.Copy(frame.RawData, conversionStream.SourceBuffer, frame.FrameLength); int sourceBytesConverted = 0; int converted = conversionStream.Convert(frame.FrameLength, out sourceBytesConverted); if (sourceBytesConverted != frame.FrameLength) { throw new InvalidOperationException("Couldn't convert the whole MP3 frame"); } Array.Copy(conversionStream.DestBuffer, 0, dest, destOffset, converted); return converted; }
IEnumerable<float[]> DecompressMp3(Mp3Frame aFrame) { /* WaveFormat waveFormat = new Mp3WaveFormat(aFrame.SampleRate, aFrame.ChannelMode == ChannelMode.Mono ? 1 : 2, aFrame.FrameLength, aFrame.BitRate); var decompressor = new AcmMp3FrameDecompressor(waveFormat); var bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat); int decompressed = decompressor..DecompressFrame(aFrame,, buffer, 0); */ yield return new float[] { 0, 0 }; }
/// <summary>Reads an MP3Frame from a stream</summary> /// <remarks>http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has some good info /// also see http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx /// </remarks> /// <returns>A valid MP3 frame, or null if none found</returns> public static Mp3Frame LoadFromStream(Stream input, bool readData) { var frame = new Mp3Frame(); frame.FileOffset = input.Position; byte[] headerBytes = new byte[4]; int bytesRead = input.Read(headerBytes, 0, headerBytes.Length); if (bytesRead < headerBytes.Length) { // reached end of stream, no more MP3 frames return null; } while (!IsValidHeader(headerBytes, frame)) { // shift down by one and try again headerBytes[0] = headerBytes[1]; headerBytes[1] = headerBytes[2]; headerBytes[2] = headerBytes[3]; bytesRead = input.Read(headerBytes, 3, 1); if (bytesRead < 1) { return null; } frame.FileOffset++; } /* no longer read the CRC since we include this in framelengthbytes if (this.crcPresent) this.crc = reader.ReadInt16();*/ int bytesRequired = frame.FrameLength - 4; if (readData) { frame.RawData = new byte[frame.FrameLength]; Array.Copy(headerBytes, frame.RawData, 4); bytesRead = input.Read(frame.RawData, 4, bytesRequired); if (bytesRead < bytesRequired) { // TODO: could have an option to suppress this, although it does indicate a corrupt file // for now, caller should handle this exception throw new EndOfStreamException("Unexpected end of stream before frame complete"); } } else { // n.b. readData should not be false if input stream does not support seeking input.Position += bytesRequired; } return frame; }
/// <summary> /// Decompresses a frame /// </summary> /// <param name="frame">The MP3 frame</param> /// <param name="dest">destination buffer</param> /// <param name="destOffset">Offset within destination buffer</param> /// <returns>Bytes written into destination buffer</returns> public int DecompressFrame(Mp3Frame frame, byte[] dest, int destOffset) { if (frame == null) { throw new ArgumentNullException("frame", "You must provide a non-null Mp3Frame to decompress"); } Array.Copy(frame.RawData, conversionStream.SourceBuffer, frame.FrameLength); int sourceBytesConverted = 0; int converted = conversionStream.Convert(frame.FrameLength, out sourceBytesConverted); if (sourceBytesConverted != frame.FrameLength) { throw new InvalidOperationException(String.Format("Couldn't convert the whole MP3 frame (converted {0}/{1})", sourceBytesConverted, frame.FrameLength)); } Array.Copy(conversionStream.DestBuffer, 0, dest, destOffset, converted); return converted; }
private Mp3FileReader(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> /// checks if the four bytes represent a valid header, /// if they are, will parse the values into Mp3Frame /// </summary> private static bool IsValidHeader(byte[] headerBytes, Mp3Frame frame) { if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here frame.MpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (frame.MpegVersion == MpegVersion.Reserved) { //throw new FormatException("Unsupported MPEG Version"); return(false); } frame.MpegLayer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (frame.MpegLayer == MpegLayer.Reserved) { return(false); } int layerIndex = frame.MpegLayer == MpegLayer.Layer1 ? 0 : frame.MpegLayer == MpegLayer.Layer2 ? 1 : 2; frame.CrcPresent = (headerBytes[1] & 0x01) == 0x00; frame.BitRateIndex = (headerBytes[2] & 0xF0) >> 4; if (frame.BitRateIndex == 15) { // invalid index return(false); } int versionIndex = frame.MpegVersion == Wave.MpegVersion.Version1 ? 0 : 1; frame.BitRate = bitRates[versionIndex, layerIndex, frame.BitRateIndex] * 1000; if (frame.BitRate == 0) { return(false); } int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (sampleFrequencyIndex == 3) { return(false); } if (frame.MpegVersion == MpegVersion.Version1) { frame.SampleRate = sampleRatesVersion1[sampleFrequencyIndex]; } else if (frame.MpegVersion == MpegVersion.Version2) { frame.SampleRate = sampleRatesVersion2[sampleFrequencyIndex]; } else { // mpegVersion == MpegVersion.Version25 frame.SampleRate = sampleRatesVersion25[sampleFrequencyIndex]; } bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; frame.ChannelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); frame.ChannelExtension = (headerBytes[3] & 0x30) >> 4; if (frame.ChannelExtension != 0 && frame.ChannelMode != ChannelMode.JointStereo) { return(false); } frame.Copyright = (headerBytes[3] & 0x08) == 0x08; bool original = (headerBytes[3] & 0x04) == 0x04; int emphasis = (headerBytes[3] & 0x03); int nPadding = padding ? 1 : 0; frame.SampleCount = samplesPerFrame[versionIndex, layerIndex]; int coefficient = frame.SampleCount / 8; if (frame.MpegLayer == MpegLayer.Layer1) { frame.FrameLength = (coefficient * frame.BitRate / frame.SampleRate + nPadding) * 4; } else { frame.FrameLength = (coefficient * frame.BitRate) / frame.SampleRate + nPadding; } if (frame.FrameLength > MaxFrameLength) { return(false); } return(true); } return(false); }
/// <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> /// Reads decompressed PCM data from our MP3 file. /// </summary> public override int Read(byte[] sampleBuffer, int offset, int numBytes) { int bytesRead = 0; lock (repositionLock) { if (decompressLeftovers != 0) { int toCopy = Math.Min(decompressLeftovers, numBytes); Array.Copy(decompressBuffer, decompressBufferOffset, sampleBuffer, offset, toCopy); decompressLeftovers -= toCopy; if (decompressLeftovers == 0) { decompressBufferOffset = 0; } else { decompressBufferOffset += toCopy; } bytesRead += toCopy; offset += toCopy; } int targetTocIndex = tocIndex; // the frame index that contains the requested data if (repositionedFlag) { decompressor.Reset(); // Seek back a few frames of the stream to get the reset decoder decode a few // warm-up frames before reading the requested data. Without the warm-up phase, // the first half of the frame after the reset is attenuated and does not resemble // the data as it would be when reading sequentially from the beginning, because // the decoder is missing the required overlap from the previous frame. tocIndex = Math.Max(0, tocIndex - 3); // no warm-up at the beginning of the stream mp3Stream.Position = tableOfContents[tocIndex].FilePosition; repositionedFlag = false; } while (bytesRead < numBytes) { Mp3Frame frame = ReadNextFrame(); if (frame != null) { int decompressed = decompressor.DecompressFrame(frame, decompressBuffer, 0); if (tocIndex <= targetTocIndex || decompressed == 0) { // The first frame after a reset usually does not immediately yield decoded samples. // Because the next instructions will fail if a buffer offset is set and the frame // decoding didn't return data, we skip the part. // We skip the following instructions also after decoding a warm-up frame. continue; } // Two special cases can happen here: // 1. We are interested in the first frame of the stream, but need to read the second frame too // for the decoder to return decoded data // 2. We are interested in the second frame of the stream, but because reading the first frame // as warm-up didn't yield any data (because the decoder needs two frames to return data), we // get data from the first and second frame. // This case needs special handling, and we have to purge the data of the first frame. else if (tocIndex == targetTocIndex + 1 && decompressed == bytesPerDecodedFrame * 2) { // Purge the first frame's data Array.Copy(decompressBuffer, bytesPerDecodedFrame, decompressBuffer, 0, bytesPerDecodedFrame); decompressed = bytesPerDecodedFrame; } int toCopy = Math.Min(decompressed - decompressBufferOffset, numBytes - bytesRead); Array.Copy(decompressBuffer, decompressBufferOffset, sampleBuffer, offset, toCopy); if ((toCopy + decompressBufferOffset) < decompressed) { decompressBufferOffset = toCopy + decompressBufferOffset; decompressLeftovers = decompressed - decompressBufferOffset; } else { // no lefovers decompressBufferOffset = 0; decompressLeftovers = 0; } offset += toCopy; bytesRead += toCopy; } else { break; } } } Debug.Assert(bytesRead <= numBytes, "MP3 File Reader read too much"); position += bytesRead; return(bytesRead); }
/// <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); }
public void SetupBackend(Mp3Frame frame) { //first cleanup the the backend. the old MP3 info could be different StopPlayer(); bFileEnding = false; //setup the output stream, using the provider & mp3Frame waveOut = new NAudio.Wave.DirectSoundOut(); SetWaveFormat(frame); decompressor = new AcmMp3FrameDecompressor(waveFormat); out_buffer = new BufferedWaveProvider(decompressor.OutputFormat); volumeHandler = new VolumeWaveProvider16(out_buffer); //1.0 = full volume, 0.0 = silence volumeHandler.Volume = volume; waveOut.Init(volumeHandler); //signal event we are set up if (backendHandler != null) backendHandler(this, true); waveOut.Play(); }
public int AddNextFrame(Mp3Frame frame) { if (frame == null) throw new ArgumentNullException("given frame = null"); //when receiving data... if (out_buffer == null) { SetupBackend(frame); } byte[] buffer = new byte[16384 * 50]; int decompressed = 0; if (frame != null) { decompressed = decompressor.DecompressFrame(frame, buffer, 0); if (out_buffer.BufferedBytes + decompressed < out_buffer.BufferLength) { out_buffer.AddSamples(buffer, 0, decompressed);//AddSamples(buffer,decompressed);//out_buffer.AddSamples(buffer, 0, decompressed); } } return decompressed; }
/// <summary> /// checks if the four bytes represent a valid header, /// if they are, will parse the values into Mp3Frame /// </summary> private static bool IsValidHeader(byte[] headerBytes, Mp3Frame frame) { if ((headerBytes[0] == 0xFF) && ((headerBytes[1] & 0xE0) == 0xE0)) { // TODO: could do with a bitstream class here frame.MpegVersion = (MpegVersion)((headerBytes[1] & 0x18) >> 3); if (frame.MpegVersion == MpegVersion.Reserved) { //throw new FormatException("Unsupported MPEG Version"); return false; } frame.MpegLayer = (MpegLayer)((headerBytes[1] & 0x06) >> 1); if (frame.MpegLayer == MpegLayer.Reserved) { return false; } int layerIndex = frame.MpegLayer == MpegLayer.Layer1 ? 0 : frame.MpegLayer == MpegLayer.Layer2 ? 1 : 2; frame.crcPresent = (headerBytes[1] & 0x01) == 0x00; int bitRateIndex = (headerBytes[2] & 0xF0) >> 4; if (bitRateIndex == 15) { // invalid index return false; } int versionIndex = frame.MpegVersion == Wave.MpegVersion.Version1 ? 0 : 1; frame.BitRate = bitRates[versionIndex, layerIndex, bitRateIndex] * 1000; if (frame.BitRate == 0) { return false; } int sampleFrequencyIndex = (headerBytes[2] & 0x0C) >> 2; if (sampleFrequencyIndex == 3) { return false; } if (frame.MpegVersion == MpegVersion.Version1) { frame.SampleRate = sampleRatesVersion1[sampleFrequencyIndex]; } else if (frame.MpegVersion == MpegVersion.Version2) { frame.SampleRate = sampleRatesVersion2[sampleFrequencyIndex]; } else { // mpegVersion == MpegVersion.Version25 frame.SampleRate = sampleRatesVersion25[sampleFrequencyIndex]; } bool padding = (headerBytes[2] & 0x02) == 0x02; bool privateBit = (headerBytes[2] & 0x01) == 0x01; frame.ChannelMode = (ChannelMode)((headerBytes[3] & 0xC0) >> 6); int channelExtension = (headerBytes[3] & 0x30) >> 4; bool copyright = (headerBytes[3] & 0x08) == 0x08; bool original = (headerBytes[3] & 0x04) == 0x04; int emphasis = (headerBytes[3] & 0x03); int nPadding = padding ? 1 : 0; frame.SampleCount = samplesPerFrame[versionIndex, layerIndex]; int coefficient = frame.SampleCount / 8; if (frame.MpegLayer == MpegLayer.Layer1) { frame.FrameLength = (coefficient * frame.BitRate / frame.SampleRate + nPadding) * 4; } else { frame.FrameLength = (coefficient * frame.BitRate) / frame.SampleRate + nPadding; } if (frame.FrameLength > MaxFrameLength) { return false; } return true; } return false; }
private void _bufferLoop() { Console.WriteLine("[Buffering thread] Started."); _wavebuffer.DiscardOnBufferOverflow = true; // Buffering loop do { if (_cancel_buffer.IsCancellationRequested) { Console.WriteLine("[Buffering thread] Cancellation requested."); //_cancel_buffer_token.ThrowIfCancellationRequested(); //Console.WriteLine("[Buffering thread] WARNING: Cancellation token is not cleanly set!"); break; } // Checking metadata if (Metadata != stream.Metadata) { this.Metadata = stream.Metadata; Task.Factory.StartNew(() => { Console.WriteLine("[Buffering thread] Metadata has been changed to \"{0}\"", stream.Metadata); Console.WriteLine("[Buffering thread] Delaying because of the buffering...", stream.Metadata); Thread.Sleep(_wavebuffer.BufferedDuration); Console.WriteLine("[Buffering thread] Exposing metadata NOW.", stream.Metadata); if (MetadataChanged != null) MetadataChanged.Invoke(this, new EventArgs()); }); } // Seperated buffer long bufferSize = 1024 * (Codec == StreamCodec.MP3 ? 128 : 8); // 128 kB for MP3, 8 kB for OGG/AACplus byte[] buffer = new byte[bufferSize]; int decompressedLength = 0; switch (Codec) { case StreamCodec.MP3: // Decompress the frame decompressedLength = _decoderMp3.DecompressFrame(frame, buffer, 0); // Read next frame frame = Mp3Frame.LoadFromStream(stream); // Add the decompressed frame (samples) into the audio buffer for later playback _wavebuffer.AddSamples(buffer, 0, decompressedLength); break; default: throw new NotSupportedException(); } } while (true); _decoderMp3.Dispose(); stream.Close(); stream.Dispose(); }
private static bool IsValidHeader(byte[] headerBytes, Mp3Frame frame) { if (headerBytes[0] != 255 || (headerBytes[1] & 224) != 224) { return(false); } frame.MpegVersion = (MpegVersion)((headerBytes[1] & 24) >> 3); if (frame.MpegVersion == MpegVersion.Reserved) { return(false); } frame.MpegLayer = (MpegLayer)((headerBytes[1] & 6) >> 1); if (frame.MpegLayer == MpegLayer.Reserved) { return(false); } int num = (frame.MpegLayer == MpegLayer.Layer1) ? 0 : ((frame.MpegLayer == MpegLayer.Layer2) ? 1 : 2); frame.CrcPresent = ((headerBytes[1] & 1) == 0); frame.BitRateIndex = (headerBytes[2] & 240) >> 4; if (frame.BitRateIndex == 15) { return(false); } int num2 = (frame.MpegVersion == MpegVersion.Version1) ? 0 : 1; frame.BitRate = Mp3Frame.bitRates[num2, num, frame.BitRateIndex] * 1000; if (frame.BitRate == 0) { return(false); } int num3 = (headerBytes[2] & 12) >> 2; if (num3 == 3) { return(false); } if (frame.MpegVersion == MpegVersion.Version1) { frame.SampleRate = Mp3Frame.sampleRatesVersion1[num3]; } else if (frame.MpegVersion == MpegVersion.Version2) { frame.SampleRate = Mp3Frame.sampleRatesVersion2[num3]; } else { frame.SampleRate = Mp3Frame.sampleRatesVersion25[num3]; } bool flag = (headerBytes[2] & 2) == 2; byte b = headerBytes[2]; frame.ChannelMode = (ChannelMode)((headerBytes[3] & 192) >> 6); frame.ChannelExtension = (headerBytes[3] & 48) >> 4; if (frame.ChannelExtension != 0 && frame.ChannelMode != ChannelMode.JointStereo) { return(false); } frame.Copyright = ((headerBytes[3] & 8) == 8); byte b2 = headerBytes[3]; byte b3 = headerBytes[3]; int num4 = flag ? 1 : 0; frame.SampleCount = Mp3Frame.samplesPerFrame[num2, num]; int num5 = frame.SampleCount / 8; if (frame.MpegLayer == MpegLayer.Layer1) { frame.FrameLength = (num5 * frame.BitRate / frame.SampleRate + num4) * 4; } else { frame.FrameLength = num5 * frame.BitRate / frame.SampleRate + num4; } return(frame.FrameLength <= 16384); }
public static Mp3Frame LoadFromStream(Stream input) { return(Mp3Frame.LoadFromStream(input, true)); }
public void SetWaveFormat(Mp3Frame frame) { if (frame == null) return; waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate); return; }
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); }
private void _buffer(Stream input) { Console.WriteLine("[Initial buffering] Meta interval: {0}", this.StationInformation.ContainsKey("icy-metaint") ? long.Parse(this.StationInformation["icy-metaint"]) : -1); // Auto-fix the stream and auto-parse metadata stream = new FixedBufferedStream( input, this.StationInformation.ContainsKey("icy-metaint") ? long.Parse(this.StationInformation["icy-metaint"]) : -1 ); // Read first frame this.Status = StreamStatus.Buffering; switch (Codec) { case StreamCodec.MP3: // Make a decoder which can decode that (and sequentially following) frames // The decoder will decode to 16-bit samples frame = Mp3Frame.LoadFromStream(stream); _decoderMp3 = new AcmMp3FrameDecompressor(new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate)); Console.WriteLine("[Initial buffering] MP3 decoder will encode to {0}-encoded wave format.", _decoderMp3.OutputFormat.Encoding); break; default: throw new NotSupportedException(); } }
public void CanParseValidMp3Frame() { MemoryStream ms = new MemoryStream(constructValidMp3Frame()); Mp3Frame frame = new Mp3Frame(ms); }
public Mp3FrameInfo(Mp3Frame frame, double averageVolume) { this.Frame = frame; _averageVolume = averageVolume; }
public void FailsToParseInvalidFrame(int length) { MemoryStream ms = new MemoryStream(new byte[length]); Assert.Throws<EndOfStreamException>(() => { Mp3Frame frame = new Mp3Frame(ms); }); }
private void ValidateFrameFormat(Mp3Frame frame) { if (frame.SampleRate != Mp3WaveFormat.SampleRate) { string message = String.Format( "Got a frame at sample rate {0}, in an MP3 with sample rate {1}. Mp3FileReader does not support sample rate changes.", frame.SampleRate, Mp3WaveFormat.SampleRate); throw new InvalidOperationException(message); } int channels = frame.ChannelMode == ChannelMode.Mono ? 1 : 2; if (channels != Mp3WaveFormat.Channels) { string message = String.Format( "Got a frame with channel mode {0}, in an MP3 with {1} channels. Mp3FileReader does not support changes to channel count.", frame.ChannelMode, Mp3WaveFormat.Channels); throw new InvalidOperationException(message); } }
private int DecompressFrame(Mp3Frame frame, byte[] buffer) { // decode frame if (_decompressor == null) { WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate); _decompressor = new AcmMp3FrameDecompressor(waveFormat); _waveProvider = new BufferedWaveProvider(_decompressor.OutputFormat); _waveProvider.BufferDuration = TimeSpan.FromSeconds(5); _channels = _waveProvider.WaveFormat.Channels; _sampleProvider = _waveProvider.ToSampleProvider(); } return _decompressor.DecompressFrame(frame, buffer, 0); }