[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, &current.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