Commit 146d47c4 authored by François Cartegnie's avatar François Cartegnie 🤞

demux: adaptative: split update steps and handle failures

And use targetduration hint for scheduling HLS updates
parent 1a4b8ae2
......@@ -57,6 +57,7 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_,
i_nzpcr ( 0 )
{
currentPeriod = playlist->getFirstPeriod();
failedupdates = 0;
}
PlaylistManager::~PlaylistManager ()
......@@ -248,6 +249,11 @@ bool PlaylistManager::setPosition(mtime_t time)
return ret;
}
bool PlaylistManager::needsUpdate() const
{
return playlist->isLive() && (failedupdates < 3);
}
bool PlaylistManager::seekAble() const
{
if(playlist->isLive())
......@@ -262,6 +268,11 @@ bool PlaylistManager::seekAble() const
return true;
}
void PlaylistManager::scheduleNextUpdate()
{
}
bool PlaylistManager::updatePlaylist()
{
std::vector<AbstractStream *>::const_iterator it;
......@@ -318,7 +329,13 @@ int PlaylistManager::doDemux(int64_t increment)
break;
}
updatePlaylist();
if(needsUpdate())
{
if(updatePlaylist())
scheduleNextUpdate();
else
failedupdates++;
}
return VLC_DEMUXER_SUCCESS;
}
......
......@@ -60,7 +60,9 @@ namespace adaptative
int esCount() const;
bool setPosition(mtime_t);
bool seekAble() const;
virtual bool needsUpdate() const;
virtual bool updatePlaylist();
virtual void scheduleNextUpdate();
/* static callbacks */
static int control_callback(demux_t *, int, va_list);
......@@ -88,6 +90,7 @@ namespace adaptative
time_t nextPlaylistupdate;
mtime_t i_nzpcr;
BasePeriod *currentPeriod;
int failedupdates;
};
}
......
......@@ -119,9 +119,10 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM
initializing = true;
}
bool b_updated = false;
/* Ensure ephemere content is updated/loaded */
if(rep->needsUpdate())
rep->runLocalUpdates(getSegmentStart(), count, false);
b_updated = rep->runLocalUpdates(getSegmentStart(), count, false);
if(prevRep && !rep->consistentSegmentNumber())
{
......@@ -134,8 +135,12 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM
first = false;
}
if(!rep->consistentSegmentNumber())
curRepresentation->pruneBySegmentNumber(count);
if(b_updated)
{
if(!rep->consistentSegmentNumber())
curRepresentation->pruneBySegmentNumber(count);
curRepresentation->scheduleNextUpdate(count);
}
if(!init_sent)
{
......@@ -249,8 +254,11 @@ void SegmentTracker::pruneFromCurrent()
void SegmentTracker::updateSelected()
{
if(curRepresentation)
if(curRepresentation && curRepresentation->needsUpdate())
{
curRepresentation->runLocalUpdates(getSegmentStart(), count, true);
curRepresentation->scheduleNextUpdate(count);
}
}
void SegmentTracker::notify(const SegmentTrackerEvent &event)
......
......@@ -30,6 +30,7 @@
#include "BaseRepresentation.h"
#include "BaseAdaptationSet.h"
#include "SegmentTemplate.h"
#include "SegmentTimeline.h"
#include "ID.hpp"
using namespace adaptative;
......@@ -77,6 +78,16 @@ bool BaseRepresentation::needsUpdate() const
return false;
}
bool BaseRepresentation::runLocalUpdates(mtime_t, uint64_t, bool)
{
return false;
}
void BaseRepresentation::scheduleNextUpdate(uint64_t)
{
}
bool BaseRepresentation::consistentSegmentNumber() const
{
return b_consistent;
......
......@@ -58,10 +58,12 @@ namespace adaptative
void setBandwidth ( uint64_t bandwidth );
const std::list<std::string> & getCodecs () const;
void addCodec (const std::string &);
virtual bool needsUpdate() const;
bool consistentSegmentNumber () const;
virtual mtime_t getMinAheadTime (uint64_t) const;
virtual bool needsUpdate () const;
virtual bool runLocalUpdates (mtime_t, uint64_t, bool);
virtual void scheduleNextUpdate (uint64_t);
virtual void debug (vlc_object_t *,int = 0) const;
......
......@@ -448,11 +448,6 @@ uint64_t SegmentInformation::translateSegmentNumber(uint64_t num, const SegmentI
return num;
}
void SegmentInformation::runLocalUpdates(mtime_t, uint64_t, bool)
{
}
SegmentInformation::SwitchPolicy SegmentInformation::getSwitchPolicy() const
{
if(switchpolicy == SWITCH_UNKNOWN)
......
......@@ -88,7 +88,6 @@ namespace adaptative
virtual void mergeWithTimeline(SegmentTimeline *); /* ! don't use with global merge */
virtual void pruneBySegmentNumber(uint64_t);
virtual uint64_t translateSegmentNumber(uint64_t, const SegmentInformation *) const;
virtual void runLocalUpdates(mtime_t, uint64_t, bool);
protected:
std::size_t getAllSegments(std::vector<ISegment *> &) const;
......
......@@ -59,15 +59,42 @@ DASHManager::~DASHManager ()
{
}
bool DASHManager::updatePlaylist()
void DASHManager::scheduleNextUpdate()
{
if(!playlist->isLive() || !playlist->minUpdatePeriod.Get())
return true;
time_t now = time(NULL);
if(nextPlaylistupdate && now < nextPlaylistupdate)
return true;
mtime_t minbuffer = 0;
std::vector<AbstractStream *>::const_iterator it;
for(it=streams.begin(); it!=streams.end(); ++it)
{
const AbstractStream *st = *it;
const mtime_t m = st->getMinAheadTime();
if(m > 0 && (m < minbuffer || minbuffer == 0))
minbuffer = m;
}
minbuffer /= 2;
if(playlist->minUpdatePeriod.Get() > minbuffer)
minbuffer = playlist->minUpdatePeriod.Get();
if(minbuffer < 5 * CLOCK_FREQ)
minbuffer = 5 * CLOCK_FREQ;
nextPlaylistupdate = now + minbuffer / CLOCK_FREQ;
msg_Dbg(p_demux, "Updated MPD, next update in %" PRId64 "s", (mtime_t) nextPlaylistupdate - now );
}
bool DASHManager::needsUpdate() const
{
if(nextPlaylistupdate && time(NULL) < nextPlaylistupdate)
return false;
return PlaylistManager::needsUpdate();
}
bool DASHManager::updatePlaylist()
{
/* do update */
if(nextPlaylistupdate)
{
......@@ -83,7 +110,6 @@ bool DASHManager::updatePlaylist()
if(!mpdstream)
{
block_Release(p_block);
nextPlaylistupdate = now + playlist->minUpdatePeriod.Get() / CLOCK_FREQ;
return false;
}
......@@ -92,7 +118,6 @@ bool DASHManager::updatePlaylist()
{
stream_Delete(mpdstream);
block_Release(p_block);
nextPlaylistupdate = now + playlist->minUpdatePeriod.Get() / CLOCK_FREQ;
return false;
}
......@@ -117,25 +142,6 @@ bool DASHManager::updatePlaylist()
block_Release(p_block);
}
/* Compute new MPD update time */
mtime_t mininterval = 0;
mtime_t maxinterval = 0;
playlist->getPlaylistDurationsRange(&mininterval, &maxinterval);
if(playlist->minUpdatePeriod.Get() > mininterval)
mininterval = playlist->minUpdatePeriod.Get();
if(mininterval < 5 * CLOCK_FREQ)
mininterval = 5 * CLOCK_FREQ;
if(maxinterval < mininterval)
maxinterval = mininterval;
nextPlaylistupdate = now + (mininterval + (maxinterval - mininterval) / 2) / CLOCK_FREQ;
msg_Dbg(p_demux, "Updated MPD, next update in %" PRId64 "s (%" PRId64 "..%" PRId64 ")",
(mtime_t) nextPlaylistupdate - now, mininterval/ CLOCK_FREQ, maxinterval/ CLOCK_FREQ );
return true;
}
......
......@@ -49,7 +49,9 @@ namespace dash
logic::AbstractAdaptationLogic::LogicType type);
virtual ~DASHManager ();
virtual bool updatePlaylist(); //reimpl
virtual bool needsUpdate() const; /* reimpl */
virtual bool updatePlaylist(); /* reimpl */
virtual void scheduleNextUpdate();/* reimpl */
static bool isDASH(xml::Node *);
static bool mimeMatched(const std::string &);
......
......@@ -302,6 +302,10 @@ void M3U8Parser::parseSegments(vlc_object_t *p_obj, Representation *rep, const s
}
break;
case SingleValueTag::EXTXTARGETDURATION:
rep->targetDuration = static_cast<const SingleValueTag *>(tag)->getValue().decimal();
break;
case SingleValueTag::EXTXPLAYLISTTYPE:
rep->b_live = (static_cast<const SingleValueTag *>(tag)->getValue().value != "VOD");
break;
......
......@@ -42,7 +42,8 @@ Representation::Representation ( BaseAdaptationSet *set ) :
b_live = true;
b_loaded = false;
switchpolicy = SegmentInformation::SWITCH_SEGMENT_ALIGNED; /* FIXME: based on streamformat */
nextPlaylistupdate = 0;
nextUpdateTime = 0;
targetDuration = 0;
streamFormat = StreamFormat::UNKNOWN;
}
......@@ -97,16 +98,48 @@ void Representation::debug(vlc_object_t *obj, int indent) const
}
}
void Representation::scheduleNextUpdate(uint64_t number)
{
const AbstractPlaylist *playlist = getPlaylist();
const time_t now = time(NULL);
/* Compute new update time */
mtime_t minbuffer = getMinAheadTime(number);
/* Update frequency must always be at least targetDuration (if any)*/
if(targetDuration)
{
if(minbuffer >= 3 * CLOCK_FREQ * targetDuration)
minbuffer -= 2 * CLOCK_FREQ * targetDuration;
}
else
{
minbuffer /= 2;
if(targetDuration > minbuffer / CLOCK_FREQ)
minbuffer = targetDuration * CLOCK_FREQ;
}
if(minbuffer < CLOCK_FREQ)
minbuffer = CLOCK_FREQ;
nextUpdateTime = now + minbuffer / CLOCK_FREQ;
msg_Dbg(playlist->getVLCObject(), "Updated playlist ID %s, next update in %" PRId64 "s",
getID().str().c_str(), (mtime_t) nextUpdateTime - now);
debug(playlist->getVLCObject(), 0);
}
bool Representation::needsUpdate() const
{
return true;
return !b_loaded || (isLive() && nextUpdateTime < time(NULL));
}
void Representation::runLocalUpdates(mtime_t, uint64_t number, bool prune)
bool Representation::runLocalUpdates(mtime_t, uint64_t number, bool prune)
{
const time_t now = time(NULL);
const AbstractPlaylist *playlist = getPlaylist();
if(!b_loaded || (isLive() && nextPlaylistupdate < now))
if(!b_loaded || (isLive() && nextUpdateTime < now))
{
M3U8Parser parser;
parser.appendSegmentsFromPlaylistURI(playlist->getVLCObject(), this);
......@@ -115,28 +148,10 @@ void Representation::runLocalUpdates(mtime_t, uint64_t number, bool prune)
if(prune)
pruneBySegmentNumber(number);
/* Compute new update time */
mtime_t mininterval = 0;
mtime_t maxinterval = 0;
getDurationsRange( &mininterval, &maxinterval );
if(playlist->minUpdatePeriod.Get() > mininterval)
mininterval = playlist->minUpdatePeriod.Get();
if(mininterval < 5 * CLOCK_FREQ)
mininterval = 5 * CLOCK_FREQ;
if(maxinterval < mininterval)
maxinterval = mininterval;
nextPlaylistupdate = now + (mininterval + (maxinterval - mininterval) / 2) / CLOCK_FREQ;
msg_Dbg(playlist->getVLCObject(), "Updated playlist ID %s, next update in %" PRId64 "s",
getID().str().c_str(), (mtime_t) nextPlaylistupdate - now);
debug(playlist->getVLCObject(), 0);
return true;
}
return true;
}
void Representation::getDurationsRange(mtime_t *min, mtime_t *max) const
......
......@@ -47,9 +47,10 @@ namespace hls
Url getPlaylistUrl() const;
bool isLive() const;
bool initialized() const;
virtual void scheduleNextUpdate(uint64_t); /* reimpl */
virtual bool needsUpdate() const; /* reimpl */
virtual void debug(vlc_object_t *, int) const; /* reimpl */
virtual void runLocalUpdates(mtime_t, uint64_t, bool); /* reimpl */
virtual bool runLocalUpdates(mtime_t, uint64_t, bool); /* reimpl */
virtual void getDurationsRange(mtime_t *, mtime_t *) const; /* reimpl */
virtual uint64_t translateSegmentNumber(uint64_t, const SegmentInformation *) const; /* reimpl */
......@@ -57,7 +58,8 @@ namespace hls
StreamFormat streamFormat;
bool b_live;
bool b_loaded;
time_t nextPlaylistupdate;
time_t nextUpdateTime;
time_t targetDuration;
Url playlistUrl;
Property<std::string> audio;
Property<std::string> video;
......
......@@ -92,19 +92,44 @@ bool SmoothManager::updatePlaylist()
return updatePlaylist(false);
}
bool SmoothManager::updatePlaylist(bool forcemanifest)
void SmoothManager::scheduleNextUpdate()
{
/* FIXME: do update from manifest after resuming from pause */
if(!playlist->isLive() || !playlist->minUpdatePeriod.Get())
return true;
time_t now = time(NULL);
if(nextPlaylistupdate && now < nextPlaylistupdate)
return true;
mtime_t minbuffer = 0;
std::vector<AbstractStream *>::const_iterator it;
for(it=streams.begin(); it!=streams.end(); ++it)
{
const AbstractStream *st = *it;
const mtime_t m = st->getMinAheadTime();
if(m > 0 && (m < minbuffer || minbuffer == 0))
minbuffer = m;
}
minbuffer /= 2;
if(playlist->minUpdatePeriod.Get() > minbuffer)
minbuffer = playlist->minUpdatePeriod.Get();
if(minbuffer < 5 * CLOCK_FREQ)
minbuffer = 5 * CLOCK_FREQ;
nextPlaylistupdate = now + minbuffer / CLOCK_FREQ;
msg_Dbg(p_demux, "Updated playlist, next update in %" PRId64 "s", (mtime_t) nextPlaylistupdate - now );
}
bool SmoothManager::needsUpdate() const
{
if(nextPlaylistupdate && time(NULL) < nextPlaylistupdate)
return false;
return PlaylistManager::needsUpdate();
}
mtime_t mininterval = 0;
mtime_t maxinterval = 0;
bool SmoothManager::updatePlaylist(bool forcemanifest)
{
/* FIXME: do update from manifest after resuming from pause */
std::vector<AbstractStream *>::iterator it;
for(it=streams.begin(); it!=streams.end(); it++)
......@@ -118,7 +143,6 @@ bool SmoothManager::updatePlaylist(bool forcemanifest)
Manifest *newManifest = fetchManifest();
if(newManifest)
{
newManifest->getPlaylistDurationsRange(&mininterval, &maxinterval);
playlist->mergeWith(newManifest, 0);
delete newManifest;
......@@ -129,26 +153,9 @@ bool SmoothManager::updatePlaylist(bool forcemanifest)
playlist->debug();
#endif
}
else return false;
}
/* Compute new Manifest update time */
if(!mininterval && !maxinterval)
playlist->getPlaylistDurationsRange(&mininterval, &maxinterval);
if(playlist->minUpdatePeriod.Get() > mininterval)
mininterval = playlist->minUpdatePeriod.Get();
if(mininterval < 5 * CLOCK_FREQ)
mininterval = 5 * CLOCK_FREQ;
if(maxinterval < mininterval)
maxinterval = mininterval;
nextPlaylistupdate = now + (mininterval + (maxinterval - mininterval) / 2) / CLOCK_FREQ;
// msg_Dbg(p_demux, "Updated Manifest, next update in %" PRId64 "s (%" PRId64 "..%" PRId64 ")",
// (mtime_t) nextPlaylistupdate - now, mininterval/ CLOCK_FREQ, maxinterval/ CLOCK_FREQ );
return true;
}
......
......@@ -44,7 +44,10 @@ namespace smooth
logic::AbstractAdaptationLogic::LogicType type );
virtual ~SmoothManager();
virtual bool updatePlaylist(); //reimpl
virtual bool needsUpdate() const; /* reimpl */
virtual void scheduleNextUpdate(); /* reimpl */
virtual bool updatePlaylist(); /* reimpl */
static bool isSmoothStreaming(xml::Node *);
static bool mimeMatched(const std::string &);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment