Streams.cpp 10.8 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_, const StreamFormat &format_)
39
{
40
    p_realdemux = demux_;
41
    format = format_;
42 43
    currentChunk = NULL;
    eof = false;
44
    dead = false;
45
    disabled = false;
46 47
    flushing = false;
    discontinuity = false;
48
    segmentTracker = NULL;
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    pcr = VLC_TS_INVALID;

    demuxer = NULL;
    fakeesout = NULL;

    /* Don't even try if not supported */
    if((unsigned)format == StreamFormat::UNSUPPORTED)
        throw VLC_EGENERIC;

    demuxersource = new (std::nothrow) ChunksSourceStream( VLC_OBJECT(p_realdemux), this );
    if(!demuxersource)
        throw VLC_EGENERIC;

    CommandsFactory *factory = new CommandsFactory();
    fakeesout = new (std::nothrow) FakeESOut(p_realdemux->out, factory);
    if(!fakeesout)
    {
        delete demuxersource;
        throw VLC_EGENERIC;
    }
    fakeesout->setExtraInfoProvider( this );
70 71
}

72
AbstractStream::~AbstractStream()
73 74
{
    delete currentChunk;
75
    delete segmentTracker;
76 77 78 79

    delete demuxer;
    delete demuxersource;
    delete fakeesout;
80 81 82
}


83
void AbstractStream::bind(SegmentTracker *tracker, HTTPConnectionManager *conn)
84
{
85
    segmentTracker = tracker;
86
    segmentTracker->registerListener(this);
87
    connManager = conn;
88 89
}

90
void AbstractStream::prepareFormatChange()
91
{
92 93 94 95 96 97 98 99 100 101 102 103 104 105
    if(demuxer)
    {
        /* Enqueue Del Commands for all current ES */
        demuxer->drain();
        /* Enqueue Del Commands for all current ES */
        fakeesout->scheduleAllForDeletion();
        fakeesout->schedulePCRReset();
        fakeesout->commandsqueue.Commit();
        /* ignoring demuxer's own Del commands */
        fakeesout->commandsqueue.setDrop(true);
        delete demuxer;
        fakeesout->commandsqueue.setDrop(false);
        demuxer = NULL;
    }
106 107
}

108
void AbstractStream::setLanguage(const std::string &lang)
109 110
{
    language = lang;
111 112
}

113
void AbstractStream::setDescription(const std::string &desc)
114 115 116 117
{
    description = desc;
}

118 119 120 121 122 123
bool AbstractStream::isEOF() const
{
    return dead;
}

mtime_t AbstractStream::getPCR() const
124
{
125
    return pcr;
126 127
}

128 129 130 131 132 133 134
mtime_t AbstractStream::getMinAheadTime() const
{
    if(!segmentTracker)
        return 0;
    return segmentTracker->getMinAheadTime();
}

135
mtime_t AbstractStream::getBufferingLevel() const
136
{
137
    return fakeesout->commandsqueue.getBufferingLevel();
138 139
}

140
mtime_t AbstractStream::getFirstDTS() const
141
{
142
    return fakeesout->commandsqueue.getFirstDTS();
143 144
}

145
int AbstractStream::esCount() const
146
{
147
    return fakeesout->esCount();
148 149
}

150
bool AbstractStream::seekAble() const
151
{
152 153 154 155
    return (demuxer &&
            !fakeesout->restarting() &&
            !discontinuity &&
            !flushing );
156 157
}

158
bool AbstractStream::isSelected() const
159
{
160
    return fakeesout->hasSelectedEs();
161 162
}

163
bool AbstractStream::reactivate(mtime_t basetime)
164 165 166 167 168 169 170 171 172 173 174 175 176
{
    if(setPosition(basetime, false))
    {
        disabled = false;
        return true;
    }
    else
    {
        eof = true; /* can't reactivate */
        return false;
    }
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
bool AbstractStream::startDemux()
{
    if(demuxer)
        return false;

    try
    {
        demuxersource->Reset();
        demuxer = createDemux(format);
    } catch(int) {
        msg_Err(p_realdemux, "Failed to create demuxer");
    }

    return !!demuxer;
}

bool AbstractStream::restartDemux()
{
    if(!demuxer)
    {
        return startDemux();
    }
    else if(demuxer->reinitsOnSeek())
    {
        /* Push all ES as recycling candidates */
        fakeesout->recycleAll();
        /* Restart with ignoring pushes to queue */
        return demuxer->restart(fakeesout->commandsqueue);
    }
206
    fakeesout->commandsqueue.Commit();
207 208 209 210
    return true;
}

bool AbstractStream::isDisabled() const
211 212 213 214
{
    return disabled;
}

215
AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send)
216
{
217
    /* Ensure it is configured */
218
    if(!segmentTracker || !connManager || dead)
219
        return AbstractStream::status_eof;
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    if(flushing)
    {
        if(!send)
            return AbstractStream::status_buffering;

        pcr = fakeesout->commandsqueue.Process(p_realdemux->out, VLC_TS_0 + nz_deadline);
        if(!fakeesout->commandsqueue.isEmpty())
            return AbstractStream::status_demuxed;

        fakeesout->commandsqueue.Abort(true); /* reset buffering level */
        flushing = false;
        pcr = 0;
        return AbstractStream::status_dis;
    }

236
    if(!demuxer)
237
    {
238 239
        format = segmentTracker->initialFormat();
        if(!startDemux())
240
        {
241 242 243 244 245 246 247 248 249 250 251
            /* If demux fails because of probing failure / wrong format*/
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on format change" );
                prepareFormatChange();
                discontinuity = false;
                flushing = true;
                return AbstractStream::status_buffering;
            }
            dead = true; /* Prevent further retries */
            return AbstractStream::status_eof;
252
        }
253
        setTimeOffset();
254 255 256
    }

    if(nz_deadline + VLC_TS_0 > getBufferingLevel()) /* not already demuxed */
257
    {
258 259 260
        if(!segmentTracker->segmentsListReady()) /* Live Streams */
            return AbstractStream::status_buffering_ahead;

261
        /* need to read, demuxer still buffering, ... */
262
        if(demuxer->demux(nz_deadline) != VLC_DEMUXER_SUCCESS)
263
        {
264
            if(discontinuity)
265 266 267 268 269 270 271 272 273 274 275
            {
                msg_Dbg( p_realdemux, "Flushing on discontinuity" );
                prepareFormatChange();
                discontinuity = false;
                flushing = true;
                return AbstractStream::status_buffering;
            }

            fakeesout->commandsqueue.Commit();
            if(fakeesout->commandsqueue.isEmpty())
                return AbstractStream::status_eof;
276
        }
277
        else if(nz_deadline + VLC_TS_0 > getBufferingLevel()) /* need to read more */
278
        {
279
            return AbstractStream::status_buffering;
280
        }
281 282
    }

283 284 285
    AdvDebug(msg_Dbg(p_realdemux, "Stream %s pcr %ld dts %ld deadline %ld buflevel %ld",
             description.c_str(), getPCR(), getFirstDTS(), nz_deadline, getBufferingLevel()));

286
    if(send)
287
        pcr = fakeesout->commandsqueue.Process( p_realdemux->out, VLC_TS_0 + nz_deadline );
288

289 290 291 292 293 294 295
    /* Disable streams that are not selected (alternate streams) */
    if(esCount() && !isSelected() && !fakeesout->restarting())
    {
        disabled = true;
        segmentTracker->reset();
    }

296
    return AbstractStream::status_demuxed;
297 298
}

299
block_t * AbstractStream::readNextBlock()
300
{
301 302
    if (currentChunk == NULL && !eof)
        currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);
303

304
    if(discontinuity)
305
    {
306 307
        msg_Info(p_realdemux, "Encountered discontinuity");
        /* Force stream/demuxer to end for this call */
308 309 310
        return NULL;
    }

311
    if(currentChunk == NULL)
312
    {
313
        eof = true;
314 315
        return NULL;
    }
316

317
    const bool b_segment_head_chunk = (currentChunk->getBytesRead() == 0);
318

319
    block_t *block = currentChunk->readBlock();
320
    if(block == NULL)
321
    {
322
        delete currentChunk;
323
        currentChunk = NULL;
324
        return NULL;
325 326
    }

327
    if (currentChunk->isEmpty())
328
    {
329
        delete currentChunk;
330
        currentChunk = NULL;
331 332
    }

333
    block = checkBlock(block, b_segment_head_chunk);
334

335
    return block;
336 337
}

338
bool AbstractStream::setPosition(mtime_t time, bool tryonly)
339
{
340
    if(!seekAble())
341 342
        return false;

343
    bool ret = segmentTracker->setPositionByTime(time, demuxer->reinitsOnSeek(), tryonly);
344
    if(!tryonly && ret)
345
    {
346
        if(demuxer->reinitsOnSeek())
347 348 349 350
        {
            if(currentChunk)
                delete currentChunk;
            currentChunk = NULL;
351

352 353
            if( !restartDemux() )
                dead = true;
354

355
            setTimeOffset();
356
        }
357

358
        pcr = VLC_TS_INVALID;
359 360
        es_out_Control(p_realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                       VLC_TS_0 + time);
361
    }
362 363 364
    return ret;
}

365
mtime_t AbstractStream::getPlaybackTime() const
366
{
367
    return segmentTracker->getPlaybackTime();
368
}
369

370
void AbstractStream::runUpdates()
371 372 373 374
{
    if(!isDisabled())
        segmentTracker->updateSelected();
}
375 376 377 378 379 380 381 382 383

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());
}

384 385 386 387 388 389 390 391 392 393
void AbstractStream::setTimeOffset()
{
    /* Check if we need to set an offset as the demuxer
     * will start from zero from seek point */
    if(demuxer && demuxer->alwaysStartsFromZero())
        fakeesout->setTimestampOffset(segmentTracker->getPlaybackTime());
    else
        fakeesout->setTimestampOffset(0);
}

394 395 396 397 398 399 400 401 402 403 404 405 406
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 */
407 408
                msg_Info(p_realdemux, "Changing stream format %s -> %s",
                         format.str().c_str(), event.u.format.f->str().c_str());
409 410 411 412 413 414 415 416 417 418 419 420
                format = *event.u.format.f;

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

        case SegmentTrackerEvent::SWITCHING:
        default:
            break;
    }
}