vlc | branch: master | Francois Cartegnie <fcvlc...@free.fr> | Mon Mar 15 21:14:56 2021 +0100| [cfdfa43bab1a358bb8d592c7053fb230dfa83f1f] | committer: Francois Cartegnie
demux: adaptive: split chunk computation & processing > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=cfdfa43bab1a358bb8d592c7053fb230dfa83f1f --- modules/demux/adaptive/SegmentTracker.cpp | 187 ++++++++++++++++++------------ modules/demux/adaptive/SegmentTracker.hpp | 16 ++- 2 files changed, 131 insertions(+), 72 deletions(-) diff --git a/modules/demux/adaptive/SegmentTracker.cpp b/modules/demux/adaptive/SegmentTracker.cpp index 35853c1d56..d3331d55d7 100644 --- a/modules/demux/adaptive/SegmentTracker.cpp +++ b/modules/demux/adaptive/SegmentTracker.cpp @@ -215,81 +215,157 @@ void SegmentTracker::reset() notify(RepresentationSwitchEvent(current.rep, nullptr)); current = Position(); next = Position(); + resetChunksSequence(); initializing = true; format = StreamFormat::UNKNOWN; } -SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, - AbstractConnectionManager *connManager) +SegmentTracker::ChunkEntry::ChunkEntry() +{ + chunk = nullptr; +} + +SegmentTracker::ChunkEntry::ChunkEntry(SegmentChunk *c, Position p, vlc_tick_t d) +{ + chunk = c; + pos = p; + duration = d; +} + +bool SegmentTracker::ChunkEntry::isValid() const { - ISegment *segment; + return chunk && pos.isValid(); +} +SegmentTracker::ChunkEntry +SegmentTracker::prepareChunk(bool switch_allowed, Position pos, + AbstractConnectionManager *connManager) const +{ if(!adaptationSet) - return nullptr; + return ChunkEntry(); bool b_updated = false; - bool b_switched = false; /* starting */ - if(!next.isValid()) + if(!pos.isValid()) { - next = getStartPosition(); - b_switched = true; + pos = getStartPosition(); + if(!pos.isValid()) + return ChunkEntry(); } else /* continuing, or seek */ { - if(!current.isValid() || !adaptationSet->isSegmentAligned() || initializing) + if(!adaptationSet->isSegmentAligned() || !pos.init_sent || !pos.index_sent) switch_allowed = false; if(switch_allowed) { Position temp; - temp.rep = logic->getNextRepresentation(adaptationSet, next.rep); - if(temp.rep && temp.rep != next.rep) + temp.rep = logic->getNextRepresentation(adaptationSet, pos.rep); + if(temp.rep && temp.rep != pos.rep) { /* Ensure ephemere content is updated/loaded */ - if(temp.rep->needsUpdate(next.number)) + if(temp.rep->needsUpdate(pos.number)) b_updated = temp.rep->runLocalUpdates(resources); /* if we need to translate pos */ if(!temp.rep->consistentSegmentNumber()) { /* Convert our segment number */ - temp.number = temp.rep->translateSegmentNumber(next.number, next.rep); + temp.number = temp.rep->translateSegmentNumber(pos.number, pos.rep); } - else temp.number = next.number; + else temp.number = pos.number; } if(temp.isValid()) - { - next = temp; - b_switched = current.isValid(); - } + pos = temp; } } - if(!next.isValid()) + ISegment *segment = nullptr; + + pos.rep->scheduleNextUpdate(pos.number, b_updated); + + if(!pos.init_sent) + { + segment = pos.rep->getInitSegment(); + if(!segment) + ++pos; + } + + if(!segment && !pos.index_sent) + { + if(pos.rep->needsIndex()) + segment = pos.rep->getIndexSegment(); + if(!segment) + ++pos; + } + + bool b_gap = true; + if(!segment) + segment = pos.rep->getNextMediaSegment(pos.number, &pos.number, &b_gap); + + if(!segment) + return ChunkEntry(); + + SegmentChunk *segmentChunk = segment->toChunk(resources, connManager, pos.number, pos.rep); + if(!segmentChunk) + return ChunkEntry(); + + const Timescale timescale = pos.rep->inheritTimescale(); + return ChunkEntry(segmentChunk, pos, timescale.ToTime(segment->duration.Get())); +} + +void SegmentTracker::resetChunksSequence() +{ + while(!chunkssequence.empty()) + { + delete chunkssequence.front().chunk; + chunkssequence.pop_front(); + } +} + +SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, + AbstractConnectionManager *connManager) +{ + if(!adaptationSet || !next.isValid()) + return nullptr; + + if(chunkssequence.empty()) + { + ChunkEntry chunk = prepareChunk(switch_allowed, next, connManager); + chunkssequence.push_back(chunk); + } + + ChunkEntry chunk = chunkssequence.front(); + if(!chunk.isValid()) + { + chunkssequence.pop_front(); + delete chunk.chunk; return nullptr; + } + + /* here next == wanted chunk pos */ + bool b_gap = (next.number != chunk.pos.number); + bool b_switched = (next.rep != chunk.pos.rep); if(b_switched) { - notify(RepresentationSwitchEvent(current.rep, next.rep)); + notify(RepresentationSwitchEvent(next.rep, chunk.pos.rep)); initializing = true; - assert(!next.index_sent); - assert(!next.init_sent); } - next.rep->scheduleNextUpdate(next.number, b_updated); - current = next; + /* advance or don't trigger duplicate events */ + next = current = chunk.pos; - if(current.rep->getStreamFormat() != format) + if(chunk.pos.rep->getStreamFormat() != format) { /* Initial format ? */ if(format == StreamFormat(StreamFormat::UNKNOWN)) { - format = current.rep->getStreamFormat(); + format = chunk.pos.rep->getStreamFormat(); } else { - format = current.rep->getStreamFormat(); + format = chunk.pos.rep->getStreamFormat(); notify(FormatChangedEvent(&format)); /* Notify new demux format */ return nullptr; /* Force current demux to end */ } @@ -307,34 +383,6 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, return nullptr; /* Can't return chunk because no demux will be created */ } - if(!current.init_sent) - { - ++next; - segment = current.rep->getInitSegment(); - if(segment) - return segment->toChunk(resources, connManager, current.number, current.rep); - current = next; - } - - if(!current.index_sent) - { - ++next; - if(current.rep->needsIndex()) - { - segment = current.rep->getIndexSegment(); - if(segment) - return segment->toChunk(resources, connManager, current.number, current.rep); - } - current = next; - } - - bool b_gap = false; - segment = current.rep->getNextMediaSegment(current.number, ¤t.number, &b_gap); - if(!segment) - return nullptr; - if(b_gap) - next = current; - if(initializing) { b_gap = false; @@ -342,33 +390,29 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, initializing = false; } - SegmentChunk *chunk = segment->toChunk(resources, connManager, next.number, next.rep); - /* Notify new segment length for stats / logic */ - if(chunk) - { - const Timescale timescale = next.rep->inheritTimescale(); - notify(SegmentChangedEvent(next.rep->getAdaptationSet()->getID(), - timescale.ToTime(segment->duration.Get()))); - } + if(chunk.pos.init_sent && chunk.pos.index_sent) + notify(SegmentChangedEvent(adaptationSet->getID(), chunk.duration)); /* We need to check segment/chunk format changes, as we can't rely on representation's (HLS)*/ - if(chunk && format != chunk->getStreamFormat()) + if(format != chunk.pos.rep->getStreamFormat()) { - format = chunk->getStreamFormat(); + format = chunk.pos.rep->getStreamFormat(); notify(FormatChangedEvent(&format)); } /* Handle both implicit and explicit discontinuities */ - if( (b_gap && next.number) || (chunk && chunk->discontinuity) ) - { + if(b_gap || chunk.chunk->discontinuity) notify(DiscontinuityEvent()); - } - if(chunk) + if(!b_gap) ++next; - return chunk; + /* pop position and return our chunk */ + chunkssequence.pop_front(); + SegmentChunk *segmentChunk = chunk.chunk; + chunk.chunk = nullptr; + return segmentChunk; } bool SegmentTracker::setPositionByTime(vlc_tick_t time, bool restarted, bool tryonly) @@ -404,10 +448,11 @@ void SegmentTracker::setPosition(const Position &pos, bool restarted) initializing = true; current = Position(); next = pos; + resetChunksSequence(); notify(PositionChangedEvent()); } -SegmentTracker::Position SegmentTracker::getStartPosition() +SegmentTracker::Position SegmentTracker::getStartPosition() const { Position pos; pos.rep = logic->getNextRepresentation(adaptationSet, nullptr); diff --git a/modules/demux/adaptive/SegmentTracker.hpp b/modules/demux/adaptive/SegmentTracker.hpp index 4dde71cdc6..05b05d4a05 100644 --- a/modules/demux/adaptive/SegmentTracker.hpp +++ b/modules/demux/adaptive/SegmentTracker.hpp @@ -188,7 +188,7 @@ namespace adaptive bool setPositionByTime(vlc_tick_t, bool, bool); void setPosition(const Position &, bool); bool setStartPosition(); - Position getStartPosition(); + Position getStartPosition() const; vlc_tick_t getPlaybackTime(bool = false) const; /* Current segment start time if selected */ bool getMediaPlaybackRange(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const; vlc_tick_t getMinAheadTime() const; @@ -199,6 +199,20 @@ namespace adaptive bool bufferingAvailable() const; private: + class ChunkEntry + { + public: + ChunkEntry(); + ChunkEntry(SegmentChunk *c, Position p, vlc_tick_t d); + bool isValid() const; + SegmentChunk *chunk; + Position pos; + vlc_tick_t duration; + }; + std::list<ChunkEntry> chunkssequence; + ChunkEntry prepareChunk(bool switch_allowed, Position pos, + AbstractConnectionManager *connManager) const; + void resetChunksSequence(); void setAdaptationLogic(AbstractAdaptationLogic *); void notify(const TrackerEvent &) const; bool first; _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits