From e3ae28bcb236c51a3a1102354d93901b40e91e55 Mon Sep 17 00:00:00 2001 From: Francois Cartegnie Date: Thu, 14 Jan 2021 20:38:04 +0100 Subject: [PATCH] demux: adaptive: fix commands comparison strictly weak ordering was not preserved with same pts pkts (assumed a & b were compared in stored order) Causing corruption with non standard split IFrames as < 2^16 PES size. refs #25380 --- modules/demux/adaptive/plumbing/CommandsQueue.cpp | 51 ++++++++++++++--------- modules/demux/adaptive/plumbing/CommandsQueue.hpp | 7 +++- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/modules/demux/adaptive/plumbing/CommandsQueue.cpp b/modules/demux/adaptive/plumbing/CommandsQueue.cpp index 0cbcecda1b..34a54e0fc7 100644 --- a/modules/demux/adaptive/plumbing/CommandsQueue.cpp +++ b/modules/demux/adaptive/plumbing/CommandsQueue.cpp @@ -248,6 +248,7 @@ CommandsQueue::CommandsQueue( CommandsFactory *f ) b_draining = false; b_eof = false; commandsFactory = f; + nextsequence = 0; } CommandsQueue::~CommandsQueue() @@ -256,18 +257,27 @@ CommandsQueue::~CommandsQueue() delete commandsFactory; } -static bool compareCommands( AbstractCommand *a, AbstractCommand *b ) +static bool compareCommands( const Queueentry &a, const Queueentry &b ) { - if(a->getTime() == b->getTime()) + if(a.second->getTime() == b.second->getTime()) { /* Reorder the initial clock PCR setting PCR0 DTS0 PCR0 DTS1 PCR1 so it appears after the block, avoiding it not being output */ - if(a->getType() == ES_OUT_SET_GROUP_PCR && - b->getType() == ES_OUT_PRIVATE_COMMAND_SEND) + if(a.second->getType() == ES_OUT_SET_GROUP_PCR && + b.second->getType() == ES_OUT_PRIVATE_COMMAND_SEND && + a.first < b.first) return false; - return true; + + return a.first < b.first; + } + else if (a.second->getTime() == VLC_TICK_INVALID || b.second->getTime() == VLC_TICK_INVALID) + { + return a.first < b.first; + } + else + { + return a.second->getTime() < b.second->getTime(); } - else return (a->getTime() < b->getTime() && a->getTime() != VLC_TICK_INVALID); } void CommandsQueue::Schedule( AbstractCommand *command ) @@ -280,11 +290,11 @@ void CommandsQueue::Schedule( AbstractCommand *command ) { bufferinglevel = command->getTime(); LockedCommit(); - commands.push_back( command ); + commands.push_back( Queueentry(nextsequence++, command) ); } else { - incoming.push_back( command ); + incoming.push_back( Queueentry(nextsequence++, command) ); } } @@ -306,15 +316,16 @@ vlc_tick_t CommandsQueue::Process( es_out_t *out, vlc_tick_t barrier ) ex: for a target time of 2, you must dequeue <= 2 until >= PCR2 A0,A1,A2,B0,PCR0,B1,B2,PCR2,B3,A3,PCR3 */ - std::list output; - std::list in; + std::list output; + std::list in; in.splice( in.end(), commands ); while( !in.empty() ) { - AbstractCommand *command = in.front(); + Queueentry entry = in.front(); + AbstractCommand *command = entry.second; if( command->getType() == ES_OUT_PRIVATE_COMMAND_DEL && b_datasent ) break; @@ -340,21 +351,21 @@ vlc_tick_t CommandsQueue::Process( es_out_t *out, vlc_tick_t barrier ) /* ensure no more non dated for that ES is sent * since we're sure that data is above barrier */ disabled_esids.insert( id ); - commands.push_back( command ); + commands.push_back( entry ); } else if( command->getTime() == VLC_TICK_INVALID ) { if( disabled_esids.find( id ) == disabled_esids.end() ) - output.push_back( command ); + output.push_back( entry ); else - commands.push_back( command ); + commands.push_back( entry ); } else /* Falls below barrier, send */ { - output.push_back( command ); + output.push_back( entry ); } } - else output.push_back( command ); /* will discard below */ + else output.push_back( entry ); /* will discard below */ } /* push remaining ones if broke above */ @@ -366,7 +377,7 @@ vlc_tick_t CommandsQueue::Process( es_out_t *out, vlc_tick_t barrier ) /* Now execute our selected commands */ while( !output.empty() ) { - AbstractCommand *command = output.front(); + AbstractCommand *command = output.front().second; output.pop_front(); if( command->getType() == ES_OUT_PRIVATE_COMMAND_SEND ) @@ -402,7 +413,7 @@ void CommandsQueue::Abort( bool b_reset ) commands.splice( commands.end(), incoming ); while( !commands.empty() ) { - delete commands.front(); + delete commands.front().second; commands.pop_front(); } @@ -471,11 +482,11 @@ vlc_tick_t CommandsQueue::getBufferingLevel() const vlc_tick_t CommandsQueue::getFirstDTS() const { - std::list::const_iterator it; + std::list::const_iterator it; vlc_tick_t i_firstdts = pcr; for( it = commands.begin(); it != commands.end(); ++it ) { - const vlc_tick_t i_dts = (*it)->getTime(); + const vlc_tick_t i_dts = (*it).second->getTime(); if( i_dts != VLC_TICK_INVALID ) { if( i_dts < i_firstdts || i_firstdts == VLC_TICK_INVALID ) diff --git a/modules/demux/adaptive/plumbing/CommandsQueue.hpp b/modules/demux/adaptive/plumbing/CommandsQueue.hpp index cc15fd4973..ab4b0d4a7b 100644 --- a/modules/demux/adaptive/plumbing/CommandsQueue.hpp +++ b/modules/demux/adaptive/plumbing/CommandsQueue.hpp @@ -147,6 +147,8 @@ namespace adaptive virtual EsOutMetaCommand * createEsOutMetaCommand( int, const vlc_meta_t * ) const; }; + using Queueentry = std::pair; + /* Queuing for doing all the stuff in order */ class CommandsQueue { @@ -173,13 +175,14 @@ namespace adaptive CommandsFactory *commandsFactory; void LockedCommit(); void LockedSetDraining(); - std::list incoming; - std::list commands; + std::list incoming; + std::list commands; vlc_tick_t bufferinglevel; vlc_tick_t pcr; bool b_draining; bool b_drop; bool b_eof; + uint64_t nextsequence; }; } -- 2.11.4.GIT