public void Dispose() { HasEndOfStream = true; if (_container != null) { _container.DisposePacketReader(this); } _container = null; _current = null; if (_first != null) { var node = _first; _first = null; while (node.Next != null) { var tmp = node.Next; node.Next = null; node = tmp; node.Prev = null; } } _last = null; }
public DataPacket FindPacket(long granulePos, Func <DataPacket, DataPacket, int> packetGranuleCountCallback) { // This will find which packet contains the granule position being requested. It is basically a linear search. // Please note, the spec actually calls for a bisection search, but the result here should be the same. // don't look for any position before 0! if (granulePos < 0) { throw new ArgumentOutOfRangeException(nameof(granulePos)); } OggPacket foundPacket = null; // determine which direction to search from... var packet = _current ?? _first; if (granulePos > packet.PageGranulePosition) { // forward search // find the first packet in the page the requested granule is on while (granulePos > packet.PageGranulePosition) { if ((packet.Next == null || packet.IsContinued) && !HasEndOfStream) { _container.GatherNextPage(StreamSerial); if (HasEndOfStream) { packet = null; break; } } packet = packet.Next; } foundPacket = FindPacketInPage(packet, granulePos, packetGranuleCountCallback); } else { // reverse search (or we're looking at the same page) while (packet.Prev != null && (granulePos <= packet.Prev.PageGranulePosition || packet.Prev.PageGranulePosition == -1)) { packet = packet.Prev; } foundPacket = FindPacketInPage(packet, granulePos, packetGranuleCountCallback); } return(foundPacket); }
public static void Return(OggPacket packet) { if (packet == null) { return; } lock (_mutex) { if (_pool.Count < MaxPackets) { _pool.Push(packet); } } }
private OggPacket GetLastPacketInPage(OggPacket packet) { if (packet != null) { int pageSeqNumber = packet.PageSequenceNumber; while (packet.Next != null && packet.Next.PageSequenceNumber == pageSeqNumber) { packet = packet.Next; } if (packet != null && packet.IsContinued) { // move to the *actual* last packet of the page... // If .Prev is null, something is wrong and we can't seek anyway packet = packet.Prev; } } return(packet); }
internal void AddPacket(OggPacket packet) { lock (_packetLock) { // if we've already found the end of the stream, don't accept any more packets if (HasEndOfStream) { return; } // if the packet is a resync, it cannot be a continuation... if (packet.IsResync) { packet.IsContinuation = false; if (_last != null) { _last.IsContinued = false; } } if (packet.IsContinuation) { // if we get here, the stream is invalid if there isn't a previous packet if (_last == null) { throw new InvalidDataException(); } // if the last packet isn't continued, something is wrong if (!_last.IsContinued) { throw new InvalidDataException(); } _last.MergeWith(packet); _last.IsContinued = packet.IsContinued; } else { if (!(packet is OggPacket p)) { throw new ArgumentException("Wrong packet datatype."); } if (_first == null) { // this is the first packet to add, so just set first & last to point at it _first = p; _last = p; } else { // swap the new packet in to the last position (remember, we're doubly-linked) _last = (p.Prev = _last).Next = p; } } if (packet.IsEndOfStream) { SetEndOfStream(); } } }
private OggPacket FindPacketInPage( OggPacket pagePacket, long targetGranulePos, Func <DataPacket, DataPacket, int> packetGranuleCountCallback) { OggPacket lastPacketInPage = GetLastPacketInPage(pagePacket); if (lastPacketInPage == null) { return(null); } // return the packet the granule position is in OggPacket packet = lastPacketInPage; do { if (!packet.GranuleCount.HasValue) { // we don't know its length or position... // if it's the last packet in the page, it gets the page's granule position. Otherwise, calc it. if (packet == lastPacketInPage) { packet.GranulePosition = packet.PageGranulePosition; } else { packet.GranulePosition = packet.Next.GranulePosition - packet.Next.GranuleCount.Value; } // if it's the last packet in the stream, it might be a partial. The spec says the last packet has to be on its own page, so if it is not assume the stream was truncated. if (packet == _last && HasEndOfStream && packet.Prev.PageSequenceNumber < packet.PageSequenceNumber) { packet.GranuleCount = (int)(packet.GranulePosition - packet.Prev.PageGranulePosition); } else if (packet.Prev != null) { packet.Prev.Reset(); packet.Reset(); packet.GranuleCount = packetGranuleCountCallback(packet, packet.Prev); } else { // probably the first data packet... if (packet.GranulePosition > packet.Next.GranulePosition - packet.Next.GranuleCount) { throw new InvalidOperationException("First data packet size mismatch."); } packet.GranuleCount = (int)packet.GranulePosition; } } // we now know the granule position and count of the packet... is the target within that range? if (targetGranulePos <= packet.GranulePosition && targetGranulePos > packet.GranulePosition - packet.GranuleCount) { // make sure the previous packet has a position too if (packet.Prev != null && !packet.Prev.GranuleCount.HasValue) { packet.Prev.GranulePosition = packet.GranulePosition - packet.GranuleCount.Value; } return(packet); } packet = packet.Prev; } while (packet != null && packet.PageSequenceNumber == lastPacketInPage.PageSequenceNumber); // couldn't find it, but maybe that's because something glitched in the file... // we're doing this in case there's a dicontinuity in the file... It's not perfect, but it'll work if (packet != null && packet.PageGranulePosition < targetGranulePos) { packet.GranulePosition = packet.PageGranulePosition; return(packet.Next); } return(null); }