diff --git a/modules/demux/adaptive/PlaylistManager.cpp b/modules/demux/adaptive/PlaylistManager.cpp index 9a67b7c8cb9f66100419472471b798ce976aad8c..71498da06a3fcde2718f84b06f22607136f26327 100644 --- a/modules/demux/adaptive/PlaylistManager.cpp +++ b/modules/demux/adaptive/PlaylistManager.cpp @@ -74,12 +74,11 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_, vlc_cond_init(&waitcond); vlc_mutex_init(&cached.lock); cached.b_live = false; - 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.playlistStart = 0; + cached.playlistEnd = 0; + cached.playlistLength = 0; cached.lastupdate = 0; } @@ -397,7 +396,7 @@ vlc_tick_t PlaylistManager::getFirstPlaybackTime() const return 0; } -vlc_tick_t PlaylistManager::getCurrentPlaybackTime() const +vlc_tick_t PlaylistManager::getCurrentDemuxTime() const { vlc_mutex_locker locker(&demux.lock); return demux.i_nzpcr; @@ -537,16 +536,16 @@ int PlaylistManager::doControl(int i_query, va_list args) case DEMUX_GET_LENGTH: { vlc_mutex_locker locker(&cached.lock); - if(cached.b_live && cached.i_length == 0) + if(cached.b_live && cached.playlistLength == 0) return VLC_EGENERIC; - *(va_arg (args, vlc_tick_t *)) = cached.i_length; + *(va_arg (args, vlc_tick_t *)) = cached.playlistLength; break; } case DEMUX_GET_POSITION: { vlc_mutex_locker locker(&cached.lock); - if(cached.b_live && cached.i_length == 0) + if(cached.b_live && cached.playlistLength == 0) return VLC_EGENERIC; *(va_arg (args, double *)) = cached.f_position; break; @@ -557,35 +556,26 @@ int PlaylistManager::doControl(int i_query, va_list args) setBufferingRunState(false); /* stop downloader first */ vlc_mutex_locker locker(&cached.lock); - 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) + if(cached.playlistLength == 0) { setBufferingRunState(true); return VLC_EGENERIC; } - vlc_tick_t seektime = i_start + i_duration * va_arg(args, double); - if(!setPosition(seektime)) + double pos = va_arg(args, double); + vlc_tick_t seekTime = cached.playlistStart + cached.playlistLength * pos; + + SeekDebug(msg_Dbg(p_demux, "Seek %f to %ld plstart %ld duration %ld", + pos, seekTime, cached.playlistEnd, cached.playlistLength)); + + if(!setPosition(seekTime)) { setBufferingRunState(true); return VLC_EGENERIC; } demux.i_nzpcr = VLC_TICK_INVALID; + cached.lastupdate = 0; setBufferingRunState(true); break; } @@ -603,6 +593,7 @@ int PlaylistManager::doControl(int i_query, va_list args) vlc_mutex_locker locker(&cached.lock); demux.i_nzpcr = VLC_TICK_INVALID; + cached.lastupdate = 0; setBufferingRunState(true); break; } @@ -697,46 +688,62 @@ void PlaylistManager::updateControlsPosition() return; cached.lastupdate = now; - cached.i_time = getCurrentPlaybackTime(); - cached.b_live = playlist->isLive(); - if(cached.b_live) + vlc_tick_t rapPlaylistStart = 0; + vlc_tick_t rapDemuxStart = 0; + std::vector<AbstractStream *>::iterator it; + for(it=streams.begin(); it!=streams.end(); ++it) { - std::vector<AbstractStream *>::iterator it; - for(it=streams.begin(); it!=streams.end(); ++it) + AbstractStream *st = *it; + if(st->isValid() && !st->isDisabled() && st->isSelected()) { - AbstractStream *st = *it; - if(st->isValid() && !st->isDisabled() && st->isSelected()) - { - if(st->getMediaPlaybackRange(&cached.rangeStart, &cached.rangeEnd, - &cached.rangeLength)) - break; - } + if(st->getMediaPlaybackTimes(&cached.playlistStart, &cached.playlistEnd, + &cached.playlistLength, + &rapPlaylistStart, &rapDemuxStart)) + 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; - } + /* + * Relative position: + * -> Elapsed demux time (current demux time - first demux time) + * Since PlaylistTime != DemuxTime (HLS crap, TS): + * -> Use Playlist<->Demux time offset provided by EsOut + * to convert to elapsed playlist time. + * But this diff is not available until we have demuxed data... + * Fallback on relative seek from playlist start in that case + * But also playback might not have started at beginning of playlist + * -> Apply relative start from seek point (set on EsOut as ExpectedTime) + * + * All seeks need to be done in playlist time ! + */ + + vlc_tick_t currentDemuxTime = getCurrentDemuxTime(); + cached.b_live = playlist->isLive(); - 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 + SeekDebug(msg_Dbg(p_demux, "playlist Start/End %ld/%ld len %ld" + "rap pl/demux (%ld/%ld)", + cached.playlistStart, cached.playlistEnd, cached.playlistEnd, + rapPlaylistStart, rapDemuxStart)); + + if(cached.b_live) + { + /* Special case for live until we can provide relative start to fully match + the above description */ + cached.i_time = currentDemuxTime; + + if(cached.playlistStart != cached.playlistEnd) { - end = cached.rangeEnd; - start = cached.rangeStart; + if(cached.playlistStart < 0) /* Live template. Range start = now() - buffering depth */ + { + cached.playlistEnd = vlc_tick_from_sec(now); + cached.playlistStart = cached.playlistEnd - cached.playlistLength; + } } - - const vlc_tick_t currentTime = getCurrentPlaybackTime(); - if(currentTime > start && currentTime <= end && cached.i_length) + const vlc_tick_t currentTime = getCurrentDemuxTime(); + if(currentTime > cached.playlistStart && + currentTime <= cached.playlistEnd && cached.playlistLength) { - cached.f_position = ((double)(currentTime - start)) / cached.i_length; + cached.f_position = ((double)(currentTime - cached.playlistStart)) / cached.playlistLength; } else { @@ -745,18 +752,26 @@ void PlaylistManager::updateControlsPosition() } else { - cached.i_length = playlist->duration.Get(); - cached.i_time -= getFirstPlaybackTime(); - if(cached.i_length) + if(playlist->duration.Get() > cached.playlistLength) + cached.playlistLength = playlist->duration.Get(); + + if(cached.playlistLength && currentDemuxTime) { - const vlc_tick_t i_length = getCurrentPlaybackTime() - getFirstPlaybackTime(); - cached.f_position = (double) i_length / cached.i_length; + /* convert to playlist time */ + vlc_tick_t rapRelOffset = currentDemuxTime - rapDemuxStart; /* offset from start/seek */ + vlc_tick_t absPlaylistTime = rapPlaylistStart + rapRelOffset; /* converted as abs playlist time */ + vlc_tick_t relMediaTime = absPlaylistTime - cached.playlistStart; /* elapsed, in playlist time */ + cached.i_time = absPlaylistTime; + cached.f_position = (double) relMediaTime / cached.playlistLength; } else { cached.f_position = 0.0; } } + + SeekDebug(msg_Dbg(p_demux, "cached.i_time (%ld) cur %ld rap start (pl %ld/dmx %ld)", + cached.i_time, currentDemuxTime, rapPlaylistStart, rapDemuxStart)); } AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn) diff --git a/modules/demux/adaptive/PlaylistManager.h b/modules/demux/adaptive/PlaylistManager.h index 03f799ac1de907f45fb18233683f041312aa40d2..b94f59d7de2ad934ab8f25861037f2dc56f4a144 100644 --- a/modules/demux/adaptive/PlaylistManager.h +++ b/modules/demux/adaptive/PlaylistManager.h @@ -79,7 +79,7 @@ namespace adaptive vlc_tick_t getFirstDTS() const; virtual vlc_tick_t getFirstPlaybackTime() const; - vlc_tick_t getCurrentPlaybackTime() const; + vlc_tick_t getCurrentDemuxTime() const; virtual bool reactivateStream(AbstractStream *); bool setupPeriod(); @@ -118,13 +118,12 @@ namespace adaptive struct { bool b_live; - vlc_tick_t i_length; 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; + vlc_tick_t playlistStart; + vlc_tick_t playlistEnd; + vlc_tick_t playlistLength; time_t lastupdate; } cached; diff --git a/modules/demux/adaptive/Streams.cpp b/modules/demux/adaptive/Streams.cpp index faa64e068d5e06dfc23c7c06f0ae814f10053bce..e183efa0c8f5f40df88af3cf32feb1cf40d4d959 100644 --- a/modules/demux/adaptive/Streams.cpp +++ b/modules/demux/adaptive/Streams.cpp @@ -91,7 +91,7 @@ bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker, segmentTracker->registerListener(this); segmentTracker->notifyBufferingState(true); connManager = conn; - setTimeOffset(segmentTracker->getPlaybackTime()); + fakeesout->setExpectedTimestamp(segmentTracker->getPlaybackTime()); declaredCodecs(); return true; } @@ -129,7 +129,7 @@ void AbstractStream::prepareRestart(bool b_discontinuity) { /* Enqueue Del Commands for all current ES */ demuxer->drain(); - setTimeOffset(-1); + fakeEsOut()->resetTimestamps(); /* Enqueue Del Commands for all current ES */ fakeEsOut()->scheduleAllForDeletion(); if(b_discontinuity) @@ -545,9 +545,10 @@ bool AbstractStream::setPosition(vlc_tick_t time, bool tryonly) currentChunk = NULL; needrestart = false; - setTimeOffset(-1); - setTimeOffset(segmentTracker->getPlaybackTime()); + fakeEsOut()->resetTimestamps(); + vlc_tick_t seekMediaTime = segmentTracker->getPlaybackTime(); + fakeEsOut()->setExpectedTimestamp(seekMediaTime); if( !restartDemux() ) { msg_Info(p_realdemux, "Restart demux failed"); @@ -568,15 +569,13 @@ bool AbstractStream::setPosition(vlc_tick_t time, bool tryonly) return ret; } -vlc_tick_t AbstractStream::getPlaybackTime() const +bool AbstractStream::getMediaPlaybackTimes(vlc_tick_t *start, vlc_tick_t *end, + vlc_tick_t *length, + vlc_tick_t *mediaStart, + vlc_tick_t *demuxStart) 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); + return (segmentTracker->getMediaPlaybackRange(start, end, length) && + fakeEsOut()->getStartTimestamps(mediaStart, demuxStart)); } void AbstractStream::runUpdates() @@ -593,20 +592,6 @@ void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const p_fmt->psz_description = strdup(description.c_str()); } -void AbstractStream::setTimeOffset(vlc_tick_t i_offset) -{ - /* Check if we need to set an offset as the demuxer - * will start from zero from seek point */ - if(i_offset < 0) /* reset */ - { - fakeEsOut()->setExpectedTimestamp(-1); - } - else - { - fakeEsOut()->setExpectedTimestamp(i_offset); - } -} - AbstractDemuxer * AbstractStream::createDemux(const StreamFormat &format) { AbstractDemuxer *ret = newDemux( p_realdemux, format, diff --git a/modules/demux/adaptive/Streams.hpp b/modules/demux/adaptive/Streams.hpp index 5e7d2877f048a0442846d51897190341e12ca652..8bba3679427ef2c5ca61b71d1ee93f45420a539b 100644 --- a/modules/demux/adaptive/Streams.hpp +++ b/modules/demux/adaptive/Streams.hpp @@ -88,8 +88,8 @@ namespace adaptive status dequeue(vlc_tick_t, vlc_tick_t *); 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; + bool getMediaPlaybackTimes(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *, + vlc_tick_t *, vlc_tick_t *) const; void runUpdates(); /* Used by demuxers fake streams */ @@ -103,7 +103,6 @@ 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 &); virtual AbstractDemuxer * newDemux(demux_t *, const StreamFormat &, diff --git a/modules/demux/adaptive/tools/Debug.hpp b/modules/demux/adaptive/tools/Debug.hpp index a326d43ac24242e76219705e9cbf6c5347f4e03e..7b6548b1c2cca93ced6786c24fcc10070f0450df 100644 --- a/modules/demux/adaptive/tools/Debug.hpp +++ b/modules/demux/adaptive/tools/Debug.hpp @@ -22,6 +22,7 @@ //#define ADAPTATIVE_ADVANCED_DEBUG 0 //#define ADAPTATIVE_BW_DEBUG 0 +//#define ADAPTATIVE_SEEK_DEBUG 0 #ifdef ADAPTATIVE_ADVANCED_DEBUG #define AdvDebug(code) code @@ -35,5 +36,11 @@ #define BwDebug(code) #endif +#ifdef ADAPTATIVE_SEEK_DEBUG + #define SeekDebug(code) code +#else + #define SeekDebug(code) +#endif + #endif // DEBUG_HPP