vlc | branch: master | Francois Cartegnie <[email protected]> | 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) : _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
