Streams.cpp 12.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Streams.cpp
 *****************************************************************************
 * Copyright (C) 2014 - VideoLAN authors
 *
 * 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
#define __STDC_CONSTANT_MACROS
21
#include "Streams.hpp"
22
#include "StreamsType.hpp"
23
#include "http/HTTPConnection.hpp"
24
25
26
#include "http/HTTPConnectionManager.h"
#include "http/Chunk.h"
#include "logic/AbstractAdaptationLogic.h"
27
#include "SegmentTracker.hpp"
28
29
#include <vlc_stream.h>
#include <vlc_demux.h>
30

31
using namespace adaptative;
32
33
34
using namespace adaptative::http;
using namespace adaptative::logic;

35
36
Stream::Stream(const std::string &mime)
{
37
    init(mimeToType(mime), mimeToFormat(mime));
38
39
}

40
Stream::Stream(const StreamType type, const StreamFormat format)
41
{
42
    init(type, format);
43
44
}

45
void Stream::init(const StreamType type_, const StreamFormat format_)
46
47
{
    type = type_;
48
    format = format_;
49
    output = NULL;
50
    adaptationLogic = NULL;
51
52
    currentChunk = NULL;
    eof = false;
53
    segmentTracker = NULL;
54
55
56
57
58
59
60
}

Stream::~Stream()
{
    delete currentChunk;
    delete adaptationLogic;
    delete output;
61
    delete segmentTracker;
62
63
}

64
StreamType Stream::mimeToType(const std::string &mime)
65
{
66
    StreamType mimetype;
67
    if (!mime.compare(0, 6, "video/"))
68
        mimetype = StreamType::VIDEO;
69
    else if (!mime.compare(0, 6, "audio/"))
70
        mimetype = StreamType::AUDIO;
71
    else if (!mime.compare(0, 12, "application/"))
72
        mimetype = StreamType::APPLICATION;
73
    else /* unknown of unsupported */
74
        mimetype = StreamType::UNKNOWN;
75
76
77
    return mimetype;
}

78
StreamFormat Stream::mimeToFormat(const std::string &mime)
79
{
80
    StreamFormat format = StreamFormat::UNSUPPORTED;
81
82
83
84
85
    std::string::size_type pos = mime.find("/");
    if(pos != std::string::npos)
    {
        std::string tail = mime.substr(pos + 1);
        if(tail == "mp4")
86
            format = StreamFormat::MP4;
87
        else if (tail == "mp2t")
88
            format = StreamFormat::MPEG2TS;
89
90
91
92
    }
    return format;
}

93
94
void Stream::create(demux_t *demux, AbstractAdaptationLogic *logic,
                    SegmentTracker *tracker, AbstractStreamOutputFactory &factory)
95
{
96
    output = factory.create(demux, format);
97
98
    adaptationLogic = logic;
    segmentTracker = tracker;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
}

bool Stream::isEOF() const
{
    return false;
}

mtime_t Stream::getPCR() const
{
    return output->getPCR();
}

int Stream::getGroup() const
{
    return output->getGroup();
}

int Stream::esCount() const
{
    return output->esCount();
}

121
122
123
124
bool Stream::operator ==(const Stream &stream) const
{
    return stream.type == type;
}
125
126
127
128
129

Chunk * Stream::getChunk()
{
    if (currentChunk == NULL)
    {
130
        currentChunk = segmentTracker->getNextChunk(type);
131
132
133
134
135
136
        if (currentChunk == NULL)
            eof = true;
    }
    return currentChunk;
}

137
138
139
140
141
bool Stream::seekAble() const
{
    return (output && output->seekAble());
}

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
Stream::status Stream::demux(HTTPConnectionManager *connManager, mtime_t nz_deadline)
{
    if(nz_deadline + VLC_TS_0 > output->getPCR()) /* not already demuxed */
    {
        /* need to read, demuxer still buffering, ... */
        if(read(connManager) <= 0)
            return Stream::status_eof;

        if(nz_deadline + VLC_TS_0 > output->getPCR()) /* need to read more */
            return Stream::status_buffering;
    }

    output->sendToDecoder(nz_deadline);
    return Stream::status_demuxed;
}

158
159
160
161
162
163
164
165
166
167
168
169
170
171
size_t Stream::read(HTTPConnectionManager *connManager)
{
    Chunk *chunk = getChunk();
    if(!chunk)
        return 0;

    if(!chunk->getConnection())
    {
       if(!connManager->connectChunk(chunk))
        return 0;
    }

    size_t readsize = 0;

172
    /* New chunk, do query */
173
174
    if(chunk->getBytesRead() == 0)
    {
175
176
177
178
179
180
181
        if(chunk->getConnection()->query(chunk->getPath()) != VLC_SUCCESS)
        {
            chunk->getConnection()->releaseChunk();
            currentChunk = NULL;
            delete chunk;
            return 0;
        }
182
183
    }

184
185
186
187
    /* Because we don't know Chunk size at start, we need to get size
       from content length */
    readsize = chunk->getBytesToRead();
    if (readsize > 32768)
188
189
190
191
192
193
194
195
196
197
        readsize = 32768;

    block_t *block = block_Alloc(readsize);
    if(!block)
        return 0;

    mtime_t time = mdate();
    ssize_t ret = chunk->getConnection()->read(block->p_buffer, readsize);
    time = mdate() - time;

198
    if(ret < 0)
199
200
201
202
203
204
205
206
207
208
209
210
    {
        block_Release(block);
        chunk->getConnection()->releaseChunk();
        currentChunk = NULL;
        delete chunk;
        return 0;
    }
    else
    {
        block->i_buffer = (size_t)ret;

        adaptationLogic->updateDownloadRate(block->i_buffer, time);
211
        chunk->onDownload(&block);
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

        if (chunk->getBytesToRead() == 0)
        {
            chunk->getConnection()->releaseChunk();
            currentChunk = NULL;
            delete chunk;
        }
    }

    readsize = block->i_buffer;

    output->pushBlock(block);

    return readsize;
}

228
229
bool Stream::setPosition(mtime_t time, bool tryonly)
{
230
    bool ret = segmentTracker->setPosition(time, output->reinitsOnSeek(), tryonly);
231
    if(!tryonly && ret)
232
    {
233
        output->setPosition(time);
234
235
236
237
238
239
240
241
242
243
        if(output->reinitsOnSeek())
        {
            if(currentChunk)
            {
                currentChunk->getConnection()->releaseChunk();
                delete currentChunk;
            }
            currentChunk = NULL;
        }
    }
244
245
246
    return ret;
}

247
248
249
250
251
mtime_t Stream::getPosition() const
{
    return segmentTracker->getSegmentStart();
}

252
253
254
255
AbstractStreamOutput::AbstractStreamOutput(demux_t *demux)
{
    realdemux = demux;
    pcr = VLC_TS_0;
256
    group = 0;
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
}

AbstractStreamOutput::~AbstractStreamOutput()
{
}

mtime_t AbstractStreamOutput::getPCR() const
{
    return pcr;
}

int AbstractStreamOutput::getGroup() const
{
    return group;
}

BaseStreamOutput::BaseStreamOutput(demux_t *demux, const std::string &name) :
    AbstractStreamOutput(demux)
{
    this->name = name;
277
    seekable = true;
278
    demuxstream = NULL;
279
280
281
282
283

    fakeesout = new es_out_t;
    if (!fakeesout)
        throw VLC_ENOMEM;

284
285
    vlc_mutex_init(&lock);

286
287
288
289
290
291
    fakeesout->pf_add = esOutAdd;
    fakeesout->pf_control = esOutControl;
    fakeesout->pf_del = esOutDel;
    fakeesout->pf_destroy = esOutDestroy;
    fakeesout->pf_send = esOutSend;
    fakeesout->p_sys = (es_out_sys_t*) this;
292
293
294

    if(!restart())
        throw VLC_EGENERIC;
295
296
}

297
BaseStreamOutput::~BaseStreamOutput()
298
299
300
301
{
    if (demuxstream)
        stream_Delete(demuxstream);
    delete fakeesout;
302
303
304
305
306
307
308

    vlc_mutex_destroy(&lock);

    /* shouldn't be any */
    std::list<Demuxed *>::const_iterator it;
    for(it=queues.begin(); it!=queues.end();++it)
        delete *it;
309
310
}

311
int BaseStreamOutput::esCount() const
312
{
313
    return queues.size();
314
315
}

316
void BaseStreamOutput::pushBlock(block_t *block)
317
318
319
320
{
    stream_DemuxSend(demuxstream, block);
}

321
bool BaseStreamOutput::seekAble() const
322
323
324
325
{
    return (demuxstream && seekable);
}

326
void BaseStreamOutput::setPosition(mtime_t nztime)
327
{
328
    vlc_mutex_lock(&lock);
329
330
331
332
333
334
335
    std::list<Demuxed *>::const_iterator it;
    for(it=queues.begin(); it!=queues.end();++it)
    {
        Demuxed *pair = *it;
        if(pair->p_queue && pair->p_queue->i_dts > VLC_TS_0 + nztime)
            pair->drop();
    }
336
    pcr = VLC_TS_INVALID;
337
    vlc_mutex_unlock(&lock);
338
339
    es_out_Control(realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                   VLC_TS_0 + nztime);
340
341
    if(reinitsOnSeek())
        restart();
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
bool BaseStreamOutput::restart()
{
    stream_t *newdemuxstream = stream_DemuxNew(realdemux, name.c_str(), fakeesout);
    if(!newdemuxstream)
        return false;

    vlc_mutex_lock(&lock);
    stream_t *olddemuxstream = demuxstream;
    demuxstream = newdemuxstream;
    vlc_mutex_unlock(&lock);

    if(olddemuxstream)
        stream_Delete(olddemuxstream);

    return true;
}

bool BaseStreamOutput::reinitsOnSeek() const
{
    return false;
}

void BaseStreamOutput::sendToDecoder(mtime_t nzdeadline)
367
{
368
    vlc_mutex_lock(&lock);
369
370
371
372
    sendToDecoderUnlocked(nzdeadline);
    vlc_mutex_unlock(&lock);
}

373
void BaseStreamOutput::sendToDecoderUnlocked(mtime_t nzdeadline)
374
{
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
    std::list<Demuxed *>::const_iterator it;
    for(it=queues.begin(); it!=queues.end();++it)
    {
        Demuxed *pair = *it;
        while(pair->p_queue && pair->p_queue->i_dts <= VLC_TS_0 + nzdeadline)
        {
            block_t *p_block = pair->p_queue;
            pair->p_queue = pair->p_queue->p_next;
            p_block->p_next = NULL;

            if(pair->pp_queue_last == &p_block->p_next)
                pair->pp_queue_last = &pair->p_queue;

            realdemux->out->pf_send(realdemux->out, pair->es_id, p_block);
        }
    }
}

393
BaseStreamOutput::Demuxed::Demuxed()
394
395
396
397
398
399
{
    p_queue = NULL;
    pp_queue_last = &p_queue;
    es_id = NULL;
}

400
BaseStreamOutput::Demuxed::~Demuxed()
401
402
403
404
{
    drop();
}

405
void BaseStreamOutput::Demuxed::drop()
406
407
408
409
410
411
{
    block_ChainRelease(p_queue);
    p_queue = NULL;
    pp_queue_last = &p_queue;
}

412
/* Static callbacks */
413
es_out_id_t * BaseStreamOutput::esOutAdd(es_out_t *fakees, const es_format_t *p_fmt)
414
{
415
    BaseStreamOutput *me = (BaseStreamOutput *) fakees->p_sys;
416
417
418
    es_out_id_t *p_es = me->realdemux->out->pf_add(me->realdemux->out, p_fmt);
    if(p_es)
    {
419
        vlc_mutex_lock(&me->lock);
420
421
422
423
424
425
        Demuxed *pair = new (std::nothrow) Demuxed();
        if(pair)
        {
            pair->es_id = p_es;
            me->queues.push_back(pair);
        }
426
        vlc_mutex_unlock(&me->lock);
427
428
    }
    return p_es;
429
430
}

431
int BaseStreamOutput::esOutSend(es_out_t *fakees, es_out_id_t *p_es, block_t *p_block)
432
{
433
    BaseStreamOutput *me = (BaseStreamOutput *) fakees->p_sys;
434
    vlc_mutex_lock(&me->lock);
435
436
437
438
439
440
441
442
443
444
    std::list<Demuxed *>::const_iterator it;
    for(it=me->queues.begin(); it!=me->queues.end();++it)
    {
        Demuxed *pair = *it;
        if(pair->es_id == p_es)
        {
            block_ChainLastAppend(&pair->pp_queue_last, p_block);
            break;
        }
    }
445
    vlc_mutex_unlock(&me->lock);
446
    return VLC_SUCCESS;
447
448
}

449
void BaseStreamOutput::esOutDel(es_out_t *fakees, es_out_id_t *p_es)
450
{
451
    BaseStreamOutput *me = (BaseStreamOutput *) fakees->p_sys;
452
    vlc_mutex_lock(&me->lock);
453
454
455
456
457
    std::list<Demuxed *>::iterator it;
    for(it=me->queues.begin(); it!=me->queues.end();++it)
    {
        if((*it)->es_id == p_es)
        {
458
            me->sendToDecoderUnlocked(INT64_MAX - VLC_TS_0);
459
460
461
462
463
            delete *it;
            me->queues.erase(it);
            break;
        }
    }
464
    vlc_mutex_unlock(&me->lock);
465
466
467
    me->realdemux->out->pf_del(me->realdemux->out, p_es);
}

468
int BaseStreamOutput::esOutControl(es_out_t *fakees, int i_query, va_list args)
469
{
470
    BaseStreamOutput *me = (BaseStreamOutput *) fakees->p_sys;
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    if (i_query == ES_OUT_SET_PCR )
    {
        me->pcr = (int64_t)va_arg( args, int64_t );
        return VLC_SUCCESS;
    }
    else if( i_query == ES_OUT_SET_GROUP_PCR )
    {
        me->group = (int) va_arg( args, int );
        me->pcr = (int64_t)va_arg( args, int64_t );
        return VLC_SUCCESS;
    }

    return me->realdemux->out->pf_control(me->realdemux->out, i_query, args);
}

486
void BaseStreamOutput::esOutDestroy(es_out_t *fakees)
487
{
488
    BaseStreamOutput *me = (BaseStreamOutput *) fakees->p_sys;
489
490
491
492
    me->realdemux->out->pf_destroy(me->realdemux->out);
}
/* !Static callbacks */

493
494
495
496
497
AbstractStreamOutput *DefaultStreamOutputFactory::create(demux_t *demux, int format) const
{
    switch(format)
    {
        case StreamFormat::MP4:
498
            return new BaseStreamOutput(demux, "mp4");
499
500

        case StreamFormat::MPEG2TS:
501
            return new BaseStreamOutput(demux, "ts");
502
503
504
505
506
507
508
509

        default:
            throw VLC_EBADVAR;
            break;
    }
    return NULL;
}