3 *****************************************************************************
4 * Copyright (C) 2014 - VideoLAN and VLC authors
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include "Streams.hpp"
26 #include "logic/AbstractAdaptationLogic.h"
27 #include "http/HTTPConnection.hpp"
28 #include "http/HTTPConnectionManager.h"
29 #include "playlist/BaseRepresentation.h"
30 #include "playlist/SegmentChunk.hpp"
31 #include "plumbing/SourceStream.hpp"
32 #include "plumbing/CommandsQueue.hpp"
33 #include "tools/Debug.hpp"
34 #include <vlc_demux.h>
38 using namespace adaptive
;
39 using namespace adaptive::http
;
41 AbstractStream::AbstractStream(demux_t
* demux_
)
44 format
= StreamFormat::UNSUPPORTED
;
49 discontinuity
= false;
52 segmentTracker
= NULL
;
57 last_buffer_status
= buffering_lessthanmin
;
58 vlc_mutex_init(&lock
);
61 bool AbstractStream::init(const StreamFormat
&format_
, SegmentTracker
*tracker
, AbstractConnectionManager
*conn
)
63 /* Don't even try if not supported or already init */
64 if((unsigned)format_
== StreamFormat::UNSUPPORTED
|| demuxersource
)
67 demuxersource
= new (std::nothrow
) ChunksSourceStream( VLC_OBJECT(p_realdemux
), this );
70 CommandsFactory
*factory
= new (std::nothrow
) CommandsFactory();
73 commandsqueue
= new (std::nothrow
) CommandsQueue(factory
);
76 fakeesout
= new (std::nothrow
) FakeESOut(p_realdemux
->out
, commandsqueue
);
80 fakeesout
->setExtraInfoProvider( this );
82 segmentTracker
= tracker
;
83 segmentTracker
->registerListener(this);
84 segmentTracker
->notifyBufferingState(true);
102 AbstractStream::~AbstractStream()
106 segmentTracker
->notifyBufferingState(false);
107 delete segmentTracker
;
110 delete demuxersource
;
112 delete commandsqueue
;
114 vlc_mutex_destroy(&lock
);
117 void AbstractStream::prepareRestart(bool b_discontinuity
)
121 /* Enqueue Del Commands for all current ES */
124 /* Enqueue Del Commands for all current ES */
125 fakeesout
->scheduleAllForDeletion();
127 fakeesout
->schedulePCRReset();
128 commandsqueue
->Commit();
129 /* ignoring demuxer's own Del commands */
130 commandsqueue
->setDrop(true);
132 commandsqueue
->setDrop(false);
137 void AbstractStream::setLanguage(const std::string
&lang
)
142 void AbstractStream::setDescription(const std::string
&desc
)
147 mtime_t
AbstractStream::getPCR() const
149 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
150 mtime_t pcr
= isDisabled() ? VLC_TS_INVALID
: commandsqueue
->getPCR();
151 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
155 mtime_t
AbstractStream::getMinAheadTime() const
159 return segmentTracker
->getMinAheadTime();
162 mtime_t
AbstractStream::getFirstDTS() const
165 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
168 dts
= VLC_TS_INVALID
;
172 dts
= commandsqueue
->getFirstDTS();
173 if(dts
== VLC_TS_INVALID
)
174 dts
= commandsqueue
->getPCR();
176 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
180 int AbstractStream::esCount() const
182 return fakeesout
->esCount();
185 bool AbstractStream::seekAble() const
187 bool restarting
= fakeesout
->restarting();
188 bool draining
= commandsqueue
->isDraining();
189 bool eof
= commandsqueue
->isEOF();
191 msg_Dbg(p_realdemux
, "demuxer %p, fakeesout restarting %d, "
192 "discontinuity %d, commandsqueue draining %d, commandsqueue eof %d",
193 static_cast<void *>(demuxer
), restarting
, discontinuity
, draining
, eof
);
195 if(!demuxer
|| restarting
|| discontinuity
|| (!eof
&& draining
))
197 msg_Warn(p_realdemux
, "not seekable");
206 bool AbstractStream::isSelected() const
208 return fakeesout
->hasSelectedEs();
211 bool AbstractStream::reactivate(mtime_t basetime
)
213 if(setPosition(basetime
, false))
220 eof
= true; /* can't reactivate */
225 bool AbstractStream::startDemux()
230 demuxersource
->Reset();
231 demuxer
= createDemux(format
);
232 if(!demuxer
&& format
!= StreamFormat())
233 msg_Err(p_realdemux
, "Failed to create demuxer %p %s", (void *)demuxer
,
234 format
.str().c_str());
239 bool AbstractStream::restartDemux()
244 b_ret
= startDemux();
246 else if(demuxer
->needsRestartOnSeek())
249 /* Push all ES as recycling candidates */
250 fakeesout
->recycleAll();
251 /* Restart with ignoring es_Del pushes to queue when terminating demux */
252 commandsqueue
->setDrop(true);
254 commandsqueue
->setDrop(false);
255 b_ret
= demuxer
->create();
260 commandsqueue
->Commit();
265 void AbstractStream::setDisabled(bool b
)
268 segmentTracker
->notifyBufferingState(!b
);
272 bool AbstractStream::isDisabled() const
274 return dead
|| disabled
;
277 bool AbstractStream::canActivate() const
282 bool AbstractStream::decodersDrained()
284 return fakeesout
->decodersDrained();
287 AbstractStream::buffering_status
AbstractStream::getLastBufferStatus() const
289 return last_buffer_status
;
292 mtime_t
AbstractStream::getDemuxedAmount() const
294 return commandsqueue
->getDemuxedAmount();
297 AbstractStream::buffering_status
AbstractStream::bufferize(mtime_t nz_deadline
,
298 unsigned i_min_buffering
, unsigned i_extra_buffering
)
300 last_buffer_status
= doBufferize(nz_deadline
, i_min_buffering
, i_extra_buffering
);
301 return last_buffer_status
;
304 AbstractStream::buffering_status
AbstractStream::doBufferize(mtime_t nz_deadline
,
305 unsigned i_min_buffering
, unsigned i_extra_buffering
)
307 vlc_mutex_lock(&lock
);
309 /* Ensure it is configured */
310 if(!segmentTracker
|| !connManager
|| dead
)
312 vlc_mutex_unlock(&lock
);
313 return AbstractStream::buffering_end
;
316 /* Disable streams that are not selected (alternate streams) */
317 if(esCount() && !isSelected() && !fakeesout
->restarting())
320 segmentTracker
->reset();
321 commandsqueue
->Abort(false);
322 msg_Dbg(p_realdemux
, "deactivating %s stream %s",
323 format
.str().c_str(), description
.c_str());
324 vlc_mutex_unlock(&lock
);
325 return AbstractStream::buffering_end
;
328 if(commandsqueue
->isDraining())
330 vlc_mutex_unlock(&lock
);
331 return AbstractStream::buffering_suspended
;
336 format
= segmentTracker
->getCurrentFormat();
339 /* If demux fails because of probing failure / wrong format*/
342 msg_Dbg( p_realdemux
, "Draining on format change" );
344 discontinuity
= false;
345 commandsqueue
->setDraining();
346 vlc_mutex_unlock(&lock
);
347 return AbstractStream::buffering_ongoing
;
349 dead
= true; /* Prevent further retries */
350 commandsqueue
->setEOF(true);
351 vlc_mutex_unlock(&lock
);
352 return AbstractStream::buffering_end
;
356 const int64_t i_total_buffering
= i_min_buffering
+ i_extra_buffering
;
358 mtime_t i_demuxed
= commandsqueue
->getDemuxedAmount();
359 segmentTracker
->notifyBufferingLevel(i_min_buffering
, i_demuxed
, i_total_buffering
);
360 if(i_demuxed
< i_total_buffering
) /* not already demuxed */
362 if(!segmentTracker
->segmentsListReady()) /* Live Streams */
364 vlc_mutex_unlock(&lock
);
365 return AbstractStream::buffering_suspended
;
368 mtime_t nz_extdeadline
= commandsqueue
->getBufferingLevel() +
369 (i_total_buffering
- commandsqueue
->getDemuxedAmount()) / (CLOCK_FREQ
/4);
370 nz_deadline
= std::max(nz_deadline
, nz_extdeadline
);
372 /* need to read, demuxer still buffering, ... */
373 vlc_mutex_unlock(&lock
);
374 int i_ret
= demuxer
->demux(nz_deadline
);
375 vlc_mutex_lock(&lock
);
376 if(i_ret
!= VLC_DEMUXER_SUCCESS
)
378 if(discontinuity
|| needrestart
)
380 msg_Dbg(p_realdemux
, "Restarting demuxer");
381 prepareRestart(discontinuity
);
384 msg_Dbg(p_realdemux
, "Draining on discontinuity");
385 commandsqueue
->setDraining();
386 discontinuity
= false;
389 vlc_mutex_unlock(&lock
);
390 return AbstractStream::buffering_ongoing
;
392 commandsqueue
->setEOF(true);
393 vlc_mutex_unlock(&lock
);
394 return AbstractStream::buffering_end
;
396 i_demuxed
= commandsqueue
->getDemuxedAmount();
397 segmentTracker
->notifyBufferingLevel(i_min_buffering
, i_demuxed
, i_total_buffering
);
399 vlc_mutex_unlock(&lock
);
401 if(i_demuxed
< i_total_buffering
) /* need to read more */
403 if(i_demuxed
< i_min_buffering
)
404 return AbstractStream::buffering_lessthanmin
; /* high prio */
405 return AbstractStream::buffering_ongoing
;
407 return AbstractStream::buffering_full
;
410 AbstractStream::status
AbstractStream::dequeue(mtime_t nz_deadline
, mtime_t
*pi_pcr
)
412 vlc_mutex_locker
locker(&lock
);
414 *pi_pcr
= nz_deadline
;
416 if(commandsqueue
->isDraining())
418 AdvDebug(msg_Dbg(p_realdemux
, "Stream %s pcr %" PRId64
" dts %" PRId64
" deadline %" PRId64
" [DRAINING]",
419 description
.c_str(), commandsqueue
->getPCR(), commandsqueue
->getFirstDTS(),
422 *pi_pcr
= commandsqueue
->Process(p_realdemux
->out
, VLC_TS_0
+ nz_deadline
);
423 if(!commandsqueue
->isEmpty())
424 return AbstractStream::status_demuxed
;
426 if(!commandsqueue
->isEOF())
428 commandsqueue
->Abort(true); /* reset buffering level and flags */
429 return AbstractStream::status_discontinuity
;
433 if(isDisabled() || commandsqueue
->isEOF())
435 *pi_pcr
= nz_deadline
;
436 return AbstractStream::status_eof
;
439 AdvDebug(msg_Dbg(p_realdemux
, "Stream %s pcr %" PRId64
" dts %" PRId64
" deadline %" PRId64
" buflevel %" PRId64
,
440 description
.c_str(), commandsqueue
->getPCR(), commandsqueue
->getFirstDTS(),
441 nz_deadline
, commandsqueue
->getBufferingLevel()));
443 if(nz_deadline
+ VLC_TS_0
<= commandsqueue
->getBufferingLevel()) /* demuxed */
445 *pi_pcr
= commandsqueue
->Process( p_realdemux
->out
, VLC_TS_0
+ nz_deadline
);
446 return AbstractStream::status_demuxed
;
449 return AbstractStream::status_buffering
;
452 block_t
* AbstractStream::readNextBlock()
454 if (currentChunk
== NULL
&& !eof
)
455 currentChunk
= segmentTracker
->getNextChunk(!fakeesout
->restarting(), connManager
);
457 if(discontinuity
|| needrestart
)
459 msg_Info(p_realdemux
, "Encountered discontinuity");
460 /* Force stream/demuxer to end for this call */
464 if(currentChunk
== NULL
)
470 const bool b_segment_head_chunk
= (currentChunk
->getBytesRead() == 0);
472 block_t
*block
= currentChunk
->readBlock();
480 if (currentChunk
->isEmpty())
486 block
= checkBlock(block
, b_segment_head_chunk
);
491 bool AbstractStream::setPosition(mtime_t time
, bool tryonly
)
496 bool ret
= segmentTracker
->setPositionByTime(time
, demuxer
->needsRestartOnSeek(), tryonly
);
499 // clear eof flag before restartDemux() to prevent readNextBlock() fail
501 if(demuxer
->needsRestartOnSeek())
509 setTimeOffset(segmentTracker
->getPlaybackTime());
511 if( !restartDemux() )
513 msg_Info(p_realdemux
, "Restart demux failed");
520 commandsqueue
->setEOF(false);
523 else commandsqueue
->Abort( true );
525 es_out_Control(p_realdemux
->out
, ES_OUT_SET_NEXT_DISPLAY_TIME
,
531 mtime_t
AbstractStream::getPlaybackTime() const
533 return segmentTracker
->getPlaybackTime();
536 void AbstractStream::runUpdates()
539 segmentTracker
->updateSelected();
542 void AbstractStream::fillExtraFMTInfo( es_format_t
*p_fmt
) const
544 if(!p_fmt
->psz_language
&& !language
.empty())
545 p_fmt
->psz_language
= strdup(language
.c_str());
546 if(!p_fmt
->psz_description
&& !description
.empty())
547 p_fmt
->psz_description
= strdup(description
.c_str());
550 void AbstractStream::setTimeOffset(mtime_t i_offset
)
552 /* Check if we need to set an offset as the demuxer
553 * will start from zero from seek point */
554 if(i_offset
< 0) /* reset */
556 fakeesout
->setExpectedTimestampOffset(0);
560 fakeesout
->setExpectedTimestampOffset(i_offset
);
564 void AbstractStream::trackerEvent(const SegmentTrackerEvent
&event
)
568 case SegmentTrackerEvent::DISCONTINUITY
:
569 discontinuity
= true;
572 case SegmentTrackerEvent::FORMATCHANGE
:
573 /* Check if our current demux is still valid */
574 if(*event
.u
.format
.f
!= format
)
576 /* Format has changed between segments, we need to drain and change demux */
577 msg_Info(p_realdemux
, "Changing stream format %s -> %s",
578 format
.str().c_str(), event
.u
.format
.f
->str().c_str());
579 format
= *event
.u
.format
.f
;
581 /* This is an implict discontinuity */
582 discontinuity
= true;
586 case SegmentTrackerEvent::SWITCHING
:
587 if(demuxer
&& demuxer
->needsRestartOnSwitch() && !inrestart
)
593 case SegmentTrackerEvent::SEGMENT_CHANGE
:
594 if(demuxer
&& demuxer
->needsRestartOnEachSegment() && !inrestart
)