demux: adaptive: remove left indirect returns since lock removal
[vlc.git] / modules / demux / adaptive / plumbing / CommandsQueue.cpp
blob17720454a87acd54f5ffbe55cabbee8ad04bfb59
1 /*
2 * CommandsQueue.cpp
3 *****************************************************************************
4 * Copyright © 2015 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 *****************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include "CommandsQueue.hpp"
25 #include "FakeESOutID.hpp"
26 #include "FakeESOut.hpp"
27 #include <vlc_es_out.h>
28 #include <vlc_block.h>
29 #include <vlc_meta.h>
30 #include <algorithm>
31 #include <set>
33 using namespace adaptive;
35 enum
37 ES_OUT_PRIVATE_COMMAND_ADD = ES_OUT_PRIVATE_START,
38 ES_OUT_PRIVATE_COMMAND_DEL,
39 ES_OUT_PRIVATE_COMMAND_DESTROY,
40 ES_OUT_PRIVATE_COMMAND_SEND,
41 ES_OUT_PRIVATE_COMMAND_DISCONTINUITY
44 AbstractCommand::AbstractCommand( int type_ )
46 type = type_;
49 AbstractCommand::~AbstractCommand()
54 vlc_tick_t AbstractCommand::getTime() const
56 return VLC_TICK_INVALID;
59 int AbstractCommand::getType() const
61 return type;
64 AbstractFakeEsCommand::AbstractFakeEsCommand( int type, AbstractFakeESOutID *p_es ) :
65 AbstractCommand( type )
67 p_fakeid = p_es;
70 EsOutSendCommand::EsOutSendCommand( AbstractFakeESOutID *p_es, block_t *p_block_ ) :
71 AbstractFakeEsCommand( ES_OUT_PRIVATE_COMMAND_SEND, p_es )
73 p_block = p_block_;
76 EsOutSendCommand::~EsOutSendCommand()
78 if( p_block )
79 block_Release( p_block );
82 void EsOutSendCommand::Execute()
84 p_fakeid->sendData( p_block );
85 p_block = nullptr;
88 vlc_tick_t EsOutSendCommand::getTime() const
90 if( likely(p_block) )
91 return p_block->i_dts;
92 else
93 return AbstractCommand::getTime();
96 const void * EsOutSendCommand::esIdentifier() const
98 return static_cast<const void *>(p_fakeid);
101 EsOutDelCommand::EsOutDelCommand( AbstractFakeESOutID *p_es ) :
102 AbstractFakeEsCommand( ES_OUT_PRIVATE_COMMAND_DEL, p_es )
106 void EsOutDelCommand::Execute( )
108 p_fakeid->release();
111 EsOutAddCommand::EsOutAddCommand( AbstractFakeESOutID *p_es ) :
112 AbstractFakeEsCommand( ES_OUT_PRIVATE_COMMAND_ADD, p_es )
116 EsOutAddCommand::~EsOutAddCommand()
120 void EsOutAddCommand::Execute( )
122 /* Create the real ES on the adaptive demux */
123 p_fakeid->create();
126 EsOutControlPCRCommand::EsOutControlPCRCommand( int group_, vlc_tick_t pcr_ ) :
127 AbstractCommand( ES_OUT_SET_GROUP_PCR )
129 group = group_;
130 pcr = pcr_;
131 type = ES_OUT_SET_GROUP_PCR;
134 void EsOutControlPCRCommand::Execute( )
136 // do nothing here
139 vlc_tick_t EsOutControlPCRCommand::getTime() const
141 return pcr;
144 EsOutDestroyCommand::EsOutDestroyCommand() :
145 AbstractCommand( ES_OUT_PRIVATE_COMMAND_DESTROY )
149 void EsOutDestroyCommand::Execute( )
153 EsOutControlResetPCRCommand::EsOutControlResetPCRCommand() :
154 AbstractCommand( ES_OUT_PRIVATE_COMMAND_DISCONTINUITY )
158 void EsOutControlResetPCRCommand::Execute( )
162 EsOutMetaCommand::EsOutMetaCommand( AbstractFakeEsOut *out,
163 int i_group, vlc_meta_t *p_meta ) :
164 AbstractCommand( ES_OUT_SET_GROUP_META )
166 group = i_group;
167 this->out = out;
168 this->p_meta = p_meta;
171 EsOutMetaCommand::~EsOutMetaCommand()
173 if( p_meta )
174 vlc_meta_Delete( p_meta );
177 void EsOutMetaCommand::Execute()
179 out->sendMeta( group, p_meta );
183 * Commands Default Factory
186 EsOutSendCommand * CommandsFactory::createEsOutSendCommand( AbstractFakeESOutID *id, block_t *p_block ) const
188 return new (std::nothrow) EsOutSendCommand( id, p_block );
191 EsOutDelCommand * CommandsFactory::createEsOutDelCommand( AbstractFakeESOutID *id ) const
193 return new (std::nothrow) EsOutDelCommand( id );
196 EsOutAddCommand * CommandsFactory::createEsOutAddCommand( AbstractFakeESOutID *id ) const
198 return new (std::nothrow) EsOutAddCommand( id );
201 EsOutControlPCRCommand * CommandsFactory::createEsOutControlPCRCommand( int group, vlc_tick_t pcr ) const
203 return new (std::nothrow) EsOutControlPCRCommand( group, pcr );
206 EsOutDestroyCommand * CommandsFactory::createEsOutDestroyCommand() const
208 return new (std::nothrow) EsOutDestroyCommand();
211 EsOutControlResetPCRCommand * CommandsFactory::creatEsOutControlResetPCRCommand() const
213 return new (std::nothrow) EsOutControlResetPCRCommand();
216 EsOutMetaCommand * CommandsFactory::createEsOutMetaCommand( AbstractFakeEsOut *out, int group,
217 const vlc_meta_t *p_meta ) const
219 vlc_meta_t *p_dup = vlc_meta_New();
220 if( p_dup )
222 vlc_meta_Merge( p_dup, p_meta );
223 return new (std::nothrow) EsOutMetaCommand( out, group, p_dup );
225 return nullptr;
229 * Commands Queue management
231 #if 0
232 /* For queue printing/debugging */
233 std::ostream& operator<<(std::ostream& ostr, const std::list<AbstractCommand *>& list)
235 for (auto &i : list) {
236 ostr << "[" << i->getType() << "]" << SEC_FROM_VLC_TICK(i->getTime()) << " ";
238 return ostr;
240 #endif
242 CommandsQueue::CommandsQueue( CommandsFactory *f )
244 bufferinglevel = VLC_TICK_INVALID;
245 pcr = VLC_TICK_INVALID;
246 b_drop = false;
247 b_draining = false;
248 b_eof = false;
249 commandsFactory = f;
250 nextsequence = 0;
253 CommandsQueue::~CommandsQueue()
255 Abort( false );
256 delete commandsFactory;
259 static bool compareCommands( const Queueentry &a, const Queueentry &b )
261 if(a.second->getTime() == b.second->getTime())
263 /* Reorder the initial clock PCR setting PCR0 DTS0 PCR0 DTS1 PCR1
264 so it appears after the block, avoiding it not being output */
265 if(a.second->getType() == ES_OUT_SET_GROUP_PCR &&
266 b.second->getType() == ES_OUT_PRIVATE_COMMAND_SEND &&
267 a.first < b.first)
268 return false;
270 return a.first < b.first;
272 else if (a.second->getTime() == VLC_TICK_INVALID || b.second->getTime() == VLC_TICK_INVALID)
274 return a.first < b.first;
276 else
278 return a.second->getTime() < b.second->getTime();
282 void CommandsQueue::Schedule( AbstractCommand *command )
284 if( b_drop )
286 delete command;
288 else if( command->getType() == ES_OUT_SET_GROUP_PCR )
290 bufferinglevel = command->getTime();
291 LockedCommit();
292 commands.push_back( Queueentry(nextsequence++, command) );
294 else
296 incoming.push_back( Queueentry(nextsequence++, command) );
300 const CommandsFactory * CommandsQueue::factory() const
302 return commandsFactory;
305 vlc_tick_t CommandsQueue::Process( vlc_tick_t barrier )
307 vlc_tick_t lastdts = barrier;
308 std::set<const void *> disabled_esids;
309 bool b_datasent = false;
311 /* We need to filter the current commands list
312 We need to return on discontinuity or reset events if data was sent
313 We must lookup every packet until end or PCR matching barrier,
314 because packets of multiple stream can arrive delayed (with intermidiate pcr)
315 ex: for a target time of 2, you must dequeue <= 2 until >= PCR2
316 A0,A1,A2,B0,PCR0,B1,B2,PCR2,B3,A3,PCR3
318 std::list<Queueentry> output;
319 std::list<Queueentry> in;
322 in.splice( in.end(), commands );
324 while( !in.empty() )
326 Queueentry entry = in.front();
327 AbstractCommand *command = entry.second;
329 if( command->getType() == ES_OUT_PRIVATE_COMMAND_DEL && b_datasent )
330 break;
332 if( command->getType() == ES_OUT_PRIVATE_COMMAND_DISCONTINUITY && b_datasent )
333 break;
335 if(command->getType() == ES_OUT_SET_GROUP_PCR && command->getTime() > barrier )
336 break;
338 in.pop_front();
339 b_datasent = true;
341 if( command->getType() == ES_OUT_PRIVATE_COMMAND_SEND )
343 EsOutSendCommand *sendcommand = dynamic_cast<EsOutSendCommand *>(command);
344 /* We need a stream identifier to send NON DATED data following DATA for the same ES */
345 const void *id = (sendcommand) ? sendcommand->esIdentifier() : 0;
347 /* Not for now */
348 if( command->getTime() > barrier ) /* Not for now */
350 /* ensure no more non dated for that ES is sent
351 * since we're sure that data is above barrier */
352 disabled_esids.insert( id );
353 commands.push_back( entry );
355 else if( command->getTime() == VLC_TICK_INVALID )
357 if( disabled_esids.find( id ) == disabled_esids.end() )
358 output.push_back( entry );
359 else
360 commands.push_back( entry );
362 else /* Falls below barrier, send */
364 output.push_back( entry );
367 else output.push_back( entry ); /* will discard below */
370 /* push remaining ones if broke above */
371 commands.splice( commands.end(), in );
373 if(commands.empty() && b_draining)
374 b_draining = false;
376 /* Now execute our selected commands */
377 while( !output.empty() )
379 AbstractCommand *command = output.front().second;
380 output.pop_front();
382 if( command->getType() == ES_OUT_PRIVATE_COMMAND_SEND )
384 vlc_tick_t dts = command->getTime();
385 if( dts != VLC_TICK_INVALID )
386 lastdts = dts;
389 command->Execute();
390 delete command;
392 pcr = lastdts; /* Warn! no PCR update/lock release until execution */
395 return lastdts;
398 void CommandsQueue::LockedCommit()
400 /* reorder all blocks by time between 2 PCR and merge with main list */
401 incoming.sort( compareCommands );
402 commands.splice( commands.end(), incoming );
405 void CommandsQueue::Commit()
407 LockedCommit();
410 void CommandsQueue::Abort( bool b_reset )
412 commands.splice( commands.end(), incoming );
413 while( !commands.empty() )
415 delete commands.front().second;
416 commands.pop_front();
419 if( b_reset )
421 bufferinglevel = VLC_TICK_INVALID;
422 pcr = VLC_TICK_INVALID;
423 b_draining = false;
424 b_eof = false;
428 bool CommandsQueue::isEmpty() const
430 return commands.empty() && incoming.empty();
433 void CommandsQueue::setDrop( bool b )
435 b_drop = b;
438 void CommandsQueue::setDraining()
440 LockedSetDraining();
443 bool CommandsQueue::isDraining() const
445 return b_draining;
448 void CommandsQueue::setEOF( bool b )
450 b_eof = b;
451 if( b_eof )
452 LockedSetDraining();
453 else
454 b_draining = false;
457 bool CommandsQueue::isEOF() const
459 return b_eof;
462 vlc_tick_t CommandsQueue::getDemuxedAmount(vlc_tick_t from) const
464 if( bufferinglevel == VLC_TICK_INVALID || from > bufferinglevel )
465 return 0;
466 if( from > getFirstDTS() )
467 return bufferinglevel - from;
468 else
469 return bufferinglevel - getFirstDTS();
472 vlc_tick_t CommandsQueue::getBufferingLevel() const
474 return bufferinglevel;
477 vlc_tick_t CommandsQueue::getFirstDTS() const
479 std::list<Queueentry>::const_iterator it;
480 vlc_tick_t i_firstdts = pcr;
481 for( it = commands.begin(); it != commands.end(); ++it )
483 const vlc_tick_t i_dts = (*it).second->getTime();
484 if( i_dts != VLC_TICK_INVALID )
486 if( i_dts < i_firstdts || i_firstdts == VLC_TICK_INVALID )
487 i_firstdts = i_dts;
488 break;
491 return i_firstdts;
494 void CommandsQueue::LockedSetDraining()
496 LockedCommit();
497 b_draining = !commands.empty();
500 vlc_tick_t CommandsQueue::getPCR() const
502 return pcr;