thread: remove vlc_cond_destroy()
[vlc.git] / modules / demux / adaptive / PlaylistManager.cpp
blobce6da8e5dd750157e468820c8dbf72e40e21feb1
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/AbstractPlaylist.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 "tools/Debug.hpp"
40 #include <vlc_stream.h>
41 #include <vlc_demux.h>
42 #include <vlc_threads.h>
44 #include <algorithm>
45 #include <ctime>
47 using namespace adaptive::http;
48 using namespace adaptive::logic;
49 using namespace adaptive;
51 PlaylistManager::PlaylistManager( demux_t *p_demux_,
52 SharedResources *res,
53 AbstractPlaylist *pl,
54 AbstractStreamFactory *factory,
55 AbstractAdaptationLogic::LogicType type ) :
56 logicType ( type ),
57 logic ( NULL ),
58 playlist ( pl ),
59 streamFactory ( factory ),
60 p_demux ( p_demux_ )
62 currentPeriod = playlist->getFirstPeriod();
63 resources = res;
64 failedupdates = 0;
65 b_thread = false;
66 b_buffering = false;
67 b_canceled = false;
68 nextPlaylistupdate = 0;
69 demux.i_nzpcr = VLC_TICK_INVALID;
70 demux.i_firstpcr = VLC_TICK_INVALID;
71 vlc_mutex_init(&demux.lock);
72 vlc_cond_init(&demux.cond);
73 vlc_mutex_init(&lock);
74 vlc_cond_init(&waitcond);
75 vlc_mutex_init(&cached.lock);
76 cached.b_live = false;
77 cached.f_position = 0.0;
78 cached.i_time = VLC_TICK_INVALID;
79 cached.playlistStart = 0;
80 cached.playlistEnd = 0;
81 cached.playlistLength = 0;
82 cached.lastupdate = 0;
85 PlaylistManager::~PlaylistManager ()
87 delete streamFactory;
88 unsetPeriod();
89 delete playlist;
90 delete logic;
91 delete resources;
94 void PlaylistManager::unsetPeriod()
96 std::vector<AbstractStream *>::iterator it;
97 for(it=streams.begin(); it!=streams.end(); ++it)
98 delete *it;
99 streams.clear();
102 bool PlaylistManager::setupPeriod()
104 if(!currentPeriod)
105 return false;
107 if(!logic && !(logic = createLogic(logicType, resources->getConnManager())))
108 return false;
110 std::vector<BaseAdaptationSet*> sets = currentPeriod->getAdaptationSets();
111 std::vector<BaseAdaptationSet*>::iterator it;
112 for(it=sets.begin();it!=sets.end();++it)
114 BaseAdaptationSet *set = *it;
115 if(set && streamFactory)
117 SegmentTracker *tracker = new SegmentTracker(resources, logic, set);
118 if(!tracker)
119 continue;
121 AbstractStream *st = streamFactory->create(p_demux, set->getStreamFormat(),
122 tracker, resources->getConnManager());
123 if(!st)
125 delete tracker;
126 continue;
129 streams.push_back(st);
131 /* Generate stream description */
132 if(!set->getLang().empty())
133 st->setLanguage(set->getLang());
135 if(!set->description.Get().empty())
136 st->setDescription(set->description.Get());
139 return true;
142 bool PlaylistManager::init()
144 if(!setupPeriod())
145 return false;
147 playlist->playbackStart.Set(time(NULL));
148 nextPlaylistupdate = playlist->playbackStart.Get();
150 updateControlsPosition();
152 return true;
155 bool PlaylistManager::start()
157 if(b_thread)
158 return false;
160 b_thread = !vlc_clone(&thread, managerThread,
161 static_cast<void *>(this), VLC_THREAD_PRIORITY_INPUT);
162 if(!b_thread)
163 return false;
165 setBufferingRunState(true);
167 return true;
170 bool PlaylistManager::started() const
172 return b_thread;
175 void PlaylistManager::stop()
177 if(b_thread)
179 vlc_mutex_lock(&lock);
180 b_canceled = true;
181 vlc_cond_signal(&waitcond);
182 vlc_mutex_unlock(&lock);
184 vlc_join(thread, NULL);
185 b_thread = false;
189 struct PrioritizedAbstractStream
191 AbstractStream::buffering_status status;
192 vlc_tick_t demuxed_amount;
193 AbstractStream *st;
196 static bool streamCompare(const PrioritizedAbstractStream &a, const PrioritizedAbstractStream &b)
198 if( a.status >= b.status ) /* Highest prio is higer value in enum */
200 if ( a.status == b.status ) /* Highest prio is lowest buffering */
201 return a.demuxed_amount < b.demuxed_amount;
202 else
203 return true;
205 return false;
208 AbstractStream::buffering_status PlaylistManager::bufferize(vlc_tick_t i_nzdeadline,
209 vlc_tick_t i_min_buffering, vlc_tick_t i_extra_buffering)
211 AbstractStream::buffering_status i_return = AbstractStream::buffering_end;
213 /* First reorder by status >> buffering level */
214 std::vector<PrioritizedAbstractStream> prioritized_streams(streams.size());
215 std::vector<PrioritizedAbstractStream>::iterator it = prioritized_streams.begin();
216 std::vector<AbstractStream *>::iterator sit = streams.begin();
217 for( ; sit!=streams.end(); ++sit)
219 PrioritizedAbstractStream &p = *it;
220 p.st = *sit;
221 p.status = p.st->getLastBufferStatus();
222 p.demuxed_amount = p.st->getDemuxedAmount();
223 ++it;
225 std::sort(prioritized_streams.begin(), prioritized_streams.end(), streamCompare);
227 for(it=prioritized_streams.begin(); it!=prioritized_streams.end(); ++it)
229 AbstractStream *st = (*it).st;
231 if(!st->isValid())
232 continue;
234 if(st->esCount())
236 if (st->isDisabled() &&
237 (!st->isSelected() || !reactivateStream(st)))
238 continue;
240 else
242 /* initial */
245 AbstractStream::buffering_status i_ret = st->bufferize(i_nzdeadline, i_min_buffering, i_extra_buffering);
246 if(i_return != AbstractStream::buffering_ongoing) /* Buffering streams need to keep going */
248 if(i_ret > i_return)
249 i_return = i_ret;
252 /* Bail out, will start again (high prio could be same starving stream) */
253 if( i_return == AbstractStream::buffering_lessthanmin )
254 break;
257 vlc_mutex_lock(&demux.lock);
258 if(demux.i_nzpcr == VLC_TICK_INVALID &&
259 i_return != AbstractStream::buffering_lessthanmin /* prevents starting before buffering is reached */ )
261 demux.i_nzpcr = getFirstDTS();
263 vlc_mutex_unlock(&demux.lock);
265 return i_return;
268 AbstractStream::status PlaylistManager::dequeue(vlc_tick_t i_floor, vlc_tick_t *pi_nzbarrier)
270 AbstractStream::status i_return = AbstractStream::status_eof;
272 const vlc_tick_t i_nzdeadline = *pi_nzbarrier;
274 std::vector<AbstractStream *>::iterator it;
275 for(it=streams.begin(); it!=streams.end(); ++it)
277 AbstractStream *st = *it;
279 vlc_tick_t i_pcr;
280 AbstractStream::status i_ret = st->dequeue(i_nzdeadline, &i_pcr);
281 if( i_ret > i_return )
282 i_return = i_ret;
284 if( i_pcr > i_floor )
285 *pi_nzbarrier = std::min( *pi_nzbarrier, i_pcr - VLC_TICK_0 );
288 return i_return;
291 void PlaylistManager::drain()
293 for(;;)
295 bool b_drained = true;
296 std::vector<AbstractStream *>::iterator it;
297 for(it=streams.begin(); it!=streams.end(); ++it)
299 AbstractStream *st = *it;
301 if (!st->isValid() || st->isDisabled())
302 continue;
304 b_drained &= st->decodersDrained();
307 if(b_drained)
308 break;
310 vlc_tick_sleep(VLC_TICK_FROM_MS(20)); /* ugly, but we have no way to get feedback */
312 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
315 vlc_tick_t PlaylistManager::getResumeTime() const
317 vlc_mutex_locker locker(&demux.lock);
318 return demux.i_nzpcr;
321 vlc_tick_t PlaylistManager::getFirstDTS() const
323 vlc_tick_t mindts = VLC_TICK_INVALID;
324 std::vector<AbstractStream *>::const_iterator it;
325 for(it=streams.begin(); it!=streams.end(); ++it)
327 const vlc_tick_t dts = (*it)->getFirstDTS();
328 if(mindts == VLC_TICK_INVALID)
329 mindts = dts;
330 else if(dts != VLC_TICK_INVALID)
331 mindts = std::min(mindts, dts);
333 return mindts;
336 bool PlaylistManager::setPosition(vlc_tick_t time)
338 bool ret = true;
339 bool hasValidStream = false;
340 for(int real = 0; real < 2; real++)
342 /* Always probe if we can seek first */
343 std::vector<AbstractStream *>::iterator it;
344 for(it=streams.begin(); it!=streams.end(); ++it)
346 AbstractStream *st = *it;
347 if(st->isValid() && !st->isDisabled())
349 hasValidStream = true;
350 ret &= st->setPosition(time, !real);
353 if(!ret)
354 break;
356 if(!hasValidStream)
358 msg_Warn(p_demux, "there is no valid streams");
359 ret = false;
361 return ret;
364 bool PlaylistManager::needsUpdate() const
366 return playlist->needsUpdates() &&
367 playlist->isLive() && (failedupdates < 3);
370 void PlaylistManager::scheduleNextUpdate()
375 bool PlaylistManager::updatePlaylist()
377 std::vector<AbstractStream *>::const_iterator it;
378 for(it=streams.begin(); it!=streams.end(); ++it)
379 (*it)->runUpdates();
381 updateControlsPosition();
382 return true;
385 vlc_tick_t PlaylistManager::getFirstPlaybackTime() const
387 return 0;
390 vlc_tick_t PlaylistManager::getCurrentDemuxTime() const
392 vlc_mutex_locker locker(&demux.lock);
393 return demux.i_nzpcr;
396 bool PlaylistManager::reactivateStream(AbstractStream *stream)
398 return stream->reactivate(getResumeTime());
401 #define DEMUX_INCREMENT VLC_TICK_FROM_MS(50)
402 int PlaylistManager::demux_callback(demux_t *p_demux)
404 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
405 if(!manager->started() && !manager->start())
406 return VLC_DEMUXER_EOF;
407 return manager->doDemux(DEMUX_INCREMENT);
410 int PlaylistManager::doDemux(vlc_tick_t increment)
412 vlc_mutex_lock(&demux.lock);
413 if(demux.i_nzpcr == VLC_TICK_INVALID)
415 bool b_dead = true;
416 bool b_all_disabled = true;
417 std::vector<AbstractStream *>::const_iterator it;
418 for(it=streams.begin(); it!=streams.end(); ++it)
420 b_dead &= !(*it)->isValid();
421 b_all_disabled &= (*it)->isDisabled();
423 if(!b_dead)
424 vlc_cond_timedwait(&demux.cond, &demux.lock, vlc_tick_now() + VLC_TICK_FROM_MS(50));
425 vlc_mutex_unlock(&demux.lock);
426 return (b_dead || b_all_disabled) ? AbstractStream::status_eof : AbstractStream::status_buffering;
429 if(demux.i_firstpcr == VLC_TICK_INVALID)
430 demux.i_firstpcr = demux.i_nzpcr;
432 vlc_tick_t i_nzbarrier = demux.i_nzpcr + increment;
433 vlc_mutex_unlock(&demux.lock);
435 AbstractStream::status status = dequeue(demux.i_nzpcr, &i_nzbarrier);
437 updateControlsPosition();
439 switch(status)
441 case AbstractStream::status_eof:
443 /* might be end of current period */
444 if(currentPeriod)
446 setBufferingRunState(false);
447 BasePeriod *nextPeriod = playlist->getNextPeriod(currentPeriod);
448 if(!nextPeriod)
449 return VLC_DEMUXER_EOF;
450 unsetPeriod();
451 currentPeriod = nextPeriod;
452 if (!setupPeriod())
453 return VLC_DEMUXER_EOF;
455 demux.i_nzpcr = VLC_TICK_INVALID;
456 demux.i_firstpcr = VLC_TICK_INVALID;
457 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
459 setBufferingRunState(true);
462 break;
463 case AbstractStream::status_buffering:
464 vlc_mutex_lock(&demux.lock);
465 vlc_cond_timedwait(&demux.cond, &demux.lock, vlc_tick_now() + VLC_TICK_FROM_MS(50));
466 vlc_mutex_unlock(&demux.lock);
467 break;
468 case AbstractStream::status_discontinuity:
469 vlc_mutex_lock(&demux.lock);
470 demux.i_nzpcr = VLC_TICK_INVALID;
471 demux.i_firstpcr = VLC_TICK_INVALID;
472 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
473 vlc_mutex_unlock(&demux.lock);
474 break;
475 case AbstractStream::status_demuxed:
476 vlc_mutex_lock(&demux.lock);
477 if( demux.i_nzpcr != VLC_TICK_INVALID && i_nzbarrier != demux.i_nzpcr )
479 demux.i_nzpcr = i_nzbarrier;
480 vlc_tick_t pcr = VLC_TICK_0 + std::max(INT64_C(0), demux.i_nzpcr - VLC_TICK_FROM_MS(100));
481 es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, 0, pcr);
483 vlc_mutex_unlock(&demux.lock);
484 break;
487 return VLC_DEMUXER_SUCCESS;
490 int PlaylistManager::control_callback(demux_t *p_demux, int i_query, va_list args)
492 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
493 return manager->doControl(i_query, args);
496 int PlaylistManager::doControl(int i_query, va_list args)
498 switch (i_query)
500 case DEMUX_CAN_SEEK:
501 case DEMUX_CAN_CONTROL_PACE:
502 *(va_arg (args, bool *)) = true;
503 break;
505 case DEMUX_CAN_PAUSE:
507 /* Always return true then fail late.
508 * See demux.c/demux_vaControl,
509 * misleading and should be DEMUX_CAN_CONTROL_PAUSE */
510 *(va_arg (args, bool *)) = true;
511 break;
514 case DEMUX_SET_PAUSE_STATE:
516 vlc_mutex_locker locker(&cached.lock);
517 return cached.b_live ? VLC_EGENERIC : VLC_SUCCESS;
520 case DEMUX_GET_TIME:
522 vlc_mutex_locker locker(&cached.lock);
523 *(va_arg (args, vlc_tick_t *)) = cached.i_time;
524 break;
527 case DEMUX_GET_LENGTH:
529 vlc_mutex_locker locker(&cached.lock);
530 if(cached.b_live && cached.playlistLength == 0)
531 return VLC_EGENERIC;
532 *(va_arg (args, vlc_tick_t *)) = cached.playlistLength;
533 break;
536 case DEMUX_GET_POSITION:
538 vlc_mutex_locker locker(&cached.lock);
539 if(cached.b_live && cached.playlistLength == 0)
540 return VLC_EGENERIC;
541 *(va_arg (args, double *)) = cached.f_position;
542 break;
545 case DEMUX_SET_POSITION:
547 setBufferingRunState(false); /* stop downloader first */
548 vlc_mutex_locker locker(&cached.lock);
550 if(cached.playlistLength == 0)
552 setBufferingRunState(true);
553 return VLC_EGENERIC;
556 double pos = va_arg(args, double);
557 vlc_tick_t seekTime = cached.playlistStart + cached.playlistLength * pos;
559 SeekDebug(msg_Dbg(p_demux, "Seek %f to %ld plstart %ld duration %ld",
560 pos, seekTime, cached.playlistEnd, cached.playlistLength));
562 if(!setPosition(seekTime))
564 setBufferingRunState(true);
565 return VLC_EGENERIC;
568 demux.i_nzpcr = VLC_TICK_INVALID;
569 cached.lastupdate = 0;
570 setBufferingRunState(true);
571 break;
574 case DEMUX_SET_TIME:
576 setBufferingRunState(false); /* stop downloader first */
578 vlc_tick_t time = va_arg(args, vlc_tick_t);// + getFirstPlaybackTime();
579 if(!setPosition(time))
581 setBufferingRunState(true);
582 return VLC_EGENERIC;
585 vlc_mutex_locker locker(&cached.lock);
586 demux.i_nzpcr = VLC_TICK_INVALID;
587 cached.lastupdate = 0;
588 setBufferingRunState(true);
589 break;
592 case DEMUX_GET_PTS_DELAY:
593 *va_arg (args, vlc_tick_t *) = VLC_TICK_FROM_SEC(1);
594 break;
596 default:
597 return VLC_EGENERIC;
599 return VLC_SUCCESS;
602 void PlaylistManager::setBufferingRunState(bool b)
604 vlc_mutex_lock(&lock);
605 b_buffering = b;
606 vlc_cond_signal(&waitcond);
607 vlc_mutex_unlock(&lock);
610 void PlaylistManager::Run()
612 vlc_mutex_lock(&lock);
613 const vlc_tick_t i_min_buffering = playlist->getMinBuffering();
614 const vlc_tick_t i_extra_buffering = playlist->getMaxBuffering() - i_min_buffering;
615 while(1)
617 while(!b_buffering && !b_canceled)
618 vlc_cond_wait(&waitcond, &lock);
619 if (b_canceled)
620 break;
622 if(needsUpdate())
624 int canc = vlc_savecancel();
625 if(updatePlaylist())
626 scheduleNextUpdate();
627 else
628 failedupdates++;
629 vlc_restorecancel(canc);
632 vlc_mutex_lock(&demux.lock);
633 vlc_tick_t i_nzpcr = demux.i_nzpcr;
634 vlc_mutex_unlock(&demux.lock);
636 int canc = vlc_savecancel();
637 AbstractStream::buffering_status i_return = bufferize(i_nzpcr, i_min_buffering, i_extra_buffering);
638 vlc_restorecancel( canc );
640 if(i_return != AbstractStream::buffering_lessthanmin)
642 vlc_tick_t i_deadline = vlc_tick_now();
643 if(i_return == AbstractStream::buffering_ongoing)
644 i_deadline += VLC_TICK_FROM_MS(10);
645 else if(i_return == AbstractStream::buffering_full)
646 i_deadline += VLC_TICK_FROM_MS(100);
647 else if(i_return == AbstractStream::buffering_end)
648 i_deadline += VLC_TICK_FROM_SEC(1);
649 else /*if(i_return == AbstractStream::buffering_suspended)*/
650 i_deadline += VLC_TICK_FROM_MS(250);
652 vlc_mutex_lock(&demux.lock);
653 vlc_cond_signal(&demux.cond);
654 vlc_mutex_unlock(&demux.lock);
656 while(b_buffering &&
657 vlc_cond_timedwait(&waitcond, &lock, i_deadline) == 0 &&
658 i_deadline > vlc_tick_now() &&
659 !b_canceled);
660 if (b_canceled)
661 break;
664 vlc_mutex_unlock(&lock);
667 void * PlaylistManager::managerThread(void *opaque)
669 static_cast<PlaylistManager *>(opaque)->Run();
670 return NULL;
673 void PlaylistManager::updateControlsPosition()
675 vlc_mutex_locker locker(&cached.lock);
677 time_t now = time(NULL);
678 if(now - cached.lastupdate < 1)
679 return;
680 cached.lastupdate = now;
682 vlc_tick_t rapPlaylistStart = 0;
683 vlc_tick_t rapDemuxStart = 0;
684 std::vector<AbstractStream *>::iterator it;
685 for(it=streams.begin(); it!=streams.end(); ++it)
687 AbstractStream *st = *it;
688 if(st->isValid() && !st->isDisabled() && st->isSelected())
690 if(st->getMediaPlaybackTimes(&cached.playlistStart, &cached.playlistEnd,
691 &cached.playlistLength,
692 &rapPlaylistStart, &rapDemuxStart))
693 break;
698 * Relative position:
699 * -> Elapsed demux time (current demux time - first demux time)
700 * Since PlaylistTime != DemuxTime (HLS crap, TS):
701 * -> Use Playlist<->Demux time offset provided by EsOut
702 * to convert to elapsed playlist time.
703 * But this diff is not available until we have demuxed data...
704 * Fallback on relative seek from playlist start in that case
705 * But also playback might not have started at beginning of playlist
706 * -> Apply relative start from seek point (set on EsOut as ExpectedTime)
708 * All seeks need to be done in playlist time !
711 vlc_tick_t currentDemuxTime = getCurrentDemuxTime();
712 cached.b_live = playlist->isLive();
714 SeekDebug(msg_Dbg(p_demux, "playlist Start/End %ld/%ld len %ld"
715 "rap pl/demux (%ld/%ld)",
716 cached.playlistStart, cached.playlistEnd, cached.playlistEnd,
717 rapPlaylistStart, rapDemuxStart));
719 if(cached.b_live)
721 /* Special case for live until we can provide relative start to fully match
722 the above description */
723 cached.i_time = currentDemuxTime;
725 if(cached.playlistStart != cached.playlistEnd)
727 if(cached.playlistStart < 0) /* Live template. Range start = now() - buffering depth */
729 cached.playlistEnd = vlc_tick_from_sec(now);
730 cached.playlistStart = cached.playlistEnd - cached.playlistLength;
733 const vlc_tick_t currentTime = getCurrentDemuxTime();
734 if(currentTime > cached.playlistStart &&
735 currentTime <= cached.playlistEnd && cached.playlistLength)
737 cached.f_position = ((double)(currentTime - cached.playlistStart)) / cached.playlistLength;
739 else
741 cached.f_position = 0.0;
744 else
746 if(playlist->duration.Get() > cached.playlistLength)
747 cached.playlistLength = playlist->duration.Get();
749 if(cached.playlistLength && currentDemuxTime)
751 /* convert to playlist time */
752 vlc_tick_t rapRelOffset = currentDemuxTime - rapDemuxStart; /* offset from start/seek */
753 vlc_tick_t absPlaylistTime = rapPlaylistStart + rapRelOffset; /* converted as abs playlist time */
754 vlc_tick_t relMediaTime = absPlaylistTime - cached.playlistStart; /* elapsed, in playlist time */
755 cached.i_time = absPlaylistTime;
756 cached.f_position = (double) relMediaTime / cached.playlistLength;
758 else
760 cached.f_position = 0.0;
764 SeekDebug(msg_Dbg(p_demux, "cached.i_time (%ld) cur %ld rap start (pl %ld/dmx %ld)",
765 cached.i_time, currentDemuxTime, rapPlaylistStart, rapDemuxStart));
768 AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn)
770 vlc_object_t *obj = VLC_OBJECT(p_demux);
771 AbstractAdaptationLogic *logic = NULL;
772 switch(type)
774 case AbstractAdaptationLogic::FixedRate:
776 size_t bps = var_InheritInteger(p_demux, "adaptive-bw") * 8192;
777 logic = new (std::nothrow) FixedRateAdaptationLogic(obj, bps);
778 break;
780 case AbstractAdaptationLogic::AlwaysLowest:
781 logic = new (std::nothrow) AlwaysLowestAdaptationLogic(obj);
782 break;
783 case AbstractAdaptationLogic::AlwaysBest:
784 logic = new (std::nothrow) AlwaysBestAdaptationLogic(obj);
785 break;
786 case AbstractAdaptationLogic::RateBased:
788 RateBasedAdaptationLogic *ratelogic =
789 new (std::nothrow) RateBasedAdaptationLogic(obj);
790 if(ratelogic)
791 conn->setDownloadRateObserver(ratelogic);
792 logic = ratelogic;
793 break;
795 case AbstractAdaptationLogic::Default:
796 case AbstractAdaptationLogic::NearOptimal:
798 NearOptimalAdaptationLogic *noplogic =
799 new (std::nothrow) NearOptimalAdaptationLogic(obj);
800 if(noplogic)
801 conn->setDownloadRateObserver(noplogic);
802 logic = noplogic;
803 break;
805 case AbstractAdaptationLogic::Predictive:
807 AbstractAdaptationLogic *predictivelogic =
808 new (std::nothrow) PredictiveAdaptationLogic(obj);
809 if(predictivelogic)
810 conn->setDownloadRateObserver(predictivelogic);
811 logic = predictivelogic;
814 default:
815 break;
818 if(logic)
820 logic->setMaxDeviceResolution( var_InheritInteger(p_demux, "adaptive-maxwidth"),
821 var_InheritInteger(p_demux, "adaptive-maxheight") );
824 return logic;