Browse Source

demux: adaptive: use new buffering logic

pull/104/head
Francois Cartegnie 6 years ago
parent
commit
f8f3f11fae
  1. 18
      modules/demux/adaptive/PlaylistManager.cpp
  2. 2
      modules/demux/adaptive/PlaylistManager.h
  3. 25
      modules/demux/adaptive/SegmentTracker.cpp
  4. 7
      modules/demux/adaptive/SegmentTracker.hpp
  5. 7
      modules/demux/adaptive/Streams.cpp
  6. 127
      modules/demux/adaptive/playlist/SegmentInformation.cpp
  7. 2
      modules/demux/adaptive/playlist/SegmentInformation.hpp
  8. 10
      modules/demux/adaptive/playlist/SegmentTemplate.cpp
  9. 2
      modules/demux/adaptive/playlist/SegmentTemplate.h
  10. 4
      modules/demux/hls/playlist/Parser.cpp

18
modules/demux/adaptive/PlaylistManager.cpp

@ -36,6 +36,7 @@
#include "logic/AlwaysLowestAdaptationLogic.hpp"
#include "logic/PredictiveAdaptationLogic.hpp"
#include "logic/NearOptimalAdaptationLogic.hpp"
#include "logic/BufferingLogic.hpp"
#include "tools/Debug.hpp"
#include <vlc_stream.h>
#include <vlc_demux.h>
@ -61,6 +62,7 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_,
{
currentPeriod = playlist->getFirstPeriod();
resources = res;
bufferingLogic = NULL;
failedupdates = 0;
b_thread = false;
b_buffering = false;
@ -89,6 +91,7 @@ PlaylistManager::~PlaylistManager ()
delete playlist;
delete logic;
delete resources;
delete bufferingLogic;
}
void PlaylistManager::unsetPeriod()
@ -107,6 +110,9 @@ bool PlaylistManager::setupPeriod()
if(!logic && !(logic = createLogic(logicType, resources->getConnManager())))
return false;
if(!bufferingLogic && !(bufferingLogic = createBufferingLogic()))
return false;
std::vector<BaseAdaptationSet*> sets = currentPeriod->getAdaptationSets();
std::vector<BaseAdaptationSet*>::iterator it;
for(it=sets.begin();it!=sets.end();++it)
@ -114,7 +120,8 @@ bool PlaylistManager::setupPeriod()
BaseAdaptationSet *set = *it;
if(set && streamFactory)
{
SegmentTracker *tracker = new SegmentTracker(resources, logic, set);
SegmentTracker *tracker = new SegmentTracker(resources, logic,
bufferingLogic, set);
if(!tracker)
continue;
@ -610,8 +617,8 @@ void PlaylistManager::setBufferingRunState(bool b)
void PlaylistManager::Run()
{
vlc_mutex_lock(&lock);
const vlc_tick_t i_min_buffering = playlist->getMinBuffering();
const vlc_tick_t i_extra_buffering = playlist->getMaxBuffering() - i_min_buffering;
const vlc_tick_t i_min_buffering = bufferingLogic->getMinBuffering(playlist);
const vlc_tick_t i_extra_buffering = bufferingLogic->getMaxBuffering(playlist) - i_min_buffering;
while(1)
{
while(!b_buffering && !b_canceled)
@ -823,3 +830,8 @@ AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::L
return logic;
}
AbstractBufferingLogic *PlaylistManager::createBufferingLogic() const
{
return new DefaultBufferingLogic();
}

2
modules/demux/adaptive/PlaylistManager.h

@ -90,10 +90,12 @@ namespace adaptive
/* local factories */
virtual AbstractAdaptationLogic *createLogic(AbstractAdaptationLogic::LogicType,
AbstractConnectionManager *);
virtual AbstractBufferingLogic *createBufferingLogic() const;
SharedResources *resources;
AbstractAdaptationLogic::LogicType logicType;
AbstractAdaptationLogic *logic;
AbstractBufferingLogic *bufferingLogic;
AbstractPlaylist *playlist;
AbstractStreamFactory *streamFactory;
demux_t *p_demux;

25
modules/demux/adaptive/SegmentTracker.cpp

@ -29,6 +29,7 @@
#include "playlist/Segment.h"
#include "playlist/SegmentChunk.hpp"
#include "logic/AbstractAdaptationLogic.h"
#include "logic/BufferingLogic.hpp"
#include <cassert>
#include <limits>
@ -80,7 +81,9 @@ SegmentTrackerEvent::SegmentTrackerEvent(const ID &id, vlc_tick_t duration)
}
SegmentTracker::SegmentTracker(SharedResources *res,
AbstractAdaptationLogic *logic_, BaseAdaptationSet *adaptSet)
AbstractAdaptationLogic *logic_,
const AbstractBufferingLogic *bl,
BaseAdaptationSet *adaptSet)
{
resources = res;
first = true;
@ -89,6 +92,7 @@ SegmentTracker::SegmentTracker(SharedResources *res,
index_sent = false;
init_sent = false;
curRepresentation = NULL;
bufferingLogic = bl;
setAdaptationLogic(logic_);
adaptationSet = adaptSet;
format = StreamFormat::UNKNOWN;
@ -213,7 +217,7 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed,
if(curNumber == std::numeric_limits<uint64_t>::max())
{
next = rep->getLiveStartSegmentNumber(next);
next = bufferingLogic->getStartSegmentNumber(rep);
if(next == std::numeric_limits<uint64_t>::max())
return NULL;
}
@ -381,7 +385,15 @@ vlc_tick_t SegmentTracker::getMinAheadTime() const
if(!rep)
rep = logic->getNextRepresentation(adaptationSet, NULL);
if(rep)
return rep->getMinAheadTime(curNumber);
{
/* Ensure ephemere content is updated/loaded */
if(rep->needsUpdate())
(void) rep->runLocalUpdates(resources);
uint64_t startnumber = bufferingLogic->getStartSegmentNumber(rep);
assert(startnumber != std::numeric_limits<uint64_t>::max());
return rep->getMinAheadTime(startnumber);
}
return 0;
}
@ -400,6 +412,13 @@ void SegmentTracker::registerListener(SegmentTrackerListenerInterface *listener)
listeners.push_back(listener);
}
bool SegmentTracker::bufferingAvailable() const
{
if(adaptationSet->getPlaylist()->isLive())
return bufferingLogic->getMinBuffering(adaptationSet->getPlaylist()) <= getMinAheadTime();
return true;
}
void SegmentTracker::updateSelected()
{
if(curRepresentation && curRepresentation->needsUpdate())

7
modules/demux/adaptive/SegmentTracker.hpp

@ -39,6 +39,7 @@ namespace adaptive
namespace logic
{
class AbstractAdaptationLogic;
class AbstractBufferingLogic;
}
namespace playlist
@ -116,7 +117,9 @@ namespace adaptive
{
public:
SegmentTracker(SharedResources *,
AbstractAdaptationLogic *, BaseAdaptationSet *);
AbstractAdaptationLogic *,
const AbstractBufferingLogic *,
BaseAdaptationSet *);
~SegmentTracker();
StreamFormat getCurrentFormat() const;
@ -136,6 +139,7 @@ namespace adaptive
void notifyBufferingLevel(vlc_tick_t, vlc_tick_t, vlc_tick_t) const;
void registerListener(SegmentTrackerListenerInterface *);
void updateSelected();
bool bufferingAvailable() const;
private:
void setAdaptationLogic(AbstractAdaptationLogic *);
@ -149,6 +153,7 @@ namespace adaptive
StreamFormat format;
SharedResources *resources;
AbstractAdaptationLogic *logic;
const AbstractBufferingLogic *bufferingLogic;
BaseAdaptationSet *adaptationSet;
BaseRepresentation *curRepresentation;
std::list<SegmentTrackerListenerInterface *> listeners;

7
modules/demux/adaptive/Streams.cpp

@ -338,6 +338,13 @@ AbstractStream::buffering_status AbstractStream::doBufferize(vlc_tick_t nz_deadl
return AbstractStream::buffering_suspended;
}
/* Reached end of live playlist */
if(!segmentTracker->bufferingAvailable())
{
vlc_mutex_unlock(&lock);
return AbstractStream::buffering_suspended;
}
if(!demuxer)
{
format = segmentTracker->getCurrentFormat();

127
modules/demux/adaptive/playlist/SegmentInformation.cpp

@ -162,131 +162,6 @@ 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() +
/* FIXME: add dynamic pts-delay */ VLC_TICK_FROM_SEC(1);
/* Try to never buffer up to really end */
const uint64_t OFFSET_FROM_END = 3;
if( mediaSegmentTemplate )
{
uint64_t start = 0;
uint64_t end = 0;
const Timescale timescale = mediaSegmentTemplate->inheritTimescale();
const SegmentTimeline *timeline = mediaSegmentTemplate->inheritSegmentTimeline();
if( timeline )
{
start = timeline->minElementNumber();
end = timeline->maxElementNumber();
/* Try to never buffer up to really end */
end = end - std::min(end - start, OFFSET_FROM_END);
stime_t endtime, duration;
bool b_ret = timeline->getScaledPlaybackTimeDurationBySegmentNumber( end, &endtime, &duration );
if(unlikely(!b_ret)) /* should never happen */
{
assert(b_ret);
return 0;
}
vlc_tick_t fromend = std::max( i_max_buffering, getPlaylist()->suggestedPresentationDelay.Get() );
if( endtime + duration <= timescale.ToScaled( fromend ) )
return start;
uint64_t number = timeline->getElementNumberByScaledPlaybackTime(endtime - timescale.ToScaled( fromend ));
if( number < start )
number = start;
return number;
}
/* Else compute, current time and timeshiftdepth based */
else if( mediaSegmentTemplate->duration.Get() )
{
vlc_tick_t i_delay = getPlaylist()->suggestedPresentationDelay.Get();
if( i_delay == 0 || i_delay > getPlaylist()->timeShiftBufferDepth.Get() )
i_delay = getPlaylist()->timeShiftBufferDepth.Get();
if( i_delay < getPlaylist()->getMinBuffering() )
i_delay = getPlaylist()->getMinBuffering();
const uint64_t startnumber = mediaSegmentTemplate->inheritStartNumber();
end = mediaSegmentTemplate->getLiveTemplateNumber(vlc_tick_from_sec(time(NULL)));
const uint64_t count = timescale.ToScaled( i_delay ) / mediaSegmentTemplate->duration.Get();
if( startnumber + count >= end )
start = startnumber;
else
start = end - count;
uint64_t bufcount = ( OFFSET_FROM_END + timescale.ToScaled(i_max_buffering) /
mediaSegmentTemplate->duration.Get() );
/* Ensure we always pick > start # of availability window as this segment might no longer be avail */
if( end - start <= bufcount )
bufcount = end - start - 1;
return ( end - start > bufcount ) ? end - bufcount : start;
}
}
else if ( segmentList && !segmentList->getSegments().empty() )
{
const Timescale timescale = segmentList->inheritTimescale();
const std::vector<ISegment *> list = segmentList->getSegments();
const ISegment *back = list.back();
vlc_tick_t fromend = std::max( i_max_buffering, getPlaylist()->suggestedPresentationDelay.Get() );
stime_t bufferingstart = back->startTime.Get() + back->duration.Get() - timescale.ToScaled( fromend );
uint64_t number;
if( !segmentList->getSegmentNumberByScaledTime( bufferingstart, &number ) )
return list.front()->getSequenceNumber();
if( number > list.front()->getSequenceNumber() + OFFSET_FROM_END )
number -= OFFSET_FROM_END;
else
number = list.front()->getSequenceNumber();
return number;
}
else if( segmentBase )
{
const std::vector<ISegment *> list = segmentBase->subSegments();
if(!list.empty())
return segmentBase->getSequenceNumber();
const Timescale timescale = inheritTimescale();
const ISegment *back = list.back();
vlc_tick_t fromend = std::max( i_max_buffering, getPlaylist()->suggestedPresentationDelay.Get() );
const stime_t bufferingstart = back->startTime.Get() -
(OFFSET_FROM_END * back->duration.Get())- timescale.ToScaled( fromend );
uint64_t number;
if( !SegmentInfoCommon::getSegmentNumberByScaledTime( list, bufferingstart, &number ) )
return list.front()->getSequenceNumber();
return number;
}
if(parent)
return parent->getLiveStartSegmentNumber(def);
else
return def;
}
bool SegmentInformation::getMediaPlaybackRange(vlc_tick_t *rangeBegin,
vlc_tick_t *rangeEnd,
vlc_tick_t *rangeLength) const
@ -454,7 +329,7 @@ bool SegmentInformation::getSegmentNumberByTime(vlc_tick_t time, uint64_t *ret)
{
if( getPlaylist()->isLive() )
{
*ret = getLiveSegmentNumberByTime( mediaSegmentTemplate->inheritStartNumber(), time );
*ret = mediaSegmentTemplate->getLiveTemplateNumber(time, false);
}
else
{

2
modules/demux/adaptive/playlist/SegmentInformation.hpp

@ -75,8 +75,6 @@ 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 updateWith(SegmentInformation *);
virtual void mergeWithTimeline(SegmentTimeline *); /* ! don't use with global merge */

10
modules/demux/adaptive/playlist/SegmentTemplate.cpp

@ -148,7 +148,7 @@ SegmentTimeline * MediaSegmentTemplate::inheritSegmentTimeline() const
return NULL;
}
uint64_t MediaSegmentTemplate::getLiveTemplateNumber(vlc_tick_t playbacktime) const
uint64_t MediaSegmentTemplate::getLiveTemplateNumber(vlc_tick_t playbacktime, bool abs) const
{
uint64_t number = inheritStartNumber();
/* live streams / templated */
@ -156,11 +156,17 @@ uint64_t MediaSegmentTemplate::getLiveTemplateNumber(vlc_tick_t playbacktime) co
if(dur)
{
/* compute, based on current time */
/* N = (T - AST - PS - D)/D + sSN */
const Timescale timescale = inheritTimescale();
if(abs)
{
vlc_tick_t streamstart =
vlc_tick_from_sec(parentSegmentInformation->getPlaylist()->availabilityStartTime.Get());
streamstart += parentSegmentInformation->getPeriodStart();
stime_t elapsed = timescale.ToScaled(playbacktime - streamstart);
playbacktime -= streamstart;
}
stime_t elapsed = timescale.ToScaled(playbacktime) - dur;
if(elapsed > 0)
number += elapsed / dur;
}

2
modules/demux/adaptive/playlist/SegmentTemplate.h

@ -55,7 +55,7 @@ namespace adaptive
void setSegmentTimeline( SegmentTimeline * );
void updateWith( MediaSegmentTemplate * );
virtual uint64_t getSequenceNumber() const; /* reimpl */
uint64_t getLiveTemplateNumber(vlc_tick_t) const;
uint64_t getLiveTemplateNumber(vlc_tick_t, bool = true) const;
stime_t getMinAheadScaledTime(uint64_t) const;
void pruneByPlaybackTime(vlc_tick_t);
size_t pruneBySequenceNumber(uint64_t);

4
modules/demux/hls/playlist/Parser.cpp

@ -32,6 +32,7 @@
#include "../../adaptive/tools/Retrieve.hpp"
#include "../../adaptive/tools/Helper.h"
#include "../../adaptive/tools/Conversions.hpp"
#include "../../adaptive/logic/BufferingLogic.hpp"
#include "M3U8.hpp"
#include "Tags.hpp"
@ -148,7 +149,8 @@ void M3U8Parser::createAndFillRepresentation(vlc_object_t *p_obj, BaseAdaptation
if(rep->isLive())
{
/* avoid update playlist immediately */
uint64_t startseq = rep->getLiveStartSegmentNumber(0);
logic::DefaultBufferingLogic buflogic;
uint64_t startseq = buflogic.getStartSegmentNumber(rep);
rep->scheduleNextUpdate(startseq);
}
adaptSet->addRepresentation(rep);

Loading…
Cancel
Save