Streams.cpp 14.2 KB
Newer Older
1 2 3
/*
 * Streams.cpp
 *****************************************************************************
4
 * Copyright (C) 2014 - VideoLAN and VLC authors
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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.
 *****************************************************************************/
20 21 22 23 24

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

25
#include "Streams.hpp"
26
#include "http/HTTPConnection.hpp"
27
#include "http/HTTPConnectionManager.h"
28
#include "playlist/BaseRepresentation.h"
29
#include "playlist/SegmentChunk.hpp"
30 31 32
#include "plumbing/SourceStream.hpp"
#include "plumbing/CommandsQueue.hpp"
#include "tools/Debug.hpp"
33
#include <vlc_demux.h>
34

35 36
using namespace adaptive;
using namespace adaptive::http;
37

38
AbstractStream::AbstractStream(demux_t * demux_)
39
{
40
    p_realdemux = demux_;
41
    format = StreamFormat::UNSUPPORTED;
42 43
    currentChunk = NULL;
    eof = false;
44
    dead = false;
45
    disabled = false;
46
    discontinuity = false;
47
    needrestart = false;
48
    segmentTracker = NULL;
49
    demuxersource = NULL;
50
    commandsqueue = NULL;
51 52
    demuxer = NULL;
    fakeesout = NULL;
53
    vlc_mutex_init(&lock);
54
}
55

56 57 58 59 60
bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker, HTTPConnectionManager *conn)
{
    /* Don't even try if not supported or already init */
    if((unsigned)format_ == StreamFormat::UNSUPPORTED || demuxersource)
        return false;
61 62

    demuxersource = new (std::nothrow) ChunksSourceStream( VLC_OBJECT(p_realdemux), this );
63
    if(demuxersource)
64
    {
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
        CommandsFactory *factory = new (std::nothrow) CommandsFactory();
        if(factory)
        {
            commandsqueue = new (std::nothrow) CommandsQueue(factory);
            if(commandsqueue)
            {
                fakeesout = new (std::nothrow) FakeESOut(p_realdemux->out, commandsqueue);
                if(fakeesout)
                {
                    /* All successfull */
                    fakeesout->setExtraInfoProvider( this );
                    format = format_;
                    segmentTracker = tracker;
                    segmentTracker->registerListener(this);
                    connManager = conn;
                    return true;
                }
                delete commandsqueue;
                commandsqueue = NULL;
            }
            else
            {
                delete factory;
            }
        }
90 91 92
        delete demuxersource;
    }

93
    return false;
94 95
}

96
AbstractStream::~AbstractStream()
97 98
{
    delete currentChunk;
99
    delete segmentTracker;
100 101 102 103

    delete demuxer;
    delete demuxersource;
    delete fakeesout;
104
    delete commandsqueue;
105 106

    vlc_mutex_destroy(&lock);
107 108
}

109
void AbstractStream::prepareRestart(bool b_discontinuity)
110
{
111 112 113 114
    if(demuxer)
    {
        /* Enqueue Del Commands for all current ES */
        demuxer->drain();
115
        setTimeOffset(true);
116 117
        /* Enqueue Del Commands for all current ES */
        fakeesout->scheduleAllForDeletion();
118 119
        if(b_discontinuity)
            fakeesout->schedulePCRReset();
120
        commandsqueue->Commit();
121
        /* ignoring demuxer's own Del commands */
122
        commandsqueue->setDrop(true);
123
        delete demuxer;
124
        commandsqueue->setDrop(false);
125 126
        demuxer = NULL;
    }
127 128
}

129
void AbstractStream::setLanguage(const std::string &lang)
130 131
{
    language = lang;
132 133
}

134
void AbstractStream::setDescription(const std::string &desc)
135 136 137 138
{
    description = desc;
}

139
bool AbstractStream::isDead() const
140 141 142 143 144
{
    return dead;
}

mtime_t AbstractStream::getPCR() const
145
{
146 147 148 149
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    mtime_t pcr = (dead || disabled) ? VLC_TS_INVALID : commandsqueue->getPCR();
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return pcr;
150 151
}

152 153 154 155 156 157 158
mtime_t AbstractStream::getMinAheadTime() const
{
    if(!segmentTracker)
        return 0;
    return segmentTracker->getMinAheadTime();
}

159
mtime_t AbstractStream::getFirstDTS() const
160
{
161 162 163 164 165 166 167 168 169 170 171 172 173 174
    mtime_t dts;
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    if(dead || disabled)
    {
        dts = VLC_TS_INVALID;
    }
    else
    {
        dts = commandsqueue->getFirstDTS();
        if(dts == VLC_TS_INVALID)
            dts = commandsqueue->getPCR();
    }
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return dts;
175 176
}

177
int AbstractStream::esCount() const
178
{
179
    return fakeesout->esCount();
180 181
}

182
bool AbstractStream::seekAble() const
183
{
184 185 186
    return (demuxer &&
            !fakeesout->restarting() &&
            !discontinuity &&
187
            !commandsqueue->isFlushing() );
188 189
}

190
bool AbstractStream::isSelected() const
191
{
192
    return fakeesout->hasSelectedEs();
193 194
}

195
bool AbstractStream::reactivate(mtime_t basetime)
196 197 198 199 200 201 202 203 204 205 206 207 208
{
    if(setPosition(basetime, false))
    {
        disabled = false;
        return true;
    }
    else
    {
        eof = true; /* can't reactivate */
        return false;
    }
}

209 210 211 212 213
bool AbstractStream::startDemux()
{
    if(demuxer)
        return false;

214 215
    demuxersource->Reset();
    demuxer = createDemux(format);
216
    if(!demuxer && format != StreamFormat())
217 218 219 220 221 222 223 224 225 226 227
        msg_Err(p_realdemux, "Failed to create demuxer");

    return !!demuxer;
}

bool AbstractStream::restartDemux()
{
    if(!demuxer)
    {
        return startDemux();
    }
228
    else if(demuxer->needsRestartOnSeek())
229 230 231 232
    {
        /* Push all ES as recycling candidates */
        fakeesout->recycleAll();
        /* Restart with ignoring pushes to queue */
233
        return demuxer->restart(commandsqueue);
234
    }
235
    commandsqueue->Commit();
236 237 238 239
    return true;
}

bool AbstractStream::isDisabled() const
240 241 242 243
{
    return disabled;
}

244 245 246 247 248
bool AbstractStream::drain()
{
    return fakeesout->drain();
}

249 250
AbstractStream::buffering_status AbstractStream::bufferize(mtime_t nz_deadline,
                                                           unsigned i_min_buffering, unsigned i_extra_buffering)
251
{
252 253
    vlc_mutex_lock(&lock);

254
    /* Ensure it is configured */
255
    if(!segmentTracker || !connManager || dead)
256
    {
257 258 259
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }
260

261 262 263 264 265 266 267 268 269 270
    /* Disable streams that are not selected (alternate streams) */
    if(esCount() && !isSelected() && !fakeesout->restarting())
    {
        disabled = true;
        segmentTracker->reset();
        commandsqueue->Abort(false);
        msg_Dbg(p_realdemux, "deactivating stream %s", format.str().c_str());
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }
271

272 273 274 275
    if(commandsqueue->isFlushing())
    {
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_suspended;
276 277
    }

278
    if(!demuxer)
279
    {
280
        format = segmentTracker->getCurrentFormat();
281
        if(!startDemux())
282
        {
283 284 285 286
            /* If demux fails because of probing failure / wrong format*/
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on format change" );
287
                prepareRestart();
288
                discontinuity = false;
289
                commandsqueue->setFlush();
290 291
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
292 293
            }
            dead = true; /* Prevent further retries */
294 295 296
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
297 298 299
        }
    }

300 301 302 303
    const int64_t i_total_buffering = i_min_buffering + i_extra_buffering;

    mtime_t i_demuxed = commandsqueue->getDemuxedAmount();
    if(i_demuxed < i_total_buffering) /* not already demuxed */
304
    {
305
        if(!segmentTracker->segmentsListReady()) /* Live Streams */
306 307 308 309 310 311 312
        {
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_suspended;
        }

        nz_deadline = commandsqueue->getBufferingLevel() +
                     (i_total_buffering - commandsqueue->getDemuxedAmount()) / (CLOCK_FREQ/4);
313

314
        /* need to read, demuxer still buffering, ... */
315 316 317 318
        vlc_mutex_unlock(&lock);
        int i_ret = demuxer->demux(nz_deadline);
        vlc_mutex_lock(&lock);
        if(i_ret != VLC_DEMUXER_SUCCESS)
319
        {
320
            if(discontinuity || needrestart)
321
            {
322 323 324 325 326 327 328 329 330
                msg_Dbg(p_realdemux, "Restarting demuxer");
                prepareRestart(discontinuity);
                if(discontinuity)
                {
                    msg_Dbg(p_realdemux, "Flushing on discontinuity");
                    commandsqueue->setFlush();
                    discontinuity = false;
                }
                needrestart = false;
331 332
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
333
            }
334 335 336
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
337
        }
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
        i_demuxed = commandsqueue->getDemuxedAmount();
    }
    vlc_mutex_unlock(&lock);

    if(i_demuxed < i_total_buffering) /* need to read more */
    {
        if(i_demuxed < i_min_buffering)
            return AbstractStream::buffering_lessthanmin; /* high prio */
        return AbstractStream::buffering_ongoing;
    }
    return AbstractStream::buffering_full;
}

AbstractStream::status AbstractStream::dequeue(mtime_t nz_deadline, mtime_t *pi_pcr)
{
    vlc_mutex_locker locker(&lock);

    *pi_pcr = nz_deadline;

    if (disabled || dead)
        return AbstractStream::status_eof;

    if(commandsqueue->isFlushing())
    {
        *pi_pcr = commandsqueue->Process(p_realdemux->out, VLC_TS_0 + nz_deadline);
        if(!commandsqueue->isEmpty())
            return AbstractStream::status_demuxed;

        if(!commandsqueue->isEOF())
367
        {
368 369
            commandsqueue->Abort(true); /* reset buffering level and flags */
            return AbstractStream::status_discontinuity;
370
        }
371 372
    }

373 374 375 376 377
    if(commandsqueue->isEOF())
    {
        *pi_pcr = nz_deadline;
        return AbstractStream::status_eof;
    }
378

379 380 381
    AdvDebug(msg_Dbg(p_realdemux, "Stream %s pcr %ld dts %ld deadline %ld buflevel %ld",
                     description.c_str(), commandsqueue->getPCR(), commandsqueue->getFirstDTS(),
                     nz_deadline, commandsqueue->getBufferingLevel()));
382

383
    if(nz_deadline + VLC_TS_0 <= commandsqueue->getBufferingLevel()) /* demuxed */
384
    {
385 386
        *pi_pcr = commandsqueue->Process( p_realdemux->out, VLC_TS_0 + nz_deadline );
        return AbstractStream::status_demuxed;
387 388
    }

389
    return AbstractStream::status_buffering;
390 391
}

392
block_t * AbstractStream::readNextBlock()
393
{
394 395
    if (currentChunk == NULL && !eof)
        currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);
396

397
    if(discontinuity || needrestart)
398
    {
399 400
        msg_Info(p_realdemux, "Encountered discontinuity");
        /* Force stream/demuxer to end for this call */
401 402 403
        return NULL;
    }

404
    if(currentChunk == NULL)
405
    {
406
        eof = true;
407 408
        return NULL;
    }
409

410
    const bool b_segment_head_chunk = (currentChunk->getBytesRead() == 0);
411

412
    block_t *block = currentChunk->readBlock();
413
    if(block == NULL)
414
    {
415
        delete currentChunk;
416
        currentChunk = NULL;
417
        return NULL;
418 419
    }

420
    if (currentChunk->isEmpty())
421
    {
422
        delete currentChunk;
423
        currentChunk = NULL;
424 425
    }

426
    block = checkBlock(block, b_segment_head_chunk);
427

428
    return block;
429 430
}

431
bool AbstractStream::setPosition(mtime_t time, bool tryonly)
432
{
433
    if(!seekAble())
434 435
        return false;

436
    bool ret = segmentTracker->setPositionByTime(time, demuxer->needsRestartOnSeek(), tryonly);
437
    if(!tryonly && ret)
438
    {
439
        if(demuxer->needsRestartOnSeek())
440 441 442 443
        {
            if(currentChunk)
                delete currentChunk;
            currentChunk = NULL;
444
            needrestart = false;
445

446 447 448
            setTimeOffset(-1);
            setTimeOffset(segmentTracker->getPlaybackTime());

449 450
            if( !restartDemux() )
                dead = true;
451
        }
452
        else commandsqueue->Abort( true );
453 454 455

        es_out_Control(p_realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                       VLC_TS_0 + time);
456
    }
457 458 459
    return ret;
}

460
mtime_t AbstractStream::getPlaybackTime() const
461
{
462
    return segmentTracker->getPlaybackTime();
463
}
464

465
void AbstractStream::runUpdates()
466 467 468 469
{
    if(!isDisabled())
        segmentTracker->updateSelected();
}
470 471 472 473 474 475 476 477 478

void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
{
    if(!p_fmt->psz_language && !language.empty())
        p_fmt->psz_language = strdup(language.c_str());
    if(!p_fmt->psz_description && !description.empty())
        p_fmt->psz_description = strdup(description.c_str());
}

479
void AbstractStream::setTimeOffset(mtime_t i_offset)
480 481 482
{
    /* Check if we need to set an offset as the demuxer
     * will start from zero from seek point */
483 484
    if(i_offset < 0) /* reset */
    {
485
        fakeesout->setTimestampOffset(0);
486 487 488 489 490 491
    }
    else if(demuxer)
    {
        if(demuxer->alwaysStartsFromZero())
            fakeesout->setTimestampOffset(i_offset);
    }
492 493
}

494 495 496 497 498 499 500 501 502 503 504 505 506
void AbstractStream::trackerEvent(const SegmentTrackerEvent &event)
{
    switch(event.type)
    {
        case SegmentTrackerEvent::DISCONTINUITY:
            discontinuity = true;
            break;

        case SegmentTrackerEvent::FORMATCHANGE:
            /* Check if our current demux is still valid */
            if(*event.u.format.f != format)
            {
                /* Format has changed between segments, we need to drain and change demux */
507 508
                msg_Info(p_realdemux, "Changing stream format %s -> %s",
                         format.str().c_str(), event.u.format.f->str().c_str());
509 510 511 512 513 514 515 516
                format = *event.u.format.f;

                /* This is an implict discontinuity */
                discontinuity = true;
            }
            break;

        case SegmentTrackerEvent::SWITCHING:
517 518 519 520
            if(demuxer && demuxer->needsRestartOnSwitch())
            {
                needrestart = true;
            }
521 522 523 524
        default:
            break;
    }
}