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