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);
        }
Exemple #3
0
        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);
        }