[vlc-commits] demux: adaptive: enable timeshift for live content

Francois Cartegnie git at videolan.org
Sun May 26 16:58:39 CEST 2019


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon May 20 18:45:54 2019 +0200| [a2de7e4fe782a5a27b32797efa4b5e5ad3bc3a81] | committer: Francois Cartegnie

demux: adaptive: enable timeshift for live content

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a2de7e4fe782a5a27b32797efa4b5e5ad3bc3a81
---

 modules/demux/adaptive/PlaylistManager.cpp         | 131 ++++++++++++++-------
 modules/demux/adaptive/PlaylistManager.h           |   5 +-
 modules/demux/adaptive/SegmentTracker.cpp          |  12 +-
 modules/demux/adaptive/SegmentTracker.hpp          |   1 +
 modules/demux/adaptive/Streams.cpp                 |   9 ++
 modules/demux/adaptive/Streams.hpp                 |   3 +-
 .../demux/adaptive/playlist/SegmentInformation.cpp |  86 +++++++++++++-
 .../demux/adaptive/playlist/SegmentInformation.hpp |   2 +
 .../demux/adaptive/playlist/SegmentTemplate.cpp    |   7 +-
 modules/demux/adaptive/playlist/SegmentTemplate.h  |   2 +-
 modules/demux/smooth/SmoothManager.cpp             |   2 -
 modules/demux/smooth/playlist/SmoothSegment.cpp    |  12 ++
 12 files changed, 212 insertions(+), 60 deletions(-)

diff --git a/modules/demux/adaptive/PlaylistManager.cpp b/modules/demux/adaptive/PlaylistManager.cpp
index 9b298ece52..9a67b7c8cb 100644
--- a/modules/demux/adaptive/PlaylistManager.cpp
+++ b/modules/demux/adaptive/PlaylistManager.cpp
@@ -77,6 +77,10 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_,
     cached.i_length = 0;
     cached.f_position = 0.0;
     cached.i_time = VLC_TICK_INVALID;
+    cached.rangeStart = 0;
+    cached.rangeEnd = 0;
+    cached.rangeLength = 0;
+    cached.lastupdate = 0;
 }
 
 PlaylistManager::~PlaylistManager   ()
@@ -399,13 +403,6 @@ vlc_tick_t PlaylistManager::getCurrentPlaybackTime() const
     return demux.i_nzpcr;
 }
 
-void PlaylistManager::pruneLiveStream()
-{
-    vlc_tick_t minValidPos = getResumeTime();
-    if(minValidPos != VLC_TICK_INVALID)
-        playlist->pruneByPlaybackTime(minValidPos);
-}
-
 bool PlaylistManager::reactivateStream(AbstractStream *stream)
 {
     return stream->reactivate(getResumeTime());
@@ -511,12 +508,6 @@ int PlaylistManager::doControl(int i_query, va_list args)
     switch (i_query)
     {
         case DEMUX_CAN_SEEK:
-        {
-            vlc_mutex_locker locker(&cached.lock);
-            *(va_arg (args, bool *)) = ! cached.b_live;
-            break;
-        }
-
         case DEMUX_CAN_CONTROL_PACE:
             *(va_arg (args, bool *)) = true;
             break;
@@ -546,7 +537,7 @@ int PlaylistManager::doControl(int i_query, va_list args)
         case DEMUX_GET_LENGTH:
         {
             vlc_mutex_locker locker(&cached.lock);
-            if(cached.b_live)
+            if(cached.b_live && cached.i_length == 0)
                 return VLC_EGENERIC;
             *(va_arg (args, vlc_tick_t *)) = cached.i_length;
             break;
@@ -555,7 +546,7 @@ int PlaylistManager::doControl(int i_query, va_list args)
         case DEMUX_GET_POSITION:
         {
             vlc_mutex_locker locker(&cached.lock);
-            if(cached.b_live)
+            if(cached.b_live && cached.i_length == 0)
                 return VLC_EGENERIC;
             *(va_arg (args, double *)) = cached.f_position;
             break;
@@ -564,18 +555,31 @@ int PlaylistManager::doControl(int i_query, va_list args)
         case DEMUX_SET_POSITION:
         {
             setBufferingRunState(false); /* stop downloader first */
+            vlc_mutex_locker locker(&cached.lock);
 
-            const vlc_tick_t i_duration = playlist->duration.Get();
-            if(i_duration == 0 || playlist->isLive())
+            vlc_tick_t i_start, i_duration;
+            if(cached.b_live)
+            {
+                i_duration = cached.i_length;
+                if(cached.rangeStart < 0)
+                    i_start = vlc_tick_from_sec(time(NULL)) - cached.i_length;
+                else
+                    i_start = cached.rangeStart;
+            }
+            else
+            {
+                i_duration = playlist->duration.Get();
+                i_start = getFirstPlaybackTime();
+            }
+
+            if(i_duration == 0)
             {
                 setBufferingRunState(true);
                 return VLC_EGENERIC;
             }
 
-            int64_t time = i_duration * va_arg(args, double);
-            time += getFirstPlaybackTime();
-
-            if(!setPosition(time))
+            vlc_tick_t seektime = i_start + i_duration * va_arg(args, double);
+            if(!setPosition(seektime))
             {
                 setBufferingRunState(true);
                 return VLC_EGENERIC;
@@ -589,11 +593,6 @@ int PlaylistManager::doControl(int i_query, va_list args)
         case DEMUX_SET_TIME:
         {
             setBufferingRunState(false); /* stop downloader first */
-            if(playlist->isLive())
-            {
-                setBufferingRunState(true);
-                return VLC_EGENERIC;
-            }
 
             vlc_tick_t time = va_arg(args, vlc_tick_t);// + getFirstPlaybackTime();
             if(!setPosition(time))
@@ -602,6 +601,7 @@ int PlaylistManager::doControl(int i_query, va_list args)
                 return VLC_EGENERIC;
             }
 
+            vlc_mutex_locker locker(&cached.lock);
             demux.i_nzpcr = VLC_TICK_INVALID;
             setBufferingRunState(true);
             break;
@@ -691,31 +691,72 @@ void * PlaylistManager::managerThread(void *opaque)
 void PlaylistManager::updateControlsPosition()
 {
     vlc_mutex_locker locker(&cached.lock);
-    if(playlist->isLive())
-    {
-        cached.b_live = true;
-        cached.i_length = 0;
-    }
-    else
-    {
-        cached.b_live = false;
-        cached.i_length = playlist->duration.Get();
-    }
 
-    if(cached.i_length == 0)
+    time_t now = time(NULL);
+    if(now - cached.lastupdate < 1)
+        return;
+    cached.lastupdate = now;
+
+    cached.i_time = getCurrentPlaybackTime();
+    cached.b_live = playlist->isLive();
+    if(cached.b_live)
     {
-        cached.f_position = 0.0;
+        std::vector<AbstractStream *>::iterator it;
+        for(it=streams.begin(); it!=streams.end(); ++it)
+        {
+            AbstractStream *st = *it;
+            if(st->isValid() && !st->isDisabled() && st->isSelected())
+            {
+                if(st->getMediaPlaybackRange(&cached.rangeStart, &cached.rangeEnd,
+                                             &cached.rangeLength))
+                    break;
+            }
+        }
+
+        if(cached.rangeStart != cached.rangeEnd)
+        {
+            if(cached.rangeStart < 0) /* Live template. Range start = now() - buffering depth */
+                cached.i_length = cached.rangeLength;
+            else
+                cached.i_length = cached.rangeEnd - cached.rangeStart;
+        }
+
+        vlc_tick_t start, end;
+        if(cached.rangeStart < 0) /* Live template. Range start = now() - buffering depth */
+        {
+            end = vlc_tick_from_sec(now);
+            start = end - cached.i_length;
+        }
+        else
+        {
+            end = cached.rangeEnd;
+            start = cached.rangeStart;
+        }
+
+        const vlc_tick_t currentTime = getCurrentPlaybackTime();
+        if(currentTime > start && currentTime <= end && cached.i_length)
+        {
+            cached.f_position = ((double)(currentTime - start)) / cached.i_length;
+        }
+        else
+        {
+            cached.f_position = 0.0;
+        }
     }
     else
     {
-        const vlc_tick_t i_length = getCurrentPlaybackTime() - getFirstPlaybackTime();
-        cached.f_position = (double) i_length / cached.i_length;
+        cached.i_length = playlist->duration.Get();
+        cached.i_time -= getFirstPlaybackTime();
+        if(cached.i_length)
+        {
+            const vlc_tick_t i_length = getCurrentPlaybackTime() - getFirstPlaybackTime();
+            cached.f_position = (double) i_length / cached.i_length;
+        }
+        else
+        {
+            cached.f_position = 0.0;
+        }
     }
-
-    vlc_tick_t i_time = getCurrentPlaybackTime();
-    if(!playlist->isLive())
-        i_time -= getFirstPlaybackTime();
-    cached.i_time = i_time;
 }
 
 AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn)
diff --git a/modules/demux/adaptive/PlaylistManager.h b/modules/demux/adaptive/PlaylistManager.h
index 6d363f9ca9..03f799ac1d 100644
--- a/modules/demux/adaptive/PlaylistManager.h
+++ b/modules/demux/adaptive/PlaylistManager.h
@@ -81,7 +81,6 @@ namespace adaptive
             virtual vlc_tick_t getFirstPlaybackTime() const;
             vlc_tick_t getCurrentPlaybackTime() const;
 
-            void pruneLiveStream();
             virtual bool reactivateStream(AbstractStream *);
             bool setupPeriod();
             void unsetPeriod();
@@ -123,6 +122,10 @@ namespace adaptive
                 vlc_tick_t  i_time;
                 double      f_position;
                 mutable vlc_mutex_t lock;
+                vlc_tick_t  rangeStart;
+                vlc_tick_t  rangeEnd;
+                vlc_tick_t  rangeLength;
+                time_t      lastupdate;
             } cached;
 
         private:
diff --git a/modules/demux/adaptive/SegmentTracker.cpp b/modules/demux/adaptive/SegmentTracker.cpp
index d9d06296d8..583d977681 100644
--- a/modules/demux/adaptive/SegmentTracker.cpp
+++ b/modules/demux/adaptive/SegmentTracker.cpp
@@ -217,11 +217,7 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed,
     }
 
     if(b_updated)
-    {
-        if(!rep->consistentSegmentNumber())
-            curRepresentation->pruneBySegmentNumber(curNumber);
         curRepresentation->scheduleNextUpdate(next);
-    }
 
     if(rep->getStreamFormat() != format)
     {
@@ -358,6 +354,14 @@ vlc_tick_t SegmentTracker::getPlaybackTime() const
     return 0;
 }
 
+bool SegmentTracker::getMediaPlaybackRange(vlc_tick_t *start, vlc_tick_t *end,
+                                           vlc_tick_t *length) const
+{
+    if(!curRepresentation)
+        return false;
+    return curRepresentation->getMediaPlaybackRange(start, end, length);
+}
+
 vlc_tick_t SegmentTracker::getMinAheadTime() const
 {
     BaseRepresentation *rep = curRepresentation;
diff --git a/modules/demux/adaptive/SegmentTracker.hpp b/modules/demux/adaptive/SegmentTracker.hpp
index a7a837ce12..cb035d6200 100644
--- a/modules/demux/adaptive/SegmentTracker.hpp
+++ b/modules/demux/adaptive/SegmentTracker.hpp
@@ -129,6 +129,7 @@ namespace adaptive
             bool setPositionByTime(vlc_tick_t, bool, bool);
             void setPositionByNumber(uint64_t, bool);
             vlc_tick_t getPlaybackTime() const; /* Current segment start time if selected */
+            bool getMediaPlaybackRange(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const;
             vlc_tick_t getMinAheadTime() const;
             void notifyBufferingState(bool) const;
             void notifyBufferingLevel(vlc_tick_t, vlc_tick_t, vlc_tick_t) const;
diff --git a/modules/demux/adaptive/Streams.cpp b/modules/demux/adaptive/Streams.cpp
index 26710e3338..1ad8815d56 100644
--- a/modules/demux/adaptive/Streams.cpp
+++ b/modules/demux/adaptive/Streams.cpp
@@ -213,6 +213,7 @@ bool AbstractStream::isSelected() const
 
 bool AbstractStream::reactivate(vlc_tick_t basetime)
 {
+    vlc_mutex_locker locker(&lock);
     if(setPosition(basetime, false))
     {
         setDisabled(false);
@@ -275,11 +276,13 @@ void AbstractStream::setDisabled(bool b)
 
 bool AbstractStream::isValid() const
 {
+    vlc_mutex_locker locker(&lock);
     return valid;
 }
 
 bool AbstractStream::isDisabled() const
 {
+    vlc_mutex_locker locker(&lock);
     return disabled;
 }
 
@@ -559,6 +562,12 @@ vlc_tick_t AbstractStream::getPlaybackTime() const
     return segmentTracker->getPlaybackTime();
 }
 
+bool AbstractStream::getMediaPlaybackRange(vlc_tick_t *start, vlc_tick_t *end,
+                                           vlc_tick_t *length) const
+{
+    return segmentTracker->getMediaPlaybackRange(start, end, length);
+}
+
 void AbstractStream::runUpdates()
 {
     if(valid && !disabled)
diff --git a/modules/demux/adaptive/Streams.hpp b/modules/demux/adaptive/Streams.hpp
index 919a65dfc9..3b3d88d61b 100644
--- a/modules/demux/adaptive/Streams.hpp
+++ b/modules/demux/adaptive/Streams.hpp
@@ -67,7 +67,6 @@ namespace adaptive
         int esCount() const;
         bool isSelected() const;
         virtual bool reactivate(vlc_tick_t);
-        void setDisabled(bool);
         bool isDisabled() const;
         bool isValid() const;
         typedef enum {
@@ -90,6 +89,7 @@ namespace adaptive
         bool decodersDrained();
         virtual bool setPosition(vlc_tick_t, bool);
         vlc_tick_t getPlaybackTime() const;
+        bool getMediaPlaybackRange(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const;
         void runUpdates();
 
         /* Used by demuxers fake streams */
@@ -102,6 +102,7 @@ namespace adaptive
 
     protected:
         bool seekAble() const;
+        void setDisabled(bool);
         virtual void setTimeOffset(vlc_tick_t);
         virtual block_t *checkBlock(block_t *, bool) = 0;
         AbstractDemuxer * createDemux(const StreamFormat &);
diff --git a/modules/demux/adaptive/playlist/SegmentInformation.cpp b/modules/demux/adaptive/playlist/SegmentInformation.cpp
index 6b10af1bb5..7fe3d07296 100644
--- a/modules/demux/adaptive/playlist/SegmentInformation.cpp
+++ b/modules/demux/adaptive/playlist/SegmentInformation.cpp
@@ -162,6 +162,22 @@ std::size_t SegmentInformation::getAllSegments(std::vector<ISegment *> &retSegme
     return retSegments.size();
 }
 
+uint64_t SegmentInformation::getLiveSegmentNumberByTime(uint64_t def, vlc_tick_t t) const
+{
+    if( mediaSegmentTemplate )
+    {
+        if( mediaSegmentTemplate->duration.Get() )
+        {
+            return mediaSegmentTemplate->getLiveTemplateNumber(t);
+        }
+    }
+
+    if(parent)
+        return parent->getLiveStartSegmentNumber(def);
+    else
+        return def;
+}
+
 uint64_t SegmentInformation::getLiveStartSegmentNumber(uint64_t def) const
 {
     const vlc_tick_t i_max_buffering = getPlaylist()->getMaxBuffering() +
@@ -213,7 +229,7 @@ uint64_t SegmentInformation::getLiveStartSegmentNumber(uint64_t def) const
                 i_delay = getPlaylist()->getMinBuffering();
 
             const uint64_t startnumber = mediaSegmentTemplate->inheritStartNumber();
-            end = mediaSegmentTemplate->getCurrentLiveTemplateNumber();
+            end = mediaSegmentTemplate->getLiveTemplateNumber(vlc_tick_from_sec(time(NULL)));
 
             const uint64_t count = timescale.ToScaled( i_delay ) / mediaSegmentTemplate->duration.Get();
             if( startnumber + count >= end )
@@ -271,6 +287,72 @@ uint64_t SegmentInformation::getLiveStartSegmentNumber(uint64_t def) const
         return def;
 }
 
+bool SegmentInformation::getMediaPlaybackRange(vlc_tick_t *rangeBegin,
+                                               vlc_tick_t *rangeEnd,
+                                               vlc_tick_t *rangeLength) const
+{
+    if( mediaSegmentTemplate )
+    {
+        const Timescale timescale = mediaSegmentTemplate->inheritTimescale();
+        const SegmentTimeline *timeline = mediaSegmentTemplate->inheritSegmentTimeline();
+        if( timeline )
+        {
+            stime_t startTime, endTime, duration;
+            if(!timeline->getScaledPlaybackTimeDurationBySegmentNumber(timeline->minElementNumber(),
+                                                                       &startTime, &duration) ||
+               !timeline->getScaledPlaybackTimeDurationBySegmentNumber(timeline->maxElementNumber(),
+                                                                       &endTime, &duration))
+                return false;
+
+            *rangeBegin = timescale.ToTime(startTime);
+            *rangeEnd = timescale.ToTime(endTime+duration);
+            *rangeLength = timescale.ToTime(timeline->getTotalLength());
+            return true;
+        }
+        /* Else compute, current time and timeshiftdepth based */
+        else if( mediaSegmentTemplate->duration.Get() )
+        {
+            *rangeEnd = 0;
+            *rangeBegin = -1 * getPlaylist()->timeShiftBufferDepth.Get();
+            *rangeLength = getPlaylist()->timeShiftBufferDepth.Get();
+            return true;
+        }
+    }
+    else if ( segmentList && !segmentList->getSegments().empty() )
+    {
+        const Timescale timescale = segmentList->inheritTimescale();
+        const std::vector<ISegment *> list = segmentList->getSegments();
+
+        const ISegment *back = list.back();
+        const stime_t startTime = list.front()->startTime.Get();
+        const stime_t endTime = back->startTime.Get() + back->duration.Get();
+        *rangeBegin = timescale.ToTime(startTime);
+        *rangeEnd = timescale.ToTime(endTime);
+        *rangeLength = timescale.ToTime(segmentList->getTotalLength());
+        return true;
+    }
+    else if( segmentBase )
+    {
+        const std::vector<ISegment *> list = segmentBase->subSegments();
+        if(list.empty())
+            return false;
+
+        const Timescale timescale = inheritTimescale();
+        const ISegment *back = list.back();
+        const stime_t startTime = list.front()->startTime.Get();
+        const stime_t endTime = back->startTime.Get() + back->duration.Get();
+        *rangeBegin = timescale.ToTime(startTime);
+        *rangeEnd = timescale.ToTime(endTime);
+        *rangeLength = 0;
+        return true;
+    }
+
+    if(parent)
+        return parent->getMediaPlaybackRange(rangeBegin, rangeEnd, rangeLength);
+    else
+        return false;
+}
+
 /* Returns wanted segment, or next in sequence if not found */
 ISegment * SegmentInformation::getNextSegment(SegmentInfoType type, uint64_t i_pos,
                                               uint64_t *pi_newpos, bool *pb_gap) const
@@ -372,7 +454,7 @@ bool SegmentInformation::getSegmentNumberByTime(vlc_tick_t time, uint64_t *ret)
         {
             if( getPlaylist()->isLive() )
             {
-                *ret = getLiveStartSegmentNumber( mediaSegmentTemplate->inheritStartNumber() );
+                *ret = getLiveSegmentNumberByTime( mediaSegmentTemplate->inheritStartNumber(), time );
             }
             else
             {
diff --git a/modules/demux/adaptive/playlist/SegmentInformation.hpp b/modules/demux/adaptive/playlist/SegmentInformation.hpp
index 7970ce0e83..1be759ea43 100644
--- a/modules/demux/adaptive/playlist/SegmentInformation.hpp
+++ b/modules/demux/adaptive/playlist/SegmentInformation.hpp
@@ -82,7 +82,9 @@ namespace adaptive
                 ISegment * getNextSegment(SegmentInfoType, uint64_t, uint64_t *, bool *) const;
                 bool getSegmentNumberByTime(vlc_tick_t, uint64_t *) const;
                 bool getPlaybackTimeDurationBySegmentNumber(uint64_t, vlc_tick_t *, vlc_tick_t *) const;
+                uint64_t getLiveSegmentNumberByTime(uint64_t, vlc_tick_t) const;
                 uint64_t getLiveStartSegmentNumber(uint64_t) const;
+                bool     getMediaPlaybackRange(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const;
                 virtual void mergeWith(SegmentInformation *, vlc_tick_t);
                 virtual void mergeWithTimeline(SegmentTimeline *); /* ! don't use with global merge */
                 virtual void pruneBySegmentNumber(uint64_t);
diff --git a/modules/demux/adaptive/playlist/SegmentTemplate.cpp b/modules/demux/adaptive/playlist/SegmentTemplate.cpp
index c33151bc8c..cd45094810 100644
--- a/modules/demux/adaptive/playlist/SegmentTemplate.cpp
+++ b/modules/demux/adaptive/playlist/SegmentTemplate.cpp
@@ -148,7 +148,7 @@ SegmentTimeline * MediaSegmentTemplate::inheritSegmentTimeline() const
     return NULL;
 }
 
-uint64_t MediaSegmentTemplate::getCurrentLiveTemplateNumber() const
+uint64_t MediaSegmentTemplate::getLiveTemplateNumber(vlc_tick_t playbacktime) const
 {
     uint64_t number = inheritStartNumber();
     /* live streams / templated */
@@ -156,11 +156,10 @@ uint64_t MediaSegmentTemplate::getCurrentLiveTemplateNumber() const
     if(dur)
     {
         /* compute, based on current time */
-        const time_t playbacktime = time(NULL);
         const Timescale timescale = inheritTimescale();
         time_t streamstart = parentSegmentInformation->getPlaylist()->availabilityStartTime.Get();
         streamstart += parentSegmentInformation->getPeriodStart();
-        stime_t elapsed = timescale.ToScaled(vlc_tick_from_sec(playbacktime - streamstart));
+        stime_t elapsed = timescale.ToScaled(playbacktime - vlc_tick_from_sec(streamstart));
         number += elapsed / dur;
     }
 
@@ -172,7 +171,7 @@ stime_t MediaSegmentTemplate::getMinAheadScaledTime(uint64_t number) const
     if( segmentTimeline )
         return segmentTimeline->getMinAheadScaledTime(number);
 
-    uint64_t current = getCurrentLiveTemplateNumber();
+    uint64_t current = getLiveTemplateNumber(vlc_tick_from_sec(time(NULL)));
     return (current - number) * inheritDuration();
 }
 
diff --git a/modules/demux/adaptive/playlist/SegmentTemplate.h b/modules/demux/adaptive/playlist/SegmentTemplate.h
index 6fb669a179..74d5532363 100644
--- a/modules/demux/adaptive/playlist/SegmentTemplate.h
+++ b/modules/demux/adaptive/playlist/SegmentTemplate.h
@@ -55,7 +55,7 @@ namespace adaptive
                 void setSegmentTimeline( SegmentTimeline * );
                 void mergeWith( MediaSegmentTemplate *, vlc_tick_t );
                 virtual uint64_t getSequenceNumber() const; /* reimpl */
-                uint64_t getCurrentLiveTemplateNumber() const;
+                uint64_t getLiveTemplateNumber(vlc_tick_t) const;
                 stime_t getMinAheadScaledTime(uint64_t) const;
                 void pruneByPlaybackTime(vlc_tick_t);
                 size_t pruneBySequenceNumber(uint64_t);
diff --git a/modules/demux/smooth/SmoothManager.cpp b/modules/demux/smooth/SmoothManager.cpp
index 7a3f243300..e5e0f0c84b 100644
--- a/modules/demux/smooth/SmoothManager.cpp
+++ b/modules/demux/smooth/SmoothManager.cpp
@@ -174,8 +174,6 @@ bool SmoothManager::updatePlaylist(bool forcemanifest)
         else return false;
     }
 
-    pruneLiveStream();
-
     return true;
 }
 
diff --git a/modules/demux/smooth/playlist/SmoothSegment.cpp b/modules/demux/smooth/playlist/SmoothSegment.cpp
index 24d0665199..0b317e1b43 100644
--- a/modules/demux/smooth/playlist/SmoothSegment.cpp
+++ b/modules/demux/smooth/playlist/SmoothSegment.cpp
@@ -50,6 +50,18 @@ void SmoothSegmentChunk::onDownload(block_t **pp_block)
 
     IndexReader br(rep->getPlaylist()->getVLCObject());
     br.parseIndex(*pp_block, rep);
+
+    /* If timeshift depth is present, we use it for expiring segments
+       as we never update playlist itself */
+    if(rep->getPlaylist()->timeShiftBufferDepth.Get())
+    {
+        vlc_tick_t start, end, length;
+        if(rep->getMediaPlaybackRange(&start, &end, &length))
+        {
+            start = std::max(start, end - rep->getPlaylist()->timeShiftBufferDepth.Get());
+            rep->pruneByPlaybackTime(start);
+        }
+    }
 }
 
 SmoothSegment::SmoothSegment(SegmentInformation *parent) :



More information about the vlc-commits mailing list