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; } } } } }