private void ReadSamples(MpegFrame frame) { // load in all the data for this frame (1152 samples in this case) // NB: we flatten these into output order for (int ss = 0, idx = 0; ss < SSLIMIT; ss++, idx += SBLIMIT * (_granuleCount - 1)) { for (int sb = 0; sb < SBLIMIT; sb++, idx++) { for (int ch = 0; ch < _channels; ch++) { if (ch == 0 || sb < _jsbound) { int[] samples = _samples[ch]; int alloc = _allocation[ch][sb]; if (alloc != 0) { if (alloc < 0) { // grouping (Layer II only, so we don't have to play with the granule count) int val = frame.ReadBits(-alloc); int levels = (1 << (-alloc / 2 + -alloc % 2 - 1)) + 1; samples[idx] = val % levels; val /= levels; samples[idx + SBLIMIT] = val % levels; samples[idx + SBLIMIT * 2] = val / levels; } else { // non-grouping for (int gr = 0; gr < _granuleCount; gr++) { samples[idx + SBLIMIT * gr] = frame.ReadBits(alloc); } } } else { // no energy... zero out the samples for (int gr = 0; gr < _granuleCount; gr++) { samples[idx + SBLIMIT * gr] = 0; } } } else { int[] samples0 = _samples[0]; int[] samples1 = _samples[1]; // copy chan 0 to chan 1 for (int gr = 0; gr < _granuleCount; gr++) { samples1[idx + SBLIMIT * gr] = samples0[idx + SBLIMIT * gr]; } } } } } }
private void ReadAllocation(MpegFrame frame, int[] rateTable) { var _subBandCount = rateTable.Length; if (_jsbound > _subBandCount) { _jsbound = _subBandCount; } Array.Clear(_allocation[0], 0, SBLIMIT); Array.Clear(_allocation[1], 0, SBLIMIT); int sb = 0; for (; sb < _jsbound; sb++) { int[] table = _allocLookupTable[rateTable[sb]]; int bits = table[0]; for (int ch = 0; ch < _channels; ch++) { _allocation[ch][sb] = table[frame.ReadBits(bits) + 1]; } } for (; sb < _subBandCount; sb++) { int[] table = _allocLookupTable[rateTable[sb]]; _allocation[0][sb] = _allocation[1][sb] = table[frame.ReadBits(table[0]) + 1]; } }
private void ReadScaleFactors(MpegFrame frame) { for (int sb = 0; sb < SBLIMIT; sb++) { for (int ch = 0; ch < _channels; ch++) { int[][] scalefac = _scalefac[ch]; switch (_scfsi[ch][sb]) { case 0: // all three scalefac[0][sb] = frame.ReadBits(6); scalefac[1][sb] = frame.ReadBits(6); scalefac[2][sb] = frame.ReadBits(6); break; case 1: // only two (2 = 1) scalefac[0][sb] = scalefac[1][sb] = frame.ReadBits(6); scalefac[2][sb] = frame.ReadBits(6); break; case 2: // only one (3 = 2 = 1) scalefac[0][sb] = scalefac[1][sb] = scalefac[2][sb] = frame.ReadBits(6); break; case 3: // only two (3 = 2) scalefac[0][sb] = frame.ReadBits(6); scalefac[1][sb] = scalefac[2][sb] = frame.ReadBits(6); break; default: // none scalefac[0][sb] = 63; scalefac[1][sb] = 63; scalefac[2][sb] = 63; break; } } } }
public bool AddBits(MpegFrame frame, int overlap) { int originalEnd = _end; int slots = GetSlots(frame); while (--slots >= 0) { int tmp = frame.ReadBits(8); if (tmp == -1) { ThrowFrameNotEnoughBytes(); } _buf[++_end] = (byte)tmp; if (_end == BufferSize - 1) { _end = -1; } } _bitsLeft = 8; if (originalEnd == -1) { // it's either the start of the stream or we've reset... // only return true if overlap says this frame is enough return(overlap == 0); } else { // it's not the start of the stream so calculate _start based on whether we have enough bytes left // if we have enough bytes, reset start to match overlap if ((originalEnd + 1 - _start + BufferSize) % BufferSize >= overlap) { _start = (originalEnd + 1 - overlap + BufferSize) % BufferSize; return(true); } // otherwise, just set start to match the start of the frame (we probably skipped a frame) else { _start = originalEnd; return(false); } } }
private static int GetSlots(MpegFrame frame) { int cnt = frame.FrameLength - 4; if (frame.HasCrc) { cnt -= 2; } if (frame.Version == MpegVersion.Version1 && frame.ChannelMode != MpegChannelMode.Mono) { return(cnt - 32); } if (frame.Version > MpegVersion.Version1 && frame.ChannelMode == MpegChannelMode.Mono) { return(cnt - 9); } return(cnt - 17); }
// this just reads the channel mode and set a few flags private void InitFrame(MpegFrame frame) { switch (frame.ChannelMode) { case MpegChannelMode.Mono: _channels = 1; _jsbound = SBLIMIT; break; case MpegChannelMode.JointStereo: _channels = 2; _jsbound = frame.ChannelModeExtension * 4 + 4; break; default: _channels = 2; _jsbound = SBLIMIT; break; } }
public override int DecodeFrame(MpegFrame frame, Span <float> ch0, Span <float> ch1) { InitFrame(frame); int[] rateTable = GetRateTable(frame); ReadAllocation(frame, rateTable); for (int i = 0; i < _scfsi[0].Length; i++) { // Since Layer II has to know which subbands have energy, // we use the "Layer I valid" selection to mark that energy is present. // That way Layer I doesn't have to do anything else. _scfsi[0][i] = _allocation[0][i] != 0 ? 2 : -1; _scfsi[1][i] = _allocation[1][i] != 0 ? 2 : -1; } ReadScaleFactorSelection(frame, _scfsi, _channels); ReadScaleFactors(frame); ReadSamples(frame); return(DecodeSamples(ch0, ch1)); }
internal MpegFrame NextFrame() { // if _current is null, we've returned the last frame already var frame = _current; if (frame != null) { if (_canSeek) { frame.SaveBuffer(); DiscardThrough(frame.Offset + frame.FrameLength, false); } if (frame == _last && !_endFound) { do { FindNextFrame(); } while (frame == _last && !_endFound); } _current = frame.Next; if (!_canSeek) { // if we're in a forward-only stream, don't bother keeping the frames that have already been processed lock (_frameLock) { var temp = _first; _first = temp.Next; temp.Next = null; } } } return(frame); }
FrameBase FindNextFrame() { // if we've found the end, don't bother looking for anything else if (_endFound) { return(null); } var freeFrame = _lastFree; var lastFrameStart = _readOffset; lock (_frameLock) { // read 3 bytes var syncBuf = new byte[4]; try { if (Read(_readOffset, syncBuf, 0, 4) == 4) { // now loop until a frame is found do { var sync = (uint)(syncBuf[0] << 24 | syncBuf[1] << 16 | syncBuf[2] << 8 | syncBuf[3]); lastFrameStart = _readOffset; // try ID3 first (for v2 frames) if (_id3Frame == null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) { f.SaveBuffer(); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return(_id3Frame = f); } } } // now look for a RIFF header if (_first == null && _riffHeaderFrame == null) { var f = RiffHeaderFrame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { _readOffset += f.Length; DiscardThrough(_readOffset, true); return(_riffHeaderFrame = f); } } } // finally, just try for an MPEG frame var frame = MpegFrame.TrySync(sync); if (frame != null) { if (frame.Validate(_readOffset, this) && !(freeFrame != null && (frame.Layer != freeFrame.Layer || frame.Version != freeFrame.Version || frame.SampleRate != freeFrame.SampleRate || frame.BitRateIndex > 0 ) ) ) { if (!_canSeek) { frame.SaveBuffer(); DiscardThrough(_readOffset + frame.FrameLength, true); } _readOffset += frame.FrameLength; if (_first == null) { if (_vbrInfo == null && (_vbrInfo = frame.ParseVBR()) != null) { return(FindNextFrame()); } else { frame.Number = 0; _first = _last = frame; } } else { if (frame.SampleCount != _first.SampleCount) { _mixedFrameSize = true; } frame.SampleOffset = _last.SampleCount + _last.SampleOffset; frame.Number = _last.Number + 1; _last = (_last.Next = frame); } if (frame.BitRateIndex == 0) { _lastFree = frame; } return(frame); } } // if we've read MPEG frames and can't figure out what frame type we have, try looking for a new ID3 tag if (_last != null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) { f.SaveBuffer(); } // if it's a v1 tag, go ahead and parse it if (f.Version == 1) { _id3v1Frame = f; } else { // grrr... the ID3 2.4 spec says tags can be anywhere in the file and that later tags can override earlier ones... boo _id3Frame.Merge(f); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return(f); } } } // well, we didn't find anything, so rinse and repeat with the next byte ++_readOffset; if (_first == null || !_canSeek) { DiscardThrough(_readOffset, true); } Buffer.BlockCopy(syncBuf, 1, syncBuf, 0, 3); } while (Read(_readOffset + 3, syncBuf, 3, 1) == 1); } // move the "end of frame" marker for the last free format frame (in case we have one) // this is because we don't include the last four bytes otherwise lastFrameStart += 4; _endFound = true; return(null); } finally { if (freeFrame != null) { freeFrame.Length = (int)(lastFrameStart - freeFrame.Offset); if (!_canSeek) { // gotta finish filling the buffer!! throw new InvalidOperationException("Free frames cannot be read properly from forward-only streams!"); } // if _lastFree hasn't changed (we got a non-MPEG frame), clear it out if (_lastFree == freeFrame) { _lastFree = null; } } } } }
FrameBase FindNextFrame() { // if we've found the end, don't bother looking for anything else if (_endFound) return null; var freeFrame = _lastFree; var lastFrameStart = _readOffset; lock (_frameLock) { // read 3 bytes var syncBuf = new byte[4]; try { if (Read(_readOffset, syncBuf, 0, 4) == 4) { // now loop until a frame is found do { var sync = (uint)(syncBuf[0] << 24 | syncBuf[1] << 16 | syncBuf[2] << 8 | syncBuf[3]); lastFrameStart = _readOffset; // try ID3 first (for v2 frames) if (_id3Frame == null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) f.SaveBuffer(); _readOffset += f.Length; DiscardThrough(_readOffset, true); return _id3Frame = f; } } } // now look for a RIFF header if (_first == null && _riffHeaderFrame == null) { var f = RiffHeaderFrame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { _readOffset += f.Length; DiscardThrough(_readOffset, true); return _riffHeaderFrame = f; } } } // finally, just try for an MPEG frame var frame = MpegFrame.TrySync(sync); if (frame != null) { if (frame.Validate(_readOffset, this) && !(freeFrame != null && (frame.Layer != freeFrame.Layer || frame.Version != freeFrame.Version || frame.SampleRate != freeFrame.SampleRate || frame.BitRateIndex > 0 ) ) ) { if (!_canSeek) { frame.SaveBuffer(); DiscardThrough(_readOffset + frame.FrameLength, true); } _readOffset += frame.FrameLength; if (_first == null) { if (_vbrInfo == null && (_vbrInfo = frame.ParseVBR()) != null) { return FindNextFrame(); } else { frame.Number = 0; _first = _last = frame; } } else { if (frame.SampleCount != _first.SampleCount) { _mixedFrameSize = true; } frame.SampleOffset = _last.SampleCount + _last.SampleOffset; frame.Number = _last.Number + 1; _last = (_last.Next = frame); } if (frame.BitRateIndex == 0) { _lastFree = frame; } return frame; } } // if we've read MPEG frames and can't figure out what frame type we have, try looking for a new ID3 tag if (_last != null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) f.SaveBuffer(); // if it's a v1 tag, go ahead and parse it if (f.Version == 1) { _id3v1Frame = f; } else { // grrr... the ID3 2.4 spec says tags can be anywhere in the file and that later tags can override earlier ones... boo _id3Frame.Merge(f); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return f; } } } // well, we didn't find anything, so rinse and repeat with the next byte ++_readOffset; if (_first == null || !_canSeek) DiscardThrough(_readOffset, true); Buffer.BlockCopy(syncBuf, 1, syncBuf, 0, 3); } while (Read(_readOffset + 3, syncBuf, 3, 1) == 1); } // move the "end of frame" marker for the last free format frame (in case we have one) // this is because we don't include the last four bytes otherwise lastFrameStart += 4; _endFound = true; return null; } finally { if (freeFrame != null) { freeFrame.Length = (int)(lastFrameStart - freeFrame.Offset); if (!_canSeek) { // gotta finish filling the buffer!! throw new InvalidOperationException("Free frames cannot be read properly from forward-only streams!"); } // if _lastFree hasn't changed (we got a non-MPEG frame), clear it out if (_lastFree == freeFrame) { _lastFree = null; } } } } }
public abstract int DecodeFrame(MpegFrame frame, Span <float> ch0, Span <float> ch1);
static internal bool GetCRC(MpegFrame frame, ref uint crc) { return LayerIIDecoderBase.GetCRC(frame, _rateTable, _allocLookupTable, false, ref crc); }
static internal bool GetCRC(MpegFrame frame, ref uint crc) { var cnt = frame.GetSideDataSize(); while (--cnt >= 0) { MpegFrame.UpdateCRC(frame.ReadBits(8), 8, ref crc); } return true; }
static internal bool GetCRC(MpegFrame frame, ref uint crc) { return(LayerIIDecoderBase.GetCRC(frame, _rateTable, _allocLookupTable, false, ref crc)); }
static internal bool GetCRC(MpegFrame frame, ref uint crc) { return LayerIIDecoderBase.GetCRC(frame, SelectTable(frame), _allocLookupTable, true, ref crc); }
protected static bool GetCRC( MpegFrame frame, int[] rateTable, int[][] allocLookupTable, bool readScfsiBits, ref uint crc) { // ugh... we basically have to re-implement the allocation logic here. // keep up with how many active subbands we need to read selection info for var scfsiBits = 0; // only read as many subbands as we actually need; pay attention to the intensity stereo subbands var subbandCount = rateTable.Length; var jsbound = subbandCount; if (frame.ChannelMode == MpegChannelMode.JointStereo) { jsbound = frame.ChannelModeExtension * 4 + 4; } // read the full stereo subbands var channels = frame.ChannelMode == MpegChannelMode.Mono ? 1 : 2; var sb = 0; for (; sb < jsbound; sb++) { var bits = allocLookupTable[rateTable[sb]][0]; for (int ch = 0; ch < channels; ch++) { var alloc = frame.ReadBits(bits); if (alloc > 0) { scfsiBits += 2; } MpegFrame.UpdateCRC(alloc, bits, ref crc); } } // read the intensity stereo subbands for (; sb < subbandCount; sb++) { var bits = allocLookupTable[rateTable[sb]][0]; var alloc = frame.ReadBits(bits); if (alloc > 0) { scfsiBits += channels * 2; } MpegFrame.UpdateCRC(alloc, bits, ref crc); } // finally, read the scalefac selection bits if (readScfsiBits) { while (scfsiBits >= 2) { MpegFrame.UpdateCRC(frame.ReadBits(2), 2, ref crc); scfsiBits -= 2; } } return(true); }
protected abstract int[] GetRateTable(MpegFrame frame);
internal MpegFrame NextFrame() { // if _current is null, we've returned the last frame already var frame = _current; if (frame != null) { if (_canSeek) { frame.SaveBuffer(); DiscardThrough(frame.Offset + frame.FrameLength, false); } if (frame == _last && !_endFound) { do { FindNextFrame(); } while (frame == _last && !_endFound); } _current = frame.Next; if (!_canSeek) { // if we're in a forward-only stream, don't bother keeping the frames that have already been processed lock (_frameLock) { var temp = _first; _first = temp.Next; temp.Next = null; } } } return frame; }
protected abstract void ReadScaleFactorSelection(MpegFrame frame, int[][] scfsi, int channels);