Beispiel #1
0
        public long SeekTo(long granulePos, int preRoll, GetPacketGranuleCount getPacketGranuleCount)
        {
            if (_reader == null)
            {
                throw new ObjectDisposedException(nameof(PacketProvider));
            }

            var pageIndex = _reader.FindPage(granulePos);

            int packetIndex;

            if (granulePos == 0)
            {
                // for this, we can generically say the first packet on the first page having a non-zero granule
                packetIndex = 0;
            }
            else
            {
                packetIndex  = FindPacket(pageIndex, ref granulePos, getPacketGranuleCount);
                packetIndex -= preRoll;
            }

            if (!NormalizePacketIndex(ref pageIndex, ref packetIndex))
            {
                throw new ArgumentOutOfRangeException(nameof(granulePos));
            }

            _lastPacket  = null;
            _pageIndex   = pageIndex;
            _packetIndex = packetIndex;
            return(granulePos);
        }
Beispiel #2
0
        private int FindPacket(int pageIndex, ref long granulePos, GetPacketGranuleCount getPacketGranuleCount, bool isRecursed = false)
        {
            // pageIndex is the correct page; we just need to figure out which packet
            // first let's get the starting granule of the page
            long startGP;
            bool isContinued;

            if (pageIndex == 0)
            {
                startGP = 0;
            }
            else if (_reader.GetPage(pageIndex - 1, out startGP, out _, out _, out isContinued, out _, out _))
            {
                if (isContinued)
                {
                    // we have a continued packet, so we need to look at the previous page
                    return(FindPacket(pageIndex - 1, ref granulePos, getPacketGranuleCount, true));
                }
            }
            else
            {
                throw new System.IO.InvalidDataException("Could not get page?!");
            }

            // now get the ending granule of the page
            if (!_reader.GetPage(pageIndex, out var endGP, out var isResync, out _, out isContinued, out var packetCount, out _))
            {
                throw new System.IO.InvalidDataException("Could not get found page?!");
            }

            // increment through the packets until we would go past granulePos
            var packetIndex = -1;
            var isFirst     = pageIndex == _reader.FirstDataPageIndex;

            while (++packetIndex < packetCount)
            {
                var packet = CreatePacket(ref pageIndex, ref packetIndex, false, endGP, isFirst && isResync, isContinued, packetCount, 0);
                if (packet == null)
                {
                    throw new System.IO.InvalidDataException("Could not find end of continuation!");
                }
                var granules = getPacketGranuleCount(packet, isFirst);
                if (startGP + granules > granulePos)
                {
                    granulePos = startGP;
                    return(packetIndex);
                }
                startGP += granules;
                isFirst  = false;
            }

            if (isContinued && isRecursed)
            {
                granulePos = endGP;
                return(packetCount - 1);
            }

            // we ran out of packets?!
            throw new System.IO.InvalidDataException("Ran out of packets?!");
        }
Beispiel #3
0
        public long SeekTo(long granulePos, int preRoll, GetPacketGranuleCount getPacketGranuleCount)
        {
            if (_reader == null)
            {
                throw new ObjectDisposedException(nameof(PacketProvider));
            }

            int pageIndex;
            int packetIndex;

            if (granulePos == 0)
            {
                // for this, we can generically say the first packet on the first page having a non-zero granule
                pageIndex   = _reader.FirstDataPageIndex;
                packetIndex = 0;
            }
            else
            {
                pageIndex = _reader.FindPage(granulePos);
                if (_reader.HasAllPages && _reader.MaxGranulePosition == granulePos)
                {
                    // allow seek to the offset immediatly after the last available (for what good it'll do)
                    _lastPacket  = null;
                    _pageIndex   = pageIndex;
                    _packetIndex = 0;
                    return(granulePos);
                }
                else
                {
                    packetIndex = FindPacket(pageIndex, ref granulePos, getPacketGranuleCount);
                }
                packetIndex -= preRoll;
            }

            if (!NormalizePacketIndex(ref pageIndex, ref packetIndex))
            {
                throw new ArgumentOutOfRangeException(nameof(granulePos));
            }

            if (pageIndex < _reader.FirstDataPageIndex)
            {
                pageIndex   = _reader.FirstDataPageIndex;
                packetIndex = 0;
            }

            _lastPacket  = null;
            _pageIndex   = pageIndex;
            _packetIndex = packetIndex;
            return(granulePos);
        }
Beispiel #4
0
        private int FindPacket(int pageIndex, ref long granulePos, GetPacketGranuleCount getPacketGranuleCount)
        {
            // we will only look through the current page...
            // if the granule isn't on the page, behavior is:
            //   - if before: return 0
            //   - if after: return packetCount - (isContinued ? 2 : 1)
            // neither should happen because we're already looking at the correct page

            if (_reader.GetPage(pageIndex, out var pageGranulePos, out var isResync, out _, out var isContinued, out var packetCount, out var pageOverhead))
            {
                var gp          = pageGranulePos;
                var packetIndex = packetCount - (isContinued ? 2 : 1);
                while (packetIndex > 0)
                {
                    if (gp >= granulePos)
                    {
                        var packet = CreatePacket(ref pageIndex, ref packetIndex, false, pageGranulePos, isResync, isContinued, packetCount, pageOverhead);
                        if (packet == null)
                        {
                            break;
                        }
                        gp -= getPacketGranuleCount(packet, false);
                    }

                    if (gp < granulePos)
                    {
                        granulePos = gp;
                        return(packetIndex);
                    }

                    --packetIndex;
                }
                if (packetIndex == 0)
                {
                    // we're likely in the right spot for the granulePos...
                    if (pageIndex > 0 && _reader.GetPage(pageIndex - 1, out var prevGranulePos, out _, out _, out _, out _, out _))
                    {
                        granulePos = prevGranulePos;
                        return(0);
                    }
                }
            }
            return(-1);
        }
Beispiel #5
0
        private int FindPacket(int pageIndex, ref long granulePos, GetPacketGranuleCount getPacketGranuleCount)
        {
            // pageIndex is the correct page; we just need to figure out which packet
            bool isContinued;
            int  firstRealPacket = 0;

            if (_reader.GetPage(pageIndex - 1, out _, out _, out _, out isContinued, out _, out _))
            {
                if (isContinued)
                {
                    firstRealPacket = 1;
                }
            }
            else
            {
                throw new System.IO.InvalidDataException("Could not get page?!");
            }

            // now get the ending granule of the page
            if (!_reader.GetPage(pageIndex, out var pageGranulePos, out var isResync, out var isContinuation, out isContinued, out var packetCount, out _))
            {
                throw new System.IO.InvalidDataException("Could not get found page?!");
            }

            if (isContinued)
            {
                // if continued, the last packet index doesn't apply
                packetCount--;
            }

            var packetIndex  = packetCount;
            var isLastInPage = !isContinued;
            var endGP        = pageGranulePos;

            while (endGP > granulePos && --packetIndex >= firstRealPacket)
            {
                // it would be nice to pass false instead of isContinued, but (hypothetically) we don't know if getPacketGranuleCount(...) needs the whole thing...
                // Vorbis doesn't, but someone might decide to try to use us for another purpose so we'll be good here.
                var packet = CreatePacket(ref pageIndex, ref packetIndex, false, pageGranulePos, packetIndex == 0 && isResync, isContinued, packetCount, 0);
                if (packet == null)
                {
                    throw new System.IO.InvalidDataException("Could not find end of continuation!");
                }
                endGP       -= getPacketGranuleCount(packet, isLastInPage);
                isLastInPage = false;
            }

            if (packetIndex < firstRealPacket)
            {
                // either it's a continued packet OR we've hit the "long->short over page boundary" bug.
                // in both cases we'll just return the last packet of the previous page.
                var prevPageIndex   = pageIndex;
                var prevPacketIndex = -1;
                if (!NormalizePacketIndex(ref prevPageIndex, ref prevPacketIndex))
                {
                    throw new System.IO.InvalidDataException("Failed to normalize packet index?");
                }
                var packet = CreatePacket(ref prevPageIndex, ref prevPacketIndex, false, endGP, false, isContinuation, prevPacketIndex + 1, 0);
                if (packet == null)
                {
                    throw new System.IO.InvalidDataException("Could not load previous packet!");
                }
                granulePos = endGP - getPacketGranuleCount(packet, false);
                return(-1);
            }

            // normal seek; that wasn't so hard, right?
            granulePos = endGP;
            return(packetIndex);
        }
 /// <summary>
 /// Not supported
 /// </summary>
 /// <param name="granulePos"></param>
 /// <param name="preRoll"></param>
 /// <param name="getPacketGranuleCount"></param>
 /// <returns></returns>
 public long SeekTo(long granulePos, int preRoll, GetPacketGranuleCount getPacketGranuleCount) => throw new NotSupportedException();