[vlc-commits] demux: adaptive: split chunk computation & processing
Francois Cartegnie
git at videolan.org
Mon Mar 15 20:56:26 UTC 2021
vlc | branch: master | Francois Cartegnie <fcvlcdev at 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;
More information about the vlc-commits
mailing list