packetizer: hxxx: fix DirectTV extraction
[vlc.git] / modules / demux / adaptive / PlaylistManager.cpp
blob3ee5014ae0d1b0faddc65d3af55412178cc24d55
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 "playlist/AbstractPlaylist.hpp"
29 #include "playlist/BasePeriod.h"
30 #include "playlist/BaseAdaptationSet.h"
31 #include "playlist/BaseRepresentation.h"
32 #include "http/HTTPConnectionManager.h"
33 #include "logic/AlwaysBestAdaptationLogic.h"
34 #include "logic/RateBasedAdaptationLogic.h"
35 #include "logic/AlwaysLowestAdaptationLogic.hpp"
36 #include "logic/PredictiveAdaptationLogic.hpp"
37 #include "logic/NearOptimalAdaptationLogic.hpp"
38 #include "tools/Debug.hpp"
39 #include <vlc_stream.h>
40 #include <vlc_demux.h>
41 #include <vlc_threads.h>
43 #include <algorithm>
44 #include <ctime>
46 using namespace adaptive::http;
47 using namespace adaptive::logic;
48 using namespace adaptive;
50 PlaylistManager::PlaylistManager( demux_t *p_demux_,
51 AbstractPlaylist *pl,
52 AbstractStreamFactory *factory,
53 AbstractAdaptationLogic::LogicType type ) :
54 conManager ( NULL ),
55 logicType ( type ),
56 logic ( NULL ),
57 playlist ( pl ),
58 streamFactory ( factory ),
59 p_demux ( p_demux_ )
61 currentPeriod = playlist->getFirstPeriod();
62 failedupdates = 0;
63 b_thread = false;
64 b_buffering = false;
65 nextPlaylistupdate = 0;
66 demux.i_nzpcr = VLC_TS_INVALID;
67 demux.i_firstpcr = VLC_TS_INVALID;
68 vlc_mutex_init(&demux.lock);
69 vlc_cond_init(&demux.cond);
70 vlc_mutex_init(&lock);
71 vlc_cond_init(&waitcond);
72 vlc_mutex_init(&cached.lock);
73 cached.b_live = false;
74 cached.i_length = 0;
75 cached.f_position = 0.0;
76 cached.i_time = VLC_TS_INVALID;
79 PlaylistManager::~PlaylistManager ()
81 delete streamFactory;
82 unsetPeriod();
83 delete playlist;
84 delete conManager;
85 delete logic;
86 vlc_cond_destroy(&waitcond);
87 vlc_mutex_destroy(&lock);
88 vlc_mutex_destroy(&demux.lock);
89 vlc_cond_destroy(&demux.cond);
90 vlc_mutex_destroy(&cached.lock);
93 void PlaylistManager::unsetPeriod()
95 std::vector<AbstractStream *>::iterator it;
96 for(it=streams.begin(); it!=streams.end(); ++it)
97 delete *it;
98 streams.clear();
101 bool PlaylistManager::setupPeriod()
103 if(!currentPeriod)
104 return false;
106 if(!logic && !(logic = createLogic(logicType, conManager)))
107 return false;
109 std::vector<BaseAdaptationSet*> sets = currentPeriod->getAdaptationSets();
110 std::vector<BaseAdaptationSet*>::iterator it;
111 for(it=sets.begin();it!=sets.end();++it)
113 BaseAdaptationSet *set = *it;
114 if(set && streamFactory)
116 SegmentTracker *tracker = new (std::nothrow) SegmentTracker(logic, set);
117 if(!tracker)
118 continue;
120 AbstractStream *st = streamFactory->create(p_demux, set->getStreamFormat(),
121 tracker, conManager);
122 if(!st)
124 delete tracker;
125 continue;
128 streams.push_back(st);
130 /* Generate stream description */
131 std::list<std::string> languages;
132 if(!set->getLang().empty())
134 languages = set->getLang();
136 else if(!set->getRepresentations().empty())
138 languages = set->getRepresentations().front()->getLang();
141 if(!languages.empty())
142 st->setLanguage(languages.front());
144 if(!set->description.Get().empty())
145 st->setDescription(set->description.Get());
148 return true;
151 bool PlaylistManager::start()
153 if(!conManager && !(conManager = new (std::nothrow) HTTPConnectionManager(VLC_OBJECT(p_demux->s))))
154 return false;
156 if(!setupPeriod())
157 return false;
159 playlist->playbackStart.Set(time(NULL));
160 nextPlaylistupdate = playlist->playbackStart.Get();
162 updateControlsContentType();
163 updateControlsPosition();
165 b_thread = !vlc_clone(&thread, managerThread,
166 static_cast<void *>(this), VLC_THREAD_PRIORITY_INPUT);
167 if(!b_thread)
168 return false;
170 setBufferingRunState(true);
172 return true;
175 void PlaylistManager::stop()
177 if(b_thread)
179 vlc_cancel(thread);
180 vlc_join(thread, NULL);
181 b_thread = false;
185 struct PrioritizedAbstractStream
187 AbstractStream::buffering_status status;
188 mtime_t demuxed_amount;
189 AbstractStream *st;
192 static bool streamCompare(PrioritizedAbstractStream a, PrioritizedAbstractStream b)
194 if( a.status >= b.status ) /* Highest prio is higer value in enum */
196 if ( a.status == b.status ) /* Highest prio is lowest buffering */
197 return a.demuxed_amount < b.demuxed_amount;
198 else
199 return true;
201 return false;
204 AbstractStream::buffering_status PlaylistManager::bufferize(mtime_t i_nzdeadline,
205 unsigned i_min_buffering, unsigned i_extra_buffering)
207 AbstractStream::buffering_status i_return = AbstractStream::buffering_end;
209 /* First reorder by status >> buffering level */
210 std::vector<PrioritizedAbstractStream> prioritized_streams(streams.size());
211 std::vector<PrioritizedAbstractStream>::iterator it = prioritized_streams.begin();
212 std::vector<AbstractStream *>::iterator sit = streams.begin();
213 for( ; sit!=streams.end(); ++sit)
215 PrioritizedAbstractStream &p = *it;
216 p.st = *sit;
217 p.status = p.st->getLastBufferStatus();
218 p.demuxed_amount = p.st->getDemuxedAmount();
219 ++it;
221 std::sort(prioritized_streams.begin(), prioritized_streams.end(), streamCompare);
223 for(it=prioritized_streams.begin(); it!=prioritized_streams.end(); ++it)
225 AbstractStream *st = (*it).st;
227 if (st->isDisabled() &&
228 (!st->isSelected() || !st->canActivate() || !reactivateStream(st)))
229 continue;
231 AbstractStream::buffering_status i_ret = st->bufferize(i_nzdeadline, i_min_buffering, i_extra_buffering);
232 if(i_return != AbstractStream::buffering_ongoing) /* Buffering streams need to keep going */
234 if(i_ret > i_return)
235 i_return = i_ret;
238 /* Bail out, will start again (high prio could be same starving stream) */
239 if( i_return == AbstractStream::buffering_lessthanmin )
240 break;
243 vlc_mutex_lock(&demux.lock);
244 if(demux.i_nzpcr == VLC_TS_INVALID &&
245 i_return != AbstractStream::buffering_lessthanmin /* prevents starting before buffering is reached */ )
247 demux.i_nzpcr = getFirstDTS();
249 vlc_mutex_unlock(&demux.lock);
251 return i_return;
254 AbstractStream::status PlaylistManager::dequeue(mtime_t i_floor, mtime_t *pi_nzbarrier)
256 AbstractStream::status i_return = AbstractStream::status_eof;
258 const mtime_t i_nzdeadline = *pi_nzbarrier;
260 std::vector<AbstractStream *>::iterator it;
261 for(it=streams.begin(); it!=streams.end(); ++it)
263 AbstractStream *st = *it;
265 mtime_t i_pcr;
266 AbstractStream::status i_ret = st->dequeue(i_nzdeadline, &i_pcr);
267 if( i_ret > i_return )
268 i_return = i_ret;
270 if( i_pcr > i_floor )
271 *pi_nzbarrier = std::min( *pi_nzbarrier, i_pcr - VLC_TS_0 );
274 return i_return;
277 void PlaylistManager::drain()
279 for(;;)
281 bool b_drained = true;
282 std::vector<AbstractStream *>::iterator it;
283 for(it=streams.begin(); it!=streams.end(); ++it)
285 AbstractStream *st = *it;
287 if (st->isDisabled())
288 continue;
290 b_drained &= st->decodersDrained();
293 if(b_drained)
294 break;
296 msleep(20*1000); /* ugly, but we have no way to get feedback */
298 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
301 mtime_t PlaylistManager::getPCR() const
303 mtime_t minpcr = VLC_TS_INVALID;
304 std::vector<AbstractStream *>::const_iterator it;
305 for(it=streams.begin(); it!=streams.end(); ++it)
307 const mtime_t pcr = (*it)->getPCR();
308 if(minpcr == VLC_TS_INVALID)
309 minpcr = pcr;
310 else if(pcr > VLC_TS_INVALID)
311 minpcr = std::min(minpcr, pcr);
313 return minpcr;
316 mtime_t PlaylistManager::getFirstDTS() const
318 mtime_t mindts = VLC_TS_INVALID;
319 std::vector<AbstractStream *>::const_iterator it;
320 for(it=streams.begin(); it!=streams.end(); ++it)
322 const mtime_t dts = (*it)->getFirstDTS();
323 if(mindts == VLC_TS_INVALID)
324 mindts = dts;
325 else if(dts > VLC_TS_INVALID)
326 mindts = std::min(mindts, dts);
328 return mindts;
331 mtime_t PlaylistManager::getDuration() const
333 if (playlist->isLive())
334 return 0;
335 else
336 return playlist->duration.Get();
339 bool PlaylistManager::setPosition(mtime_t time)
341 bool ret = true;
342 for(int real = 0; real < 2; real++)
344 /* Always probe if we can seek first */
345 std::vector<AbstractStream *>::iterator it;
346 for(it=streams.begin(); it!=streams.end(); ++it)
348 AbstractStream *st = *it;
349 if(!st->isDisabled())
350 ret &= st->setPosition(time, !real);
352 if(!ret)
353 break;
355 return ret;
358 bool PlaylistManager::needsUpdate() const
360 return playlist->isLive() && (failedupdates < 3);
363 void PlaylistManager::scheduleNextUpdate()
368 bool PlaylistManager::updatePlaylist()
370 std::vector<AbstractStream *>::const_iterator it;
371 for(it=streams.begin(); it!=streams.end(); ++it)
372 (*it)->runUpdates();
374 updateControlsContentType();
375 updateControlsPosition();
376 return true;
379 mtime_t PlaylistManager::getFirstPlaybackTime() const
381 return 0;
384 mtime_t PlaylistManager::getCurrentPlaybackTime() const
386 return demux.i_nzpcr;
389 void PlaylistManager::pruneLiveStream()
391 mtime_t minValidPos = 0;
392 std::vector<AbstractStream *>::const_iterator it;
393 for(it=streams.begin(); it!=streams.end(); it++)
395 const AbstractStream *st = *it;
396 if(st->isDisabled() || !st->isSelected())
397 continue;
398 const mtime_t t = st->getPlaybackTime();
399 if(minValidPos == 0 || t < minValidPos)
400 minValidPos = t;
403 if(minValidPos)
404 playlist->pruneByPlaybackTime(minValidPos);
407 bool PlaylistManager::reactivateStream(AbstractStream *stream)
409 return stream->reactivate(getPCR());
412 #define DEMUX_INCREMENT (CLOCK_FREQ / 20)
413 int PlaylistManager::demux_callback(demux_t *p_demux)
415 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
416 return manager->doDemux(DEMUX_INCREMENT);
419 int PlaylistManager::doDemux(int64_t increment)
421 vlc_mutex_lock(&demux.lock);
422 if(demux.i_nzpcr == VLC_TS_INVALID)
424 bool b_dead = true;
425 std::vector<AbstractStream *>::const_iterator it;
426 for(it=streams.begin(); it!=streams.end(); ++it)
427 b_dead &= !(*it)->canActivate();
428 if(!b_dead)
429 vlc_cond_timedwait(&demux.cond, &demux.lock, mdate() + CLOCK_FREQ / 20);
430 vlc_mutex_unlock(&demux.lock);
431 return (b_dead) ? AbstractStream::status_eof : AbstractStream::status_buffering;
434 if(demux.i_firstpcr == VLC_TS_INVALID)
435 demux.i_firstpcr = demux.i_nzpcr;
437 mtime_t i_nzbarrier = demux.i_nzpcr + increment;
438 vlc_mutex_unlock(&demux.lock);
440 AbstractStream::status status = dequeue(demux.i_nzpcr, &i_nzbarrier);
442 updateControlsContentType();
443 updateControlsPosition();
445 switch(status)
447 case AbstractStream::status_eof:
449 /* might be end of current period */
450 if(currentPeriod)
452 setBufferingRunState(false);
453 BasePeriod *nextPeriod = playlist->getNextPeriod(currentPeriod);
454 if(!nextPeriod)
455 return VLC_DEMUXER_EOF;
456 unsetPeriod();
457 currentPeriod = nextPeriod;
458 if (!setupPeriod())
459 return VLC_DEMUXER_EOF;
461 demux.i_nzpcr = VLC_TS_INVALID;
462 demux.i_firstpcr = VLC_TS_INVALID;
463 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
465 setBufferingRunState(true);
468 break;
469 case AbstractStream::status_buffering:
470 vlc_mutex_lock(&demux.lock);
471 vlc_cond_timedwait(&demux.cond, &demux.lock, mdate() + CLOCK_FREQ / 20);
472 vlc_mutex_unlock(&demux.lock);
473 break;
474 case AbstractStream::status_discontinuity:
475 vlc_mutex_lock(&demux.lock);
476 demux.i_nzpcr = VLC_TS_INVALID;
477 demux.i_firstpcr = VLC_TS_INVALID;
478 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
479 vlc_mutex_unlock(&demux.lock);
480 break;
481 case AbstractStream::status_demuxed:
482 vlc_mutex_lock(&demux.lock);
483 if( demux.i_nzpcr != VLC_TS_INVALID && i_nzbarrier != demux.i_nzpcr )
485 demux.i_nzpcr = i_nzbarrier;
486 mtime_t pcr = VLC_TS_0 + std::max(INT64_C(0), demux.i_nzpcr - CLOCK_FREQ / 10);
487 es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, 0, pcr);
489 vlc_mutex_unlock(&demux.lock);
490 break;
493 return VLC_DEMUXER_SUCCESS;
496 int PlaylistManager::control_callback(demux_t *p_demux, int i_query, va_list args)
498 PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
499 return manager->doControl(i_query, args);
502 int PlaylistManager::doControl(int i_query, va_list args)
504 switch (i_query)
506 case DEMUX_CAN_SEEK:
508 vlc_mutex_locker locker(&cached.lock);
509 *(va_arg (args, bool *)) = ! cached.b_live;
510 break;
513 case DEMUX_CAN_CONTROL_PACE:
514 *(va_arg (args, bool *)) = true;
515 break;
517 case DEMUX_CAN_PAUSE:
519 /* Always return true then fail late.
520 * See demux.c/demux_vaControl,
521 * misleading and should be DEMUX_CAN_CONTROL_PAUSE */
522 *(va_arg (args, bool *)) = true;
523 break;
526 case DEMUX_SET_PAUSE_STATE:
528 vlc_mutex_locker locker(&cached.lock);
529 return cached.b_live ? VLC_EGENERIC : VLC_SUCCESS;
532 case DEMUX_GET_TIME:
534 vlc_mutex_locker locker(&cached.lock);
535 *(va_arg (args, int64_t *)) = cached.i_time;
536 break;
539 case DEMUX_GET_LENGTH:
541 vlc_mutex_locker locker(&cached.lock);
542 if(cached.b_live)
543 return VLC_EGENERIC;
544 *(va_arg (args, int64_t *)) = cached.i_length;
545 break;
548 case DEMUX_GET_POSITION:
550 vlc_mutex_locker locker(&cached.lock);
551 if(cached.b_live)
552 return VLC_EGENERIC;
553 *(va_arg (args, double *)) = cached.f_position;
554 break;
557 case DEMUX_SET_POSITION:
559 setBufferingRunState(false); /* stop downloader first */
561 const mtime_t i_duration = getDuration();
562 if(i_duration == 0) /* == playlist->isLive() */
564 setBufferingRunState(true);
565 return VLC_EGENERIC;
568 int64_t time = i_duration * va_arg(args, double);
569 time += getFirstPlaybackTime();
571 if(!setPosition(time))
573 setBufferingRunState(true);
574 return VLC_EGENERIC;
577 demux.i_nzpcr = VLC_TS_INVALID;
578 setBufferingRunState(true);
579 break;
582 case DEMUX_SET_TIME:
584 setBufferingRunState(false); /* stop downloader first */
585 if(playlist->isLive())
587 setBufferingRunState(true);
588 return VLC_EGENERIC;
591 int64_t time = va_arg(args, int64_t);// + getFirstPlaybackTime();
592 if(!setPosition(time))
594 setBufferingRunState(true);
595 return VLC_EGENERIC;
598 demux.i_nzpcr = VLC_TS_INVALID;
599 setBufferingRunState(true);
600 break;
603 case DEMUX_GET_PTS_DELAY:
604 *va_arg (args, int64_t *) = 1000 * INT64_C(1000);
605 break;
607 default:
608 return VLC_EGENERIC;
610 return VLC_SUCCESS;
613 void PlaylistManager::setBufferingRunState(bool b)
615 vlc_mutex_lock(&lock);
616 b_buffering = b;
617 vlc_cond_signal(&waitcond);
618 vlc_mutex_unlock(&lock);
621 void PlaylistManager::Run()
623 vlc_mutex_lock(&lock);
624 const unsigned i_min_buffering = playlist->getMinBuffering();
625 const unsigned i_extra_buffering = playlist->getMaxBuffering() - i_min_buffering;
626 while(1)
628 mutex_cleanup_push(&lock);
629 while(!b_buffering)
630 vlc_cond_wait(&waitcond, &lock);
631 vlc_testcancel();
632 vlc_cleanup_pop();
634 if(needsUpdate())
636 if(updatePlaylist())
637 scheduleNextUpdate();
638 else
639 failedupdates++;
642 vlc_mutex_lock(&demux.lock);
643 mtime_t i_nzpcr = demux.i_nzpcr;
644 vlc_mutex_unlock(&demux.lock);
646 int canc = vlc_savecancel();
647 AbstractStream::buffering_status i_return = bufferize(i_nzpcr, i_min_buffering, i_extra_buffering);
648 vlc_restorecancel( canc );
650 if(i_return != AbstractStream::buffering_lessthanmin)
652 mtime_t i_deadline = mdate();
653 if(i_return == AbstractStream::buffering_ongoing)
654 i_deadline += (CLOCK_FREQ / 20);
655 else if(i_return == AbstractStream::buffering_full)
656 i_deadline += (CLOCK_FREQ / 10);
657 else if(i_return == AbstractStream::buffering_end)
658 i_deadline += (CLOCK_FREQ);
659 else /*if(i_return == AbstractStream::buffering_suspended)*/
660 i_deadline += (CLOCK_FREQ / 4);
662 vlc_mutex_lock(&demux.lock);
663 vlc_cond_signal(&demux.cond);
664 vlc_mutex_unlock(&demux.lock);
666 mutex_cleanup_push(&lock);
667 while(b_buffering &&
668 vlc_cond_timedwait(&waitcond, &lock, i_deadline) == 0 &&
669 i_deadline > mdate());
670 vlc_cleanup_pop();
673 vlc_mutex_unlock(&lock);
676 void * PlaylistManager::managerThread(void *opaque)
678 static_cast<PlaylistManager *>(opaque)->Run();
679 return NULL;
682 void PlaylistManager::updateControlsPosition()
684 vlc_mutex_locker locker(&cached.lock);
685 const mtime_t i_duration = cached.i_length;
686 if(i_duration == 0)
688 cached.f_position = 0.0;
690 else
692 const mtime_t i_length = getCurrentPlaybackTime() - getFirstPlaybackTime();
693 cached.f_position = (double) i_length / i_duration;
696 mtime_t i_time = getCurrentPlaybackTime();
697 if(!playlist->isLive())
698 i_time -= getFirstPlaybackTime();
699 cached.i_time = i_time;
702 void PlaylistManager::updateControlsContentType()
704 vlc_mutex_locker locker(&cached.lock);
705 if(playlist->isLive())
707 cached.b_live = true;
708 cached.i_length = 0;
710 else
712 cached.b_live = false;
713 cached.i_length = getDuration();
717 AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn)
719 AbstractAdaptationLogic *logic = NULL;
720 switch(type)
722 case AbstractAdaptationLogic::FixedRate:
724 size_t bps = var_InheritInteger(p_demux, "adaptive-bw") * 8192;
725 logic = new (std::nothrow) FixedRateAdaptationLogic(bps);
726 break;
728 case AbstractAdaptationLogic::AlwaysLowest:
729 logic = new (std::nothrow) AlwaysLowestAdaptationLogic();
730 break;
731 case AbstractAdaptationLogic::AlwaysBest:
732 logic = new (std::nothrow) AlwaysBestAdaptationLogic();
733 break;
734 case AbstractAdaptationLogic::RateBased:
736 RateBasedAdaptationLogic *ratelogic =
737 new (std::nothrow) RateBasedAdaptationLogic(VLC_OBJECT(p_demux));
738 if(ratelogic)
739 conn->setDownloadRateObserver(ratelogic);
740 logic = ratelogic;
741 break;
743 case AbstractAdaptationLogic::Default:
744 case AbstractAdaptationLogic::NearOptimal:
746 NearOptimalAdaptationLogic *noplogic =
747 new (std::nothrow) NearOptimalAdaptationLogic(VLC_OBJECT(p_demux));
748 if(noplogic)
749 conn->setDownloadRateObserver(noplogic);
750 logic = noplogic;
751 break;
753 case AbstractAdaptationLogic::Predictive:
755 AbstractAdaptationLogic *predictivelogic =
756 new (std::nothrow) PredictiveAdaptationLogic(VLC_OBJECT(p_demux));
757 if(predictivelogic)
758 conn->setDownloadRateObserver(predictivelogic);
759 logic = predictivelogic;
762 default:
763 break;
766 if(logic)
768 logic->setMaxDeviceResolution( var_InheritInteger(p_demux, "adaptive-maxwidth"),
769 var_InheritInteger(p_demux, "adaptive-maxheight") );
772 return logic;