diff --git a/lib/CalypStream.cpp b/lib/CalypStream.cpp index 70e8d84..22e45f6 100644 --- a/lib/CalypStream.cpp +++ b/lib/CalypStream.cpp @@ -205,20 +205,72 @@ private: inline int nextIndex( std::int64_t curr ) { return curr + 1; } }; +struct CalypStreamFrameBuffer : std::enable_shared_from_this +{ + std::mutex buffer_mutex; + std::vector> framePool; + std::size_t bufferIdx{ 0 }; + + CalypStreamFrameBuffer( std::size_t size, unsigned int width, unsigned int height, int pelFormat, unsigned int bitsPixel, bool hasNegative ) + { + framePool.reserve( size ); + for( std::size_t i = 0; i < size; i++ ) + { + framePool.push_back( std::make_unique( width, height, pelFormat, bitsPixel, hasNegative ) ); + } + bufferIdx = framePool.size(); + } + + ~CalypStreamFrameBuffer() = default; + + void increase( std::size_t newSize ) + { + framePool.reserve( newSize ); + auto oldSize = framePool.size(); + for( std::size_t i = oldSize; i < newSize; i++ ) + { + framePool.push_back( std::make_unique( framePool[0]->getWidth(), + framePool[0]->getHeight(), + framePool[0]->getPelFormat(), + framePool[0]->getBitsPel(), + framePool[0]->getHasNegativeValues() ) ); + } + bufferIdx += newSize - oldSize; + } + + CalypFrame* ref() { return framePool[0].get(); } + + std::shared_ptr getFrame() + { + const std::lock_guard lock( buffer_mutex ); + assert( bufferIdx > 0 ); + bufferIdx--; + auto frame = framePool[bufferIdx].release(); + auto deleter = [this, lifetime = shared_from_this()]( CalypFrame* p ) { + const std::lock_guard lock( buffer_mutex ); + framePool[bufferIdx].reset( p ); + bufferIdx++; + }; + return std::shared_ptr{ frame, deleter }; + } +}; + class CalypStream::CalypStreamPrivate { public: - std::recursive_mutex mutex; - + std::recursive_mutex stream_mutex; bool isInit; bool isInput; CalypStreamHandlerIf* handler; CreateStreamHandlerFn pfctCreateHandler; - std::vector> framePool; + std::shared_ptr frameBuffer; std::deque> frameFifo; - std::size_t bufferIdx{ 0 }; + + // std::vector> framePool; + // std::deque> frameFifo; + // std::size_t bufferIdx{ 0 }; ClpString cFilename; long long int iCurrFrameNum; @@ -250,62 +302,31 @@ public: bLoadAll = false; isInit = false; - framePool.clear(); - frameFifo.clear(); - } - - void increasePool( std::size_t newSize ) - { - framePool.reserve( newSize ); - auto oldSize = framePool.size(); - for( std::size_t i = oldSize; i < newSize; i++ ) - { - framePool.push_back( std::make_unique( framePool[0]->getWidth(), - framePool[0]->getHeight(), - framePool[0]->getPelFormat(), - framePool[0]->getBitsPel(), - framePool[0]->getHasNegativeValues() ) ); - } } bool readNextFrame( bool fillRgbBuffer = false ) { + const std::lock_guard lock( stream_mutex ); + if( !isInit || !isInput || handler->m_uiCurrFrameFileIdx >= handler->m_uiTotalNumberFrames ) return false; if( bLoadAll ) return true; - const std::lock_guard lock( mutex ); - mutex.lock(); - assert( bufferIdx > 0 ); - bufferIdx--; - auto frame = framePool[bufferIdx].release(); - mutex.unlock(); + auto frame = frameBuffer->getFrame(); if( !handler->read( *frame ) ) { throw CalypFailure( "CalypStream", "Cannot read frame from stream" ); return false; } + frameFifo.push_back( frame ); + if( fillRgbBuffer ) { frame->fillRGBBuffer(); } - - auto deleter = [this]( CalypFrame* p ) { - if( isInit ) - { - const std::lock_guard lock( mutex ); - framePool[bufferIdx].reset( p ); - bufferIdx++; - } - else - { - delete p; - } - }; - frameFifo.push_back( std::shared_ptr{ frame, deleter } ); return true; } }; @@ -455,21 +476,18 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } + d->frameFifo.clear(); + // Keep past, current and future frames - std::size_t bufferSize = d->isInput ? 4 : 1; + std::size_t bufferSize = d->isInput ? 6 : 1; try { - d->framePool.reserve( bufferSize ); - for( std::size_t i = 0; i < bufferSize; i++ ) - { - d->framePool.push_back( - std::make_unique( - d->handler->m_uiWidth, - d->handler->m_uiHeight, - d->handler->m_iPixelFormat, - d->handler->m_uiBitsPerPixel, - hasNegative ) ); - } + d->frameBuffer = std::make_shared( bufferSize, + d->handler->m_uiWidth, + d->handler->m_uiHeight, + d->handler->m_iPixelFormat, + d->handler->m_uiBitsPerPixel, + hasNegative ); } catch( CalypFailure& e ) { @@ -478,12 +496,9 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - d->frameFifo.clear(); - d->bufferIdx = d->framePool.size(); + const CalypFrame* refFrame = d->frameBuffer->ref(); - const CalypFrame& refFrame = *d->framePool[0]; - - d->handler->m_uiNBytesPerFrame = refFrame.getBytesPerFrame(); + d->handler->m_uiNBytesPerFrame = refFrame->getBytesPerFrame(); // Some handlers need to know how long is a frame to get frame number d->handler->calculateFrameNumber(); @@ -495,7 +510,7 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - if( !d->handler->configureBuffer( refFrame ) ) + if( !d->handler->configureBuffer( *refFrame ) ) { d->close(); throw CalypFailure( "CalypStream", "Cannot allocated buffers" ); @@ -520,10 +535,10 @@ bool CalypStream::reload() throw CalypFailure( "CalypStream", "Cannot open stream " + d->cFilename + " with the " + ClpString( d->handler->m_pchHandlerName ) + " handler" ); } - const CalypFrame& refFrame = *d->framePool[0]; - d->handler->m_uiNBytesPerFrame = refFrame.getBytesPerFrame(); + const CalypFrame* refFrame = d->frameBuffer->ref(); + d->handler->m_uiNBytesPerFrame = refFrame->getBytesPerFrame(); d->handler->calculateFrameNumber(); - d->handler->configureBuffer( *d->framePool[0] ); + d->handler->configureBuffer( *refFrame ); if( d->handler->m_uiWidth <= 0 || d->handler->m_uiHeight <= 0 || d->handler->m_iPixelFormat < 0 || d->handler->m_uiBitsPerPixel == 0 || d->handler->m_uiTotalNumberFrames == 0 ) @@ -610,7 +625,7 @@ auto CalypStream::hasNextFrame() -> bool auto CalypStream::hasWritingSlot() -> bool { - return !d->bLoadAll && d->bufferIdx > 0; + return !d->bLoadAll && d->frameBuffer->bufferIdx > 0; } /** @@ -619,19 +634,19 @@ auto CalypStream::hasWritingSlot() -> bool void CalypStream::loadAll() { + const std::lock_guard lock( d->stream_mutex ); if( d->bLoadAll || !d->isInput ) return; try { - d->increasePool( d->handler->m_uiTotalNumberFrames ); + d->frameBuffer->increase( d->handler->m_uiTotalNumberFrames ); } catch( CalypFailure& e ) { d->close(); throw CalypFailure( "CalypStream", "Cannot allocated frame buffer for the whole stream" ); } - seekInput( 0 ); for( unsigned int i = 2; i < d->handler->m_uiTotalNumberFrames; i++ ) { @@ -751,18 +766,17 @@ bool CalypStream::seekInputRelative( bool bIsFoward ) bool CalypStream::seekInput( unsigned long new_frame_num ) { - const std::lock_guard lock( d->mutex ); + const std::lock_guard lock( d->stream_mutex ); if( !d->isInit || new_frame_num >= d->handler->m_uiTotalNumberFrames || long( new_frame_num ) == d->iCurrFrameNum ) return false; - d->frameFifo.clear(); - d->iCurrFrameNum = new_frame_num; if( d->bLoadAll ) return true; + d->frameFifo.clear(); if( !d->handler->seek( d->iCurrFrameNum ) ) { throw CalypFailure( "CalypStream", "Cannot seek file into desired position" );