PlaylistManager.cpp 13.9 KB
Newer Older
1
2
3
4
/*
 * PlaylistManager.cpp
 *****************************************************************************
 * Copyright © 2010 - 2011 Klagenfurt University
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
5
 *             2015 VideoLAN and VLC Authors
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "PlaylistManager.h"
#include "SegmentTracker.hpp"
#include "playlist/AbstractPlaylist.hpp"
#include "playlist/BasePeriod.h"
#include "playlist/BaseAdaptationSet.h"
31
#include "playlist/BaseRepresentation.h"
32
33
34
35
#include "http/HTTPConnectionManager.h"
#include "logic/AlwaysBestAdaptationLogic.h"
#include "logic/RateBasedAdaptationLogic.h"
#include "logic/AlwaysLowestAdaptationLogic.hpp"
36
#include "tools/Debug.hpp"
37
#include <vlc_stream.h>
38
#include <vlc_demux.h>
39

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
40
41
#include <ctime>

42
43
44
using namespace adaptive::http;
using namespace adaptive::logic;
using namespace adaptive;
45

46
47
PlaylistManager::PlaylistManager( demux_t *p_demux_,
                                  AbstractPlaylist *pl,
48
                                  AbstractStreamFactory *factory,
49
                                  AbstractAdaptationLogic::LogicType type ) :
50
51
             conManager     ( NULL ),
             logicType      ( type ),
52
             logic          ( NULL ),
53
             playlist       ( pl ),
54
             streamFactory  ( factory ),
55
56
             p_demux        ( p_demux_ ),
             nextPlaylistupdate  ( 0 ),
57
             i_nzpcr        ( VLC_TS_INVALID )
58
{
59
    currentPeriod = playlist->getFirstPeriod();
60
    failedupdates = 0;
61
    i_firstpcr = i_nzpcr;
62
63
64
65
}

PlaylistManager::~PlaylistManager   ()
{
66
    delete streamFactory;
67
    unsetPeriod();
68
    delete playlist;
69
    delete conManager;
70
    delete logic;
71
72
73
74
}

void PlaylistManager::unsetPeriod()
{
75
    std::vector<AbstractStream *>::iterator it;
76
77
78
    for(it=streams.begin(); it!=streams.end(); ++it)
        delete *it;
    streams.clear();
79
80
}

81
bool PlaylistManager::setupPeriod()
82
{
83
    if(!currentPeriod)
84
85
        return false;

86
87
88
    if(!logic && !(logic = createLogic(logicType, conManager)))
        return false;

89
90
91
    std::vector<BaseAdaptationSet*> sets = currentPeriod->getAdaptationSets();
    std::vector<BaseAdaptationSet*>::iterator it;
    for(it=sets.begin();it!=sets.end();++it)
92
    {
93
        BaseAdaptationSet *set = *it;
94
        if(set && streamFactory)
95
        {
96
97
            SegmentTracker *tracker = new (std::nothrow) SegmentTracker(logic, set);
            if(!tracker)
98
99
                continue;

100
            AbstractStream *st = streamFactory->create(p_demux, set->getStreamFormat(),
101
                                                       tracker, conManager);
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            if(!st)
            {
                delete tracker;
                continue;
            }

            streams.push_back(st);

            /* Generate stream description */
            std::list<std::string> languages;
            if(!set->getLang().empty())
            {
                languages = set->getLang();
            }
            else if(!set->getRepresentations().empty())
117
            {
118
                languages = set->getRepresentations().front()->getLang();
119
            }
120
121
122
123
124
125

            if(!languages.empty())
                st->setLanguage(languages.front());

            if(!set->description.Get().empty())
                st->setDescription(set->description.Get());
126
127
        }
    }
128
129
130
    return true;
}

131
bool PlaylistManager::start()
132
{
133
    if(!conManager && !(conManager = new (std::nothrow) HTTPConnectionManager(VLC_OBJECT(p_demux->s))))
134
        return false;
135

136
    if(!setupPeriod())
137
138
139
140
141
142
143
144
        return false;

    playlist->playbackStart.Set(time(NULL));
    nextPlaylistupdate = playlist->playbackStart.Get();

    return true;
}

145
AbstractStream::status PlaylistManager::demux(mtime_t nzdeadline, bool send)
146
{
147
    AbstractStream::status i_return = AbstractStream::status_eof;
148

149
    std::vector<AbstractStream *>::iterator it;
150
    for(it=streams.begin(); it!=streams.end(); ++it)
151
    {
152
        AbstractStream *st = *it;
153
154
155
156

        if (st->isDisabled())
        {
            if(st->isSelected() && !st->isEOF())
157
                reactivateStream(st);
158
159
160
161
            else
                continue;
        }

162
        AbstractStream::status i_ret = st->demux(nzdeadline, send);
163
164
165
166
167
168
        if(i_ret == AbstractStream::status_buffering_ahead ||
           i_return == AbstractStream::status_buffering_ahead)
        {
            i_return = AbstractStream::status_buffering_ahead;
        }
        else if(i_ret == AbstractStream::status_buffering)
169
        {
170
            i_return = AbstractStream::status_buffering;
171
        }
172
173
        else if(i_ret == AbstractStream::status_demuxed &&
                i_return != AbstractStream::status_buffering)
174
        {
175
176
177
178
179
            i_return = AbstractStream::status_demuxed;
        }
        else if(i_ret == AbstractStream::status_dis)
        {
            i_return = AbstractStream::status_dis;
180
        }
181
    }
182

183
    /* might be end of current period */
184
    if(i_return == AbstractStream::status_eof && currentPeriod)
185
186
187
    {
        unsetPeriod();
        currentPeriod = playlist->getNextPeriod(currentPeriod);
188
        i_return = (setupPeriod()) ? AbstractStream::status_eop : AbstractStream::status_eof;
189
190
    }

191
    return i_return;
192
193
194
195
196
}

mtime_t PlaylistManager::getPCR() const
{
    mtime_t pcr = VLC_TS_INVALID;
197
    std::vector<AbstractStream *>::const_iterator it;
198
    for(it=streams.begin(); it!=streams.end(); ++it)
199
    {
200
        if ((*it)->isDisabled() || (*it)->isEOF())
201
            continue;
202
203
        if(pcr == VLC_TS_INVALID || pcr > (*it)->getPCR())
            pcr = (*it)->getPCR();
204
205
206
207
    }
    return pcr;
}

208
209
210
mtime_t PlaylistManager::getFirstDTS() const
{
    mtime_t dts = VLC_TS_INVALID;
211
    std::vector<AbstractStream *>::const_iterator it;
212
    for(it=streams.begin(); it!=streams.end(); ++it)
213
    {
214
        if ((*it)->isDisabled() || (*it)->isEOF())
215
            continue;
216
217
        if(dts == VLC_TS_INVALID || dts > (*it)->getFirstDTS())
            dts = (*it)->getFirstDTS();
218
219
220
221
    }
    return dts;
}

222
223
224
int PlaylistManager::esCount() const
{
    int es = 0;
225
    std::vector<AbstractStream *>::const_iterator it;
226
    for(it=streams.begin(); it!=streams.end(); ++it)
227
    {
228
        es += (*it)->esCount();
229
230
231
232
233
234
235
236
237
    }
    return es;
}

mtime_t PlaylistManager::getDuration() const
{
    if (playlist->isLive())
        return 0;
    else
238
        return playlist->duration.Get();
239
240
241
242
243
244
245
246
}

bool PlaylistManager::setPosition(mtime_t time)
{
    bool ret = true;
    for(int real = 0; real < 2; real++)
    {
        /* Always probe if we can seek first */
247
        std::vector<AbstractStream *>::iterator it;
248
        for(it=streams.begin(); it!=streams.end(); ++it)
249
        {
250
            ret &= (*it)->setPosition(time, !real);
251
252
253
254
255
256
257
        }
        if(!ret)
            break;
    }
    return ret;
}

258
259
260
261
262
263
264
265
266
267
bool PlaylistManager::needsUpdate() const
{
    return playlist->isLive() && (failedupdates < 3);
}

void PlaylistManager::scheduleNextUpdate()
{

}

268
269
bool PlaylistManager::updatePlaylist()
{
270
    std::vector<AbstractStream *>::const_iterator it;
271
272
273
    for(it=streams.begin(); it!=streams.end(); ++it)
        (*it)->runUpdates();

274
275
276
    return true;
}

277
278
279
280
281
282
283
284
285
286
mtime_t PlaylistManager::getFirstPlaybackTime() const
{
    return 0;
}

mtime_t PlaylistManager::getCurrentPlaybackTime() const
{
    return i_nzpcr;
}

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
void PlaylistManager::pruneLiveStream()
{
    mtime_t minValidPos = 0;
    std::vector<AbstractStream *>::const_iterator it;
    for(it=streams.begin(); it!=streams.end(); it++)
    {
        const AbstractStream *st = *it;
        if(st->isDisabled() || !st->isSelected() || st->isEOF())
            continue;
        const mtime_t t = st->getPlaybackTime();
        if(minValidPos == 0 || t < minValidPos)
            minValidPos = t;
    }

    if(minValidPos)
        playlist->pruneByPlaybackTime(minValidPos);
}

305
306
307
308
309
bool PlaylistManager::reactivateStream(AbstractStream *stream)
{
    return stream->reactivate(getPCR());
}

310
311
312
313
314
315
316
317
318
319
320
#define DEMUX_INCREMENT (CLOCK_FREQ / 20)
int PlaylistManager::demux_callback(demux_t *p_demux)
{
    PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
    return manager->doDemux(DEMUX_INCREMENT);
}

int PlaylistManager::doDemux(int64_t increment)
{
    if(i_nzpcr == VLC_TS_INVALID)
    {
321
        if( AbstractStream::status_eof == demux(i_nzpcr + increment, false) )
322
323
324
325
326
327
        {
            return VLC_DEMUXER_EOF;
        }
        i_nzpcr = getFirstDTS();
        if(i_nzpcr == VLC_TS_INVALID)
            i_nzpcr = getPCR();
328
329
        if(i_firstpcr == VLC_TS_INVALID)
            i_firstpcr = i_nzpcr;
330
331
    }

332
333
    AbstractStream::status status = demux(i_nzpcr + increment, true);
    AdvDebug(msg_Dbg( p_demux, "doDemux() status %d dts %ld pcr %ld", status, getFirstDTS(), getPCR() ));
334
335
    switch(status)
    {
336
    case AbstractStream::status_eof:
337
        return VLC_DEMUXER_EOF;
338
    case AbstractStream::status_buffering:
339
    case AbstractStream::status_buffering_ahead:
340
        break;
341
342
    case AbstractStream::status_dis:
    case AbstractStream::status_eop:
343
        i_nzpcr = VLC_TS_INVALID;
344
        i_firstpcr = VLC_TS_INVALID;
345
346
        es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
        break;
347
    case AbstractStream::status_demuxed:
348
349
350
        if( i_nzpcr != VLC_TS_INVALID )
        {
            i_nzpcr += increment;
351
            es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, 0, VLC_TS_0 + i_nzpcr);
352
353
354
355
        }
        break;
    }

356
357
358
359
360
361
362
    if(needsUpdate())
    {
        if(updatePlaylist())
            scheduleNextUpdate();
        else
            failedupdates++;
    }
363

364
365
366
367
    /* Live starved and update still not there ? */
    if(status == AbstractStream::status_buffering_ahead && needsUpdate())
        msleep(CLOCK_FREQ / 20); /* Ugly */

368
369
370
371
372
373
374
375
376
377
378
379
380
381
    return VLC_DEMUXER_SUCCESS;
}

int PlaylistManager::control_callback(demux_t *p_demux, int i_query, va_list args)
{
    PlaylistManager *manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
    return manager->doControl(i_query, args);
}

int PlaylistManager::doControl(int i_query, va_list args)
{
    switch (i_query)
    {
        case DEMUX_CAN_SEEK:
382
            *(va_arg (args, bool *)) = !playlist->isLive();
383
384
385
386
387
388
389
            break;

        case DEMUX_CAN_CONTROL_PACE:
            *(va_arg (args, bool *)) = true;
            break;

        case DEMUX_CAN_PAUSE:
390
            *(va_arg (args, bool *)) = !playlist->isLive();
391
392
            break;

393
394
395
        case DEMUX_SET_PAUSE_STATE:
            return (playlist->isLive()) ? VLC_EGENERIC : VLC_SUCCESS;

396
        case DEMUX_GET_TIME:
397
398
399
400
401
        {
            mtime_t i_time = getCurrentPlaybackTime();
            if(!playlist->isLive())
                i_time -= getFirstPlaybackTime();
            *(va_arg (args, int64_t *)) = i_time;
402
            break;
403
        }
404
405

        case DEMUX_GET_LENGTH:
406
407
            if(playlist->isLive())
                return VLC_EGENERIC;
408
409
410
411
            *(va_arg (args, int64_t *)) = getDuration();
            break;

        case DEMUX_GET_POSITION:
412
413
414
        {
            const mtime_t i_duration = getDuration();
            if(i_duration == 0) /* == playlist->isLive() */
415
416
                return VLC_EGENERIC;

417
418
            const mtime_t i_length = getCurrentPlaybackTime() - getFirstPlaybackTime();
            *(va_arg (args, double *)) = (double) i_length / i_duration;
419
            break;
420
        }
421
422
423

        case DEMUX_SET_POSITION:
        {
424
425
426
427
428
429
430
431
            const mtime_t i_duration = getDuration();
            if(i_duration == 0) /* == playlist->isLive() */
                return VLC_EGENERIC;

            int64_t time = i_duration * va_arg(args, double);
            time += getFirstPlaybackTime();

            if(!setPosition(time))
432
                return VLC_EGENERIC;
433

434
435
436
437
438
439
            i_nzpcr = VLC_TS_INVALID;
            break;
        }

        case DEMUX_SET_TIME:
        {
440
441
442
443
444
            if(playlist->isLive())
                return VLC_EGENERIC;

            int64_t time = va_arg(args, int64_t);// + getFirstPlaybackTime();
            if(!setPosition(time))
445
                return VLC_EGENERIC;
446

447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
            i_nzpcr = VLC_TS_INVALID;
            break;
        }

        case DEMUX_GET_PTS_DELAY:
            *va_arg (args, int64_t *) = INT64_C(1000) *
                var_InheritInteger(p_demux, "network-caching");
             break;

        default:
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

462
AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, HTTPConnectionManager *conn)
463
464
465
466
{
    switch(type)
    {
        case AbstractAdaptationLogic::FixedRate:
467
        {
468
            size_t bps = var_InheritInteger(p_demux, "adaptive-bw") * 8192;
469
470
            return new (std::nothrow) FixedRateAdaptationLogic(bps);
        }
471
472
        case AbstractAdaptationLogic::AlwaysLowest:
            return new (std::nothrow) AlwaysLowestAdaptationLogic();
473
474
        case AbstractAdaptationLogic::AlwaysBest:
            return new (std::nothrow) AlwaysBestAdaptationLogic();
475
476
        case AbstractAdaptationLogic::Default:
        case AbstractAdaptationLogic::RateBased:
477
        {
478
479
            int width = var_InheritInteger(p_demux, "adaptive-width");
            int height = var_InheritInteger(p_demux, "adaptive-height");
480
481
            RateBasedAdaptationLogic *logic =
                    new (std::nothrow) RateBasedAdaptationLogic(VLC_OBJECT(p_demux), width, height);
482
483
484
            conn->setDownloadRateObserver(logic);
            return logic;
        }
485
486
487
488
        default:
            return NULL;
    }
}