demux: adaptive: remove unused global drain
[vlc.git] / modules / demux / adaptive / PlaylistManager.cpp
blob283c3f780b1303e00c42d86765e21f8d2a45821f
1 /*
2 * PlaylistManager.cpp
3 *****************************************************************************
4 * Copyright © 2010 - 2011 Klagenfurt University
5 * 2015 VideoLAN and VLC Authors
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include "PlaylistManager.h"
27 #include "SegmentTracker.hpp"
28 #include "SharedResources.hpp"
29 #include "playlist/BasePlaylist.hpp"
30 #include "playlist/BasePeriod.h"
31 #include "playlist/BaseAdaptationSet.h"
32 #include "playlist/BaseRepresentation.h"
33 #include "http/HTTPConnectionManager.h"
34 #include "logic/AlwaysBestAdaptationLogic.h"
35 #include "logic/RateBasedAdaptationLogic.h"
36 #include "logic/AlwaysLowestAdaptationLogic.hpp"
37 #include "logic/PredictiveAdaptationLogic.hpp"
38 #include "logic/NearOptimalAdaptationLogic.hpp"
39 #include "logic/BufferingLogic.hpp"
40 #include "tools/Debug.hpp"
41 #ifdef ADAPTIVE_DEBUGGING_LOGIC
42 # include "logic/RoundRobinLogic.hpp"
43 #endif
44 #include <vlc_stream.h>
45 #include <vlc_demux.h>
46 #include <vlc_threads.h>
48 #include <algorithm>
49 #include <ctime>
51 using namespace adaptive::http;
52 using namespace adaptive::logic;
53 using namespace adaptive;
54 using vlc::threads::mutex_locker;
56 PlaylistManager::PlaylistManager( demux_t *p_demux_,
57 SharedResources *res,
58 BasePlaylist *pl,
59 AbstractStreamFactory *factory,
60 AbstractAdaptationLogic::LogicType type ) :
61 logicType ( type ),
62 logic ( nullptr ),
63 playlist ( pl ),
64 streamFactory ( factory ),
65 p_demux ( p_demux_ )
67 currentPeriod = playlist->getFirstPeriod();
68 resources = res;
69 bufferingLogic = nullptr;
70 failedupdates = 0;
71 b_thread = false;
72 b_buffering = false;
73 b_canceled = false;
74 nextPlaylistupdate = 0;
75 demux.i_nzpcr = VLC_TICK_INVALID;
76 demux.i_firstpcr = VLC_TICK_INVALID;
77 vlc_mutex_init(&demux.lock);
78 vlc_cond_init(&demux.cond);
79 vlc_mutex_init(&cached.lock);
80 cached.b_live = false;
81 cached.f_position = 0.0;
82 cached.i_time = VLC_TICK_INVALID;
83 cached.playlistStart = 0;
84 cached.playlistEnd = 0;
85 cached.playlistLength = 0;
86 cached.lastupdate = 0;
89 PlaylistManager::~PlaylistManager ()
91 delete streamFactory;
92 unsetPeriod();
93 delete playlist;
94 delete logic;
95 delete resources;
96 delete bufferingLogic;
99 void PlaylistManager::unsetPeriod()
101 std::vector<AbstractStream *>::iterator it;
102 for(it=streams.begin(); it!=streams.end(); ++it)
103 delete *it;
104 streams.clear();
107 bool PlaylistManager::setupPeriod()
109 if(!currentPeriod)
110 return false;
112 if(!logic && !(logic = createLogic(logicType, resources->getConnManager())))
113 return false;
115 if(!bufferingLogic && !(bufferingLogic = createBufferingLogic()))
116 return false;
118 std::vector<BaseAdaptationSet*> sets = currentPeriod->getAdaptationSets();
119 for(BaseAdaptationSet *set : sets)
121 if(set && streamFactory)
123 SegmentTracker *tracker = new SegmentTracker(resources, logic,
124 bufferingLogic, set);
125 if(!tracker)
126 continue;
128 AbstractStream *st = streamFactory->create(p_demux, set->getStreamFormat(),
129 tracker, resources->getConnManager());
130 if(!st)
132 delete tracker;
133 continue;
136 streams.push_back(st);
138 /* Generate stream description */
139 if(!set->getLang().empty())
140 st->setLanguage(set->getLang());
142 if(!set->description.Get().empty())
143 st->setDescription(set->description.Get());
146 return true;
149 bool PlaylistManager::init()
151 if(!setupPeriod())
152 return false;
154 playlist->playbackStart.Set(time(nullptr));
155 nextPlaylistupdate = playlist->playbackStart.Get();
157 updateControlsPosition();
159 return true;
162 bool PlaylistManager::start()
164 if(b_thread)
165 return false;
167 b_thread = !vlc_clone(&thread, managerThread,
168 static_cast<void *>(this), VLC_THREAD_PRIORITY_INPUT);
169 if(!b_thread)
170 return false;
172 setBufferingRunState(true);
174 return true;
177 bool PlaylistManager::started() const
179 return b_thread;
182 void PlaylistManager::stop()
184 if(!b_thread)
185 return;
188 mutex_locker locker {lock};
189 b_canceled = true;
190 waitcond.signal();
193 vlc_join(thread, nullptr);
194 b_thread = false;
197 struct PrioritizedAbstractStream
199 AbstractStream::BufferingStatus status;
200 vlc_tick_t demuxed_amount;
201 AbstractStream *st;
204 static bool streamCompare(const PrioritizedAbstractStream &a, const PrioritizedAbstractStream &b)
206 if( a.status >= b.status ) /* Highest prio is higer value in enum */
208 if ( a.status == b.status ) /* Highest prio is lowest buffering */
209 return a.demuxed_amount < b.demuxed_amount;
210 else
211 return true;
213 return false;
216 AbstractStream::BufferingStatus PlaylistManager::bufferize(vlc_tick_t i_nzdeadline,
217 vlc_tick_t i_min_buffering, vlc_tick_t i_extra_buffering)
219 AbstractStream::BufferingStatus i_return = AbstractStream::BufferingStatus::End;
221 /* First reorder by status >> buffering level */
222 std::vector<PrioritizedAbstractStream> prioritized_streams(streams.size());
223 std::vector<PrioritizedAbstractStream>::iterator it = prioritized_streams.begin();
224 for(AbstractStream *stream : streams)
226 PrioritizedAbstractStream &p = *it;
227 p.st = stream;
228 p.status = p.st->getLastBufferStatus();
229 p.demuxed_amount = p.st->getDemuxedAmount(i_nzdeadline);
230 ++it;
232 std::sort(prioritized_streams.begin(), prioritized_streams.end(), streamCompare);
234 for(PrioritizedAbstractStream &pst : prioritized_streams)
236 AbstractStream *st = pst.st;
238 if(!st->isValid())
239 continue;
241 if(st->esCount())
243 if (st->isDisabled() &&
244 (!st->isSelected() || !reactivateStream(st)))
245 continue;
247 else
249 /* initial */
252 AbstractStream::BufferingStatus i_ret = st->bufferize(i_nzdeadline,
253 i_min_buffering,
254 i_extra_buffering,
255 getActiveStreamsCount() <= 1);
256 if(i_return != AbstractStream::BufferingStatus::Ongoing) /* Buffering streams need to keep going */
258 if(i_ret > i_return)
259 i_return = i_ret;
262 /* Bail out, will start again (high prio could be same starving stream) */
263 if( i_return == AbstractStream::BufferingStatus::Lessthanmin )
264 break;
267 vlc_mutex_lock(&demux.lock);
268 if(demux.i_nzpcr == VLC_TICK_INVALID &&
269 i_return != AbstractStream::BufferingStatus::Lessthanmin /* prevents starting before buffering is reached */ )
271 demux.i_nzpcr = getFirstDTS();
273 vlc_mutex_unlock(&demux.lock);
275 return i_return;
278 AbstractStream::Status PlaylistManager::dequeue(vlc_tick_t i_floor, vlc_tick_t *pi_nzbarrier)
280 AbstractStream::Status i_return = AbstractStream::Status::Eof;
282 const vlc_tick_t i_nzdeadline = *pi_nzbarrier;
284 for(AbstractStream *st : streams)
286 vlc_tick_t i_pcr;
287 AbstractStream::Status i_ret = st->dequeue(i_nzdeadline, &i_pcr);
288 if( i_ret > i_return )
289 i_return = i_ret;
291 if( i_pcr > i_floor )
292 *pi_nzbarrier = std::min( *pi_nzbarrier, i_pcr - VLC_TICK_0 );
295 return i_return;
298 vlc_tick_t PlaylistManager::getResumeTime() const
300 vlc_mutex_locker locker(&demux.lock);
301 return demux.i_nzpcr;
304 vlc_tick_t PlaylistManager::getFirstDTS() const
306 vlc_tick_t mindts = VLC_TICK_INVALID;
307 for(const AbstractStream *stream : streams)
309 const vlc_tick_t dts = stream->getFirstDTS();
310 if(mindts == VLC_TICK_INVALID)
311 mindts = dts;
312 else if(dts != VLC_TICK_INVALID)
313 mindts = std::min(mindts, dts);
315 return mindts;
318 unsigned PlaylistManager::getActiveStreamsCount() const
320 // TODO improve
321 unsigned count = 0;
322 for(const AbstractStream* st : streams)
324 if(st->isValid() && !st->isDisabled())
325 count++;
327 return count;
330 bool PlaylistManager::setPosition(vlc_tick_t time)
332 bool ret = true;
333 bool hasValidStream = false;
334 for(int real = 0; real < 2; real++)
336 /* Always probe if we can seek first */
337 for(AbstractStream* st : streams)
339 if(st->isValid() && !st->isDisabled())
341 hasValidStream = true;
342 ret &= st->setPosition(time, !real);
345 if(!ret)
346 break;
348 if(!hasValidStream)
350 msg_Warn(p_demux, "there is no valid streams");
351 ret = false;
353 return ret;
356 void PlaylistManager::setLivePause(bool b)
358 if(!started())
359 return;
361 for(AbstractStream* st : streams)
362 if(st->isValid() && !st->isDisabled())
363 st->setLivePause(b);
366 bool PlaylistManager::needsUpdate() const
368 return playlist->needsUpdates() &&
369 playlist->isLive() && (failedupdates < 3);
372 void PlaylistManager::scheduleNextUpdate()
377 bool PlaylistManager::updatePlaylist()
379 for(AbstractStream* st : streams)
380 st->runUpdates();
382 updateControlsPosition();
383 return true;
386 vlc_tick_t PlaylistManager::getFirstPlaybackTime() const
388 return 0;
391 vlc_tick_t PlaylistManager::getCurrentDemuxTime() const
393 vlc_mutex_locker locker(&demux.lock);
394 return demux.i_nzpcr;
397 vlc_tick_t PlaylistManager::getMinAheadTime() const
399 vlc_tick_t minbuffer = 0;
400 std::for_each(streams.cbegin(), streams.cend(),
401 [&minbuffer](const AbstractStream *st) {
402 if(st->isValid() && !st->isDisabled() && st->isSelected())
404 const vlc_tick_t m = st->getMinAheadTime();
405 if(m > 0 && (m < minbuffer || minbuffer == 0))
406 minbuffer = m;
409 return minbuffer;
412 bool PlaylistManager::reactivateStream(AbstractStream *stream)
414 return stream->reactivate(getResumeTime());
417 #define DEMUX_INCREMENT VLC_TICK_FROM_MS(50)
418 int PlaylistManager::demux_callback(demux_t *p_demux)
420 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
421 if(!manager->started() && !manager->start())
422 return VLC_DEMUXER_EOF;
423 return manager->doDemux(DEMUX_INCREMENT);
426 int PlaylistManager::doDemux(vlc_tick_t increment)
428 vlc_mutex_lock(&demux.lock);
429 if(demux.i_nzpcr == VLC_TICK_INVALID)
431 bool b_dead = true;
432 bool b_all_disabled = true;
433 std::vector<AbstractStream *>::const_iterator it;
434 for(it=streams.begin(); it!=streams.end(); ++it)
436 b_dead &= !(*it)->isValid();
437 b_all_disabled &= (*it)->isDisabled();
439 if(!b_dead)
440 vlc_cond_timedwait(&demux.cond, &demux.lock, vlc_tick_now() + VLC_TICK_FROM_MS(50));
441 vlc_mutex_unlock(&demux.lock);
442 return (b_dead || b_all_disabled) ? VLC_DEMUXER_EOF : VLC_DEMUXER_SUCCESS;
445 if(demux.i_firstpcr == VLC_TICK_INVALID)
446 demux.i_firstpcr = demux.i_nzpcr;
448 vlc_tick_t i_nzbarrier = demux.i_nzpcr + increment;
449 vlc_mutex_unlock(&demux.lock);
451 AbstractStream::Status status = dequeue(demux.i_nzpcr, &i_nzbarrier);
453 updateControlsPosition();
455 switch(status)
457 case AbstractStream::Status::Eof:
459 /* might be end of current period */
460 if(currentPeriod)
462 setBufferingRunState(false);
463 BasePeriod *nextPeriod = playlist->getNextPeriod(currentPeriod);
464 if(!nextPeriod)
465 return VLC_DEMUXER_EOF;
466 unsetPeriod();
467 currentPeriod = nextPeriod;
468 if (!setupPeriod())
469 return VLC_DEMUXER_EOF;
471 demux.i_nzpcr = VLC_TICK_INVALID;
472 demux.i_firstpcr = VLC_TICK_INVALID;
473 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
475 setBufferingRunState(true);
478 break;
479 case AbstractStream::Status::Buffering:
480 vlc_mutex_lock(&demux.lock);
481 vlc_cond_timedwait(&demux.cond, &demux.lock, vlc_tick_now() + VLC_TICK_FROM_MS(50));
482 vlc_mutex_unlock(&demux.lock);
483 break;
484 case AbstractStream::Status::Discontinuity:
485 vlc_mutex_lock(&demux.lock);
486 demux.i_nzpcr = VLC_TICK_INVALID;
487 demux.i_firstpcr = VLC_TICK_INVALID;
488 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
489 vlc_mutex_unlock(&demux.lock);
490 break;
491 case AbstractStream::Status::Demuxed:
492 vlc_mutex_lock(&demux.lock);
493 if( demux.i_nzpcr != VLC_TICK_INVALID && i_nzbarrier != demux.i_nzpcr )
495 demux.i_nzpcr = i_nzbarrier;
496 vlc_tick_t pcr = VLC_TICK_0 + std::max(INT64_C(0), demux.i_nzpcr - VLC_TICK_FROM_MS(100));
497 es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, 0, pcr);
499 vlc_mutex_unlock(&demux.lock);
500 break;
503 return VLC_DEMUXER_SUCCESS;
506 int PlaylistManager::control_callback(demux_t *p_demux, int i_query, va_list args)
508 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
509 return manager->doControl(i_query, args);
512 int PlaylistManager::doControl(int i_query, va_list args)
514 switch (i_query)
516 case DEMUX_CAN_SEEK:
517 case DEMUX_CAN_CONTROL_PACE:
518 *(va_arg (args, bool *)) = true;
519 break;
521 case DEMUX_CAN_PAUSE:
523 /* Always return true then fail late.
524 * See demux.c/demux_vaControl,
525 * misleading and should be DEMUX_CAN_CONTROL_PAUSE */
526 *(va_arg (args, bool *)) = true;
527 break;
530 case DEMUX_SET_PAUSE_STATE:
532 vlc_mutex_locker locker(&cached.lock);
533 bool b_pause = (bool)va_arg(args, int);
534 if(playlist->isLive())
536 setBufferingRunState(false); /* stop downloader first */
537 vlc_tick_t now = vlc_tick_now();
538 if(b_pause)
540 setLivePause(true);
541 pause_start = now;
542 msg_Dbg(p_demux,"Buffering and playback paused. No timeshift support.");
544 else
546 setLivePause(false);
547 msg_Dbg(p_demux,"Resuming buffering/playback after %" PRId64 "ms",
548 MS_FROM_VLC_TICK(now-pause_start));
549 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
551 setBufferingRunState(true);
552 demux.i_nzpcr = VLC_TICK_INVALID;
553 cached.lastupdate = 0;
555 return VLC_SUCCESS;
558 case DEMUX_GET_TIME:
560 vlc_mutex_locker locker(&cached.lock);
561 *(va_arg (args, vlc_tick_t *)) = cached.i_time;
562 break;
565 case DEMUX_GET_LENGTH:
567 vlc_mutex_locker locker(&cached.lock);
568 if(cached.b_live && cached.playlistLength == 0)
569 return VLC_EGENERIC;
570 *(va_arg (args, vlc_tick_t *)) = cached.playlistLength;
571 break;
574 case DEMUX_GET_POSITION:
576 vlc_mutex_locker locker(&cached.lock);
577 if(cached.b_live && cached.playlistLength == 0)
578 return VLC_EGENERIC;
579 *(va_arg (args, double *)) = cached.f_position;
580 break;
583 case DEMUX_SET_POSITION:
585 setBufferingRunState(false); /* stop downloader first */
586 vlc_mutex_locker locker(&cached.lock);
588 if(cached.playlistLength == 0)
590 setBufferingRunState(true);
591 return VLC_EGENERIC;
594 double pos = va_arg(args, double);
595 vlc_tick_t seekTime = cached.playlistStart + cached.playlistLength * pos;
597 SeekDebug(msg_Dbg(p_demux, "Seek %f to %ld plstart %ld duration %ld",
598 pos, seekTime, cached.playlistEnd, cached.playlistLength));
600 if(!setPosition(seekTime))
602 setBufferingRunState(true);
603 return VLC_EGENERIC;
606 demux.i_nzpcr = VLC_TICK_INVALID;
607 cached.lastupdate = 0;
608 setBufferingRunState(true);
609 break;
612 case DEMUX_SET_TIME:
614 setBufferingRunState(false); /* stop downloader first */
616 vlc_tick_t time = va_arg(args, vlc_tick_t);// + getFirstPlaybackTime();
617 if(!setPosition(time))
619 setBufferingRunState(true);
620 return VLC_EGENERIC;
623 vlc_mutex_locker locker(&cached.lock);
624 demux.i_nzpcr = VLC_TICK_INVALID;
625 cached.lastupdate = 0;
626 setBufferingRunState(true);
627 break;
630 case DEMUX_GET_PTS_DELAY:
631 *va_arg (args, vlc_tick_t *) = VLC_TICK_FROM_SEC(1);
632 break;
634 default:
635 return VLC_EGENERIC;
637 return VLC_SUCCESS;
640 void PlaylistManager::setBufferingRunState(bool b)
642 mutex_locker locker {lock};
643 b_buffering = b;
644 waitcond.signal();
647 void PlaylistManager::Run()
649 mutex_locker locker {lock};
650 const vlc_tick_t i_min_buffering = bufferingLogic->getMinBuffering(playlist);
651 const vlc_tick_t i_extra_buffering = bufferingLogic->getMaxBuffering(playlist) - i_min_buffering;
652 while(1)
654 while(!b_buffering && !b_canceled)
655 waitcond.wait(lock);
656 if (b_canceled)
657 break;
659 if(needsUpdate())
661 if(updatePlaylist())
662 scheduleNextUpdate();
663 else
664 failedupdates++;
667 vlc_mutex_lock(&demux.lock);
668 vlc_tick_t i_nzpcr = demux.i_nzpcr;
669 vlc_mutex_unlock(&demux.lock);
671 AbstractStream::BufferingStatus i_return = bufferize(i_nzpcr, i_min_buffering, i_extra_buffering);
673 if(i_return != AbstractStream::BufferingStatus::Lessthanmin)
675 vlc_tick_t i_deadline = vlc_tick_now();
676 if(i_return == AbstractStream::BufferingStatus::Ongoing)
677 i_deadline += VLC_TICK_FROM_MS(10);
678 else if(i_return == AbstractStream::BufferingStatus::Full)
679 i_deadline += VLC_TICK_FROM_MS(100);
680 else if(i_return == AbstractStream::BufferingStatus::End)
681 i_deadline += VLC_TICK_FROM_SEC(1);
682 else /*if(i_return == AbstractStream::BufferingStatus::suspended)*/
683 i_deadline += VLC_TICK_FROM_MS(250);
685 // TODO: The current function doesn't seem to modify shared
686 // state under demux lock.
687 vlc_cond_signal(&demux.cond);
689 while(b_buffering &&
690 waitcond.timedwait(lock, i_deadline) == 0 &&
691 i_deadline > vlc_tick_now() &&
692 !b_canceled);
693 if (b_canceled)
694 break;
699 void * PlaylistManager::managerThread(void *opaque)
701 static_cast<PlaylistManager *>(opaque)->Run();
702 return nullptr;
705 void PlaylistManager::updateControlsPosition()
707 vlc_mutex_locker locker(&cached.lock);
709 time_t now = time(nullptr);
710 if(now - cached.lastupdate < 1)
711 return;
712 cached.lastupdate = now;
714 vlc_tick_t rapPlaylistStart = 0;
715 vlc_tick_t rapDemuxStart = 0;
716 for(AbstractStream* st : streams)
718 if(st->isValid() && !st->isDisabled() && st->isSelected())
720 if(st->getMediaPlaybackTimes(&cached.playlistStart, &cached.playlistEnd,
721 &cached.playlistLength,
722 &rapPlaylistStart, &rapDemuxStart))
723 break;
728 * Relative position:
729 * -> Elapsed demux time (current demux time - first demux time)
730 * Since PlaylistTime != DemuxTime (HLS crap, TS):
731 * -> Use Playlist<->Demux time offset provided by EsOut
732 * to convert to elapsed playlist time.
733 * But this diff is not available until we have demuxed data...
734 * Fallback on relative seek from playlist start in that case
735 * But also playback might not have started at beginning of playlist
736 * -> Apply relative start from seek point (set on EsOut as ExpectedTime)
738 * All seeks need to be done in playlist time !
741 vlc_tick_t currentDemuxTime = getCurrentDemuxTime();
742 cached.b_live = playlist->isLive();
744 SeekDebug(msg_Dbg(p_demux, "playlist Start/End %ld/%ld len %ld"
745 "rap pl/demux (%ld/%ld)",
746 cached.playlistStart, cached.playlistEnd, cached.playlistEnd,
747 rapPlaylistStart, rapDemuxStart));
749 if(cached.b_live)
751 /* Special case for live until we can provide relative start to fully match
752 the above description */
753 cached.i_time = currentDemuxTime;
755 if(cached.playlistStart != cached.playlistEnd)
757 if(cached.playlistStart < 0) /* Live template. Range start = now() - buffering depth */
759 cached.playlistEnd = vlc_tick_from_sec(now);
760 cached.playlistStart = cached.playlistEnd - cached.playlistLength;
763 const vlc_tick_t currentTime = getCurrentDemuxTime();
764 if(currentTime > cached.playlistStart &&
765 currentTime <= cached.playlistEnd && cached.playlistLength)
767 cached.f_position = ((double)(currentTime - cached.playlistStart)) / cached.playlistLength;
769 else
771 cached.f_position = 0.0;
774 else
776 if(playlist->duration.Get() > cached.playlistLength)
777 cached.playlistLength = playlist->duration.Get();
779 if(cached.playlistLength && currentDemuxTime)
781 /* convert to playlist time */
782 vlc_tick_t rapRelOffset = currentDemuxTime - rapDemuxStart; /* offset from start/seek */
783 vlc_tick_t absPlaylistTime = rapPlaylistStart + rapRelOffset; /* converted as abs playlist time */
784 vlc_tick_t relMediaTime = absPlaylistTime - cached.playlistStart; /* elapsed, in playlist time */
785 cached.i_time = absPlaylistTime;
786 cached.f_position = (double) relMediaTime / cached.playlistLength;
788 else
790 cached.f_position = 0.0;
794 SeekDebug(msg_Dbg(p_demux, "cached.i_time (%ld) cur %ld rap start (pl %ld/dmx %ld)",
795 cached.i_time, currentDemuxTime, rapPlaylistStart, rapDemuxStart));
798 AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn)
800 vlc_object_t *obj = VLC_OBJECT(p_demux);
801 AbstractAdaptationLogic *logic = nullptr;
802 switch(type)
804 case AbstractAdaptationLogic::LogicType::FixedRate:
806 size_t bps = var_InheritInteger(p_demux, "adaptive-bw") * 8192;
807 logic = new (std::nothrow) FixedRateAdaptationLogic(obj, bps);
808 break;
810 case AbstractAdaptationLogic::LogicType::AlwaysLowest:
811 logic = new (std::nothrow) AlwaysLowestAdaptationLogic(obj);
812 break;
813 case AbstractAdaptationLogic::LogicType::AlwaysBest:
814 logic = new (std::nothrow) AlwaysBestAdaptationLogic(obj);
815 break;
816 case AbstractAdaptationLogic::LogicType::RateBased:
818 RateBasedAdaptationLogic *ratelogic =
819 new (std::nothrow) RateBasedAdaptationLogic(obj);
820 if(ratelogic)
821 conn->setDownloadRateObserver(ratelogic);
822 logic = ratelogic;
823 break;
825 case AbstractAdaptationLogic::LogicType::Default:
826 #ifdef ADAPTIVE_DEBUGGING_LOGIC
827 logic = new (std::nothrow) RoundRobinLogic(obj);
828 msg_Warn(p_demux, "using RoundRobinLogic every %u", RoundRobinLogic::QUANTUM);
829 break;
830 #endif
831 case AbstractAdaptationLogic::LogicType::NearOptimal:
833 NearOptimalAdaptationLogic *noplogic =
834 new (std::nothrow) NearOptimalAdaptationLogic(obj);
835 if(noplogic)
836 conn->setDownloadRateObserver(noplogic);
837 logic = noplogic;
838 break;
840 case AbstractAdaptationLogic::LogicType::Predictive:
842 AbstractAdaptationLogic *predictivelogic =
843 new (std::nothrow) PredictiveAdaptationLogic(obj);
844 if(predictivelogic)
845 conn->setDownloadRateObserver(predictivelogic);
846 logic = predictivelogic;
849 default:
850 break;
853 if(logic)
855 int w = var_InheritInteger(p_demux, "adaptive-maxwidth");
856 int h = var_InheritInteger(p_demux, "adaptive-maxheight");
857 if(h == 0)
859 h = var_InheritInteger(p_demux, "preferred-resolution");
860 /* Adapt for slightly different minimum/maximum semantics */
861 if(h == -1)
862 h = 0;
863 else if(h == 0)
864 h = 1;
867 logic->setMaxDeviceResolution(w, h);
870 return logic;
873 AbstractBufferingLogic *PlaylistManager::createBufferingLogic() const
875 DefaultBufferingLogic *bl = new DefaultBufferingLogic();
876 if(bl)
878 unsigned v = var_InheritInteger(p_demux, "adaptive-livedelay");
879 if(v)
880 bl->setUserLiveDelay(VLC_TICK_FROM_MS(v));
881 v = var_InheritInteger(p_demux, "adaptive-maxbuffer");
882 if(v)
883 bl->setUserMaxBuffering(VLC_TICK_FROM_MS(v));
885 return bl;