internal void MergeWith(NVorbis.DataPacket continuation) { var op = continuation as Packet; if (op == null) throw new ArgumentException("Incorrect packet type!"); Length += continuation.Length; if (_mergedPacket == null) { _mergedPacket = op; } else { _mergedPacket.MergeWith(continuation); } // per the spec, a partial packet goes with the next page's granulepos. we'll go ahead and assign it to the next page as well PageGranulePosition = continuation.PageGranulePosition; PageSequenceNumber = continuation.PageSequenceNumber; }
public void Dispose() { _eosFound = true; _container.DisposePacketReader(this); _container = null; _current = null; if (_first != null) { var node = _first; _first = null; while (node.Next != null) { var temp = node.Next; node.Next = null; node = temp; node.Prev = null; } node = null; } _last = null; }
Packet FindPacketInPage(Packet pagePacket, long targetGranulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback) { var lastPacketInPage = GetLastPacketInPage(pagePacket); if (lastPacketInPage == null) { return null; } // return the packet the granule position is in var 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 && _eosFound && 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; }
Packet GetLastPacketInPage(Packet packet) { if (packet != null) { var 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(Packet packet) { lock (_packetLock) { // if we've already found the end of the stream, don't accept any more packets if (_eosFound) 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 { var p = packet as Packet; if (p == null) throw new ArgumentException("Wrong packet datatype", "packet"); 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(); } } }
bool AddPage(PageHeader hdr) { // get our packet reader (create one if we have to) PacketReader packetReader; if (!_packetReaders.TryGetValue(hdr.StreamSerial, out packetReader)) { packetReader = new PacketReader(this, hdr.StreamSerial); } // save off the container bits packetReader.ContainerBits += _containerBits; _containerBits = 0; // get our flags prepped var isContinued = false; var isContinuation = (hdr.Flags & PageFlags.ContinuesPacket) == PageFlags.ContinuesPacket; var isEOS = false; var isResync = hdr.IsResync; // add all the packets, making sure to update flags as needed var dataOffset = hdr.DataOffset; var cnt = hdr.PacketSizes.Length; foreach (var size in hdr.PacketSizes) { var packet = new Packet(this, dataOffset, size) { PageGranulePosition = hdr.GranulePosition, IsEndOfStream = isEOS, PageSequenceNumber = hdr.SequenceNumber, IsContinued = isContinued, IsContinuation = isContinuation, IsResync = isResync, }; packetReader.AddPacket(packet); // update the offset into the stream for each packet dataOffset += size; // only the first packet in a page can be a continuation or resync isContinuation = false; isResync = false; // only the last packet in a page can be continued or flagged end of stream if (--cnt == 1) { isContinued = hdr.LastPacketContinues; isEOS = (hdr.Flags & PageFlags.EndOfStream) == PageFlags.EndOfStream; } } // if the packet reader list doesn't include the serial in question, add it to the list and indicate a new stream to the caller if (!_packetReaders.ContainsKey(hdr.StreamSerial)) { _packetReaders.Add(hdr.StreamSerial, packetReader); return true; } else { // otherwise, indicate an existing stream to the caller return false; } }