diff --git a/app/CalypAppModuleIf.cpp b/app/CalypAppModuleIf.cpp index 6e83c21..ec61159 100644 --- a/app/CalypAppModuleIf.cpp +++ b/app/CalypAppModuleIf.cpp @@ -188,13 +188,13 @@ void CalypAppModuleIf::run() { return; } - m_bSuccess = true; - m_bIsRunning = false; #ifdef CALYP_THREADED_MODULES EventData* eventData = new EventData( m_bSuccess, this ); if( parent() ) QCoreApplication::postEvent( parent(), eventData ); #endif + m_bSuccess = true; + m_bIsRunning = false; return; } diff --git a/app/MainWindow.cpp b/app/MainWindow.cpp index b0d604b..0216402 100644 --- a/app/MainWindow.cpp +++ b/app/MainWindow.cpp @@ -83,11 +83,11 @@ MainWindow::MainWindow() setAcceptDrops( true ); setBackgroundRole( QPalette::Background ); - connect( m_pcWindowHandle, SIGNAL( windowActivated() ), this, SLOT( update() ) ); - connect( m_pcWindowHandle, SIGNAL( changed() ), this, SLOT( update() ) ); - connect( m_appModuleVideo, SIGNAL( changed() ), this, SLOT( update() ) ); - connect( m_appModuleQuality, SIGNAL( changed() ), this, SLOT( update() ) ); - connect( m_appModuleExtensions, SIGNAL( changed() ), this, SLOT( update() ) ); + connect( m_pcWindowHandle, &SubWindowHandle::windowActivated, this, &MainWindow::update ); + connect( m_pcWindowHandle, &SubWindowHandle::changed, this, &MainWindow::update, Qt::QueuedConnection ); + connect( m_appModuleVideo, &VideoHandle::changed, this, &MainWindow::update, Qt::QueuedConnection ); + connect( m_appModuleQuality, &QualityHandle::changed, this, &MainWindow::update, Qt::QueuedConnection ); + connect( m_appModuleExtensions, &ModulesHandle::changed, this, &MainWindow::update, Qt::QueuedConnection ); } bool MainWindow::parseArgs( int argc, char* argv[] ) diff --git a/app/ResourceHandle.cpp b/app/ResourceHandle.cpp index 2a76c17..df9d635 100644 --- a/app/ResourceHandle.cpp +++ b/app/ResourceHandle.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -41,6 +43,7 @@ ResourceWorker::ResourceWorker( std::shared_ptr stream ) void ResourceWorker::stop() { m_bStop = true; + wake(); wait(); } @@ -53,16 +56,23 @@ void ResourceWorker::wake() void ResourceWorker::run() { + m_bStop = false; // Loop forever while( !m_bStop ) { + //auto start = std::chrono::steady_clock::now(); m_pcStream->readNextFrameFillRGBBuffer(); - if( !m_pcStream->hasWritingSlot() ) - { - m_Mutex.lock(); - m_ResourceIdle.wait( &m_Mutex ); - m_Mutex.unlock(); - } + // auto end = std::chrono::steady_clock::now(); + // std::cout << "Elapsed time reading and processing a frame: " + // << std::chrono::duration_cast( end - start ).count() + // << " ms" << std::endl; + + // if( !m_pcStream->hasWritingSlot() ) + // { + // m_Mutex.lock(); + // m_ResourceIdle.wait( &m_Mutex ); + // m_Mutex.unlock(); + // } while( !m_bStop && !m_pcStream->hasWritingSlot() ) { // Wait here @@ -123,6 +133,16 @@ void ResourceHandle::removeResource( std::size_t id ) m_apcStreamResourcesList[id] = nullptr; } +void ResourceHandle::stopResourceWorker( std::size_t id ) +{ + if( !m_apcStreamResourcesWorkersList.contains( id ) ) + { + assert( false ); + return; + } + m_apcStreamResourcesWorkersList[id]->stop(); +} + void ResourceHandle::startResourceWorker( std::size_t id ) { if( !m_apcStreamResourcesWorkersList.contains( id ) ) diff --git a/app/ResourceHandle.h b/app/ResourceHandle.h index 007e952..2af3812 100644 --- a/app/ResourceHandle.h +++ b/app/ResourceHandle.h @@ -57,6 +57,7 @@ public: auto getResource( CalypStream* ptr ) -> std::size_t; auto getResourceAsset( std::size_t id ) -> CalypStream*; void removeResource( std::size_t id ); + void stopResourceWorker( std::size_t id ); void startResourceWorker( std::size_t id ); void wakeResourceWorker( std::size_t id ); diff --git a/app/VideoHandle.cpp b/app/VideoHandle.cpp index eb33f51..0e9adcd 100644 --- a/app/VideoHandle.cpp +++ b/app/VideoHandle.cpp @@ -438,7 +438,7 @@ void VideoHandle::closeSubWindow( SubWindowAbstract* subWindow ) if( m_acPlayingSubWindows.contains( videoSubWindow ) ) { int pos = m_acPlayingSubWindows.indexOf( videoSubWindow ); - m_acPlayingSubWindows.at( pos )->stop(); + // m_acPlayingSubWindows.at( pos )->stop(); m_acPlayingSubWindows.remove( pos ); if( m_acPlayingSubWindows.size() < 2 ) { @@ -675,8 +675,10 @@ void VideoHandle::calculateRealFrameRate() void VideoHandle::playEvent() { + auto start = std::chrono::steady_clock::now(); + // This value should only be true if it is really needed to refresh the UI after this play event - // Lets assum the current window is not playing. Nothing changes in the UI expect the playing windows + // Lets assume the current window is not playing. Nothing changes in the UI expect the playing windows // So no changed is emmited bool bShouldRefreshUI = false; calculateRealFrameRate(); @@ -719,6 +721,11 @@ void VideoHandle::playEvent() } if( bShouldRefreshUI ) emit changed(); + + // auto end = std::chrono::steady_clock::now(); + // std::cout << "Elapsed time going to next frame: " + // << std::chrono::duration_cast( end - start ).count() + // << " ms" << std::endl; } void VideoHandle::seekEvent( int direction ) diff --git a/app/VideoSubWindow.cpp b/app/VideoSubWindow.cpp index 75e7866..7fd8017 100644 --- a/app/VideoSubWindow.cpp +++ b/app/VideoSubWindow.cpp @@ -202,7 +202,6 @@ VideoSubWindow::~VideoSubWindow() { module->destroy(); } - if( m_pcResourceManager ) m_pcResourceManager->removeResource( m_uiResourceId ); delete m_pcUpdateTimer; @@ -214,7 +213,7 @@ VideoSubWindow::~VideoSubWindow() void VideoSubWindow::closeEvent( QCloseEvent* event ) { - stop(); + //stop(); SubWindowAbstract::closeEvent( event ); } @@ -310,12 +309,17 @@ void VideoSubWindow::refreshSubWindow() { if( getCategory() & SubWindowAbstract::VIDEO_STREAM_SUBWINDOW ) { +#ifdef CALYP_MANAGED_RESOURCES + m_pcResourceManager->stopResourceWorker( m_uiResourceId ); +#endif if( !m_pCurrStream->reload() ) { close(); return; } - // seekAbsoluteEvent( currFrameNum ); +#ifdef CALYP_MANAGED_RESOURCES + m_pcResourceManager->startResourceWorker( m_uiResourceId ); +#endif } updateVideoWindowInfo(); refreshFrame(); @@ -792,19 +796,19 @@ void VideoSubWindow::refreshFrame( bool bThreaded ) bool VideoSubWindow::goToNextFrame( bool bThreaded ) { -#ifdef CALYP_MANAGED_RESOURCES - bool bEndOfSeq = m_pCurrStream->retrieveNextFrame(); - m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); - if( !bEndOfSeq ) - { - refreshFrame(); - } -#else #ifndef QT_NO_CONCURRENT m_cRefreshResult.waitForFinished(); m_cReadResult.waitForFinished(); +#endif +#ifdef CALYP_MANAGED_RESOURCES + while( !m_pCurrStream->hasNextFrame() && !m_pCurrStream->isEof() ) + ; #endif bool bEndOfSeq = m_pCurrStream->setNextFrame(); +#ifdef CALYP_MANAGED_RESOURCES + bThreaded = false; + m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); +#endif if( !bEndOfSeq ) { #ifndef QT_NO_CONCURRENT @@ -812,16 +816,17 @@ bool VideoSubWindow::goToNextFrame( bool bThreaded ) if( bThreaded ) { m_cReadResult = QtConcurrent::run( m_pCurrStream, &CalypStream::readNextFrameFillRGBBuffer ); - refreshFrame(); + refreshFrame( bThreaded ); } else #endif { - refreshFrame(); + refreshFrame( bThreaded ); +#ifndef CALYP_MANAGED_RESOURCES m_pCurrStream->readNextFrameFillRGBBuffer(); +#endif } } -#endif return bEndOfSeq; } diff --git a/lib/CalypStream.cpp b/lib/CalypStream.cpp index 04e4590..70e8d84 100644 --- a/lib/CalypStream.cpp +++ b/lib/CalypStream.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "CalypFrame.h" #include "CalypStreamHandlerIf.h" @@ -206,7 +208,7 @@ private: class CalypStream::CalypStreamPrivate { public: - std::mutex mutex; + std::recursive_mutex mutex; bool isInit; bool isInput; @@ -214,7 +216,7 @@ public: CalypStreamHandlerIf* handler; CreateStreamHandlerFn pfctCreateHandler; - std::vector framePool; + std::vector> framePool; std::deque> frameFifo; std::size_t bufferIdx{ 0 }; @@ -240,9 +242,6 @@ public: void close() { - if( !isInit ) - return; - if( handler ) { handler->closeHandler(); @@ -251,6 +250,8 @@ public: bLoadAll = false; isInit = false; + framePool.clear(); + frameFifo.clear(); } void increasePool( std::size_t newSize ) @@ -259,11 +260,11 @@ public: auto oldSize = framePool.size(); for( std::size_t i = oldSize; i < newSize; i++ ) { - framePool.push_back( CalypFrame{ framePool[0].getWidth(), - framePool[0].getHeight(), - framePool[0].getPelFormat(), - framePool[0].getBitsPel(), - framePool[0].getHasNegativeValues() } ); + framePool.push_back( std::make_unique( framePool[0]->getWidth(), + framePool[0]->getHeight(), + framePool[0]->getPelFormat(), + framePool[0]->getBitsPel(), + framePool[0]->getHasNegativeValues() ) ); } } @@ -275,23 +276,36 @@ public: if( bLoadAll ) return true; + const std::lock_guard lock( mutex ); + mutex.lock(); assert( bufferIdx > 0 ); bufferIdx--; - CalypFrame& frame = framePool[bufferIdx]; + auto frame = framePool[bufferIdx].release(); + mutex.unlock(); - if( !handler->read( frame ) ) + if( !handler->read( *frame ) ) { throw CalypFailure( "CalypStream", "Cannot read frame from stream" ); return false; } if( fillRgbBuffer ) { - frame.fillRGBBuffer(); + frame->fillRGBBuffer(); } - frameFifo.push_back( - std::shared_ptr{ - new CalypFrame{ std::move( frame ) }, - [this]( CalypFrame* p ) { framePool[bufferIdx] = std::move( *p ); bufferIdx++; } } ); + + 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; } }; @@ -448,7 +462,13 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei d->framePool.reserve( bufferSize ); for( std::size_t i = 0; i < bufferSize; i++ ) { - d->framePool.push_back( CalypFrame{ d->handler->m_uiWidth, d->handler->m_uiHeight, d->handler->m_iPixelFormat, d->handler->m_uiBitsPerPixel, hasNegative } ); + d->framePool.push_back( + std::make_unique( + d->handler->m_uiWidth, + d->handler->m_uiHeight, + d->handler->m_iPixelFormat, + d->handler->m_uiBitsPerPixel, + hasNegative ) ); } } catch( CalypFailure& e ) @@ -461,7 +481,9 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei d->frameFifo.clear(); d->bufferIdx = d->framePool.size(); - d->handler->m_uiNBytesPerFrame = d->framePool[0].getBytesPerFrame(); + const CalypFrame& refFrame = *d->framePool[0]; + + d->handler->m_uiNBytesPerFrame = refFrame.getBytesPerFrame(); // Some handlers need to know how long is a frame to get frame number d->handler->calculateFrameNumber(); @@ -473,7 +495,7 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - if( !d->handler->configureBuffer( d->framePool[0] ) ) + if( !d->handler->configureBuffer( refFrame ) ) { d->close(); throw CalypFailure( "CalypStream", "Cannot allocated buffers" ); @@ -491,15 +513,17 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei bool CalypStream::reload() { + d->frameFifo.clear(); d->handler->closeHandler(); if( !d->handler->openHandler( d->cFilename, d->isInput ) ) { throw CalypFailure( "CalypStream", "Cannot open stream " + d->cFilename + " with the " + ClpString( d->handler->m_pchHandlerName ) + " handler" ); } - d->handler->m_uiNBytesPerFrame = d->framePool[0].getBytesPerFrame(); + const CalypFrame& refFrame = *d->framePool[0]; + d->handler->m_uiNBytesPerFrame = refFrame.getBytesPerFrame(); d->handler->calculateFrameNumber(); - d->handler->configureBuffer( d->framePool[0] ); + d->handler->configureBuffer( *d->framePool[0] ); 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 ) @@ -579,6 +603,16 @@ void CalypStream::getFormat( unsigned int& rWidth, unsigned int& rHeight, int& r } } +auto CalypStream::hasNextFrame() -> bool +{ + return d->frameFifo.size() > 1; +} + +auto CalypStream::hasWritingSlot() -> bool +{ + return !d->bLoadAll && d->bufferIdx > 0; +} + /** * @brief Read operations */ @@ -607,22 +641,6 @@ void CalypStream::loadAll() d->iCurrFrameNum = 0; } -// auto CalypStream::retrieveNextFrame() -> bool -// { -// const std::lock_guard lock( d->mutex ); -// bool bEndOfSeq = false; -// if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) -// { -// d->iCurrFrameNum++; -// d->currentFrame = d->frameBuffer->retrieveFrame(); -// } -// else -// { -// bEndOfSeq = true; -// } -// return bEndOfSeq; -// } - std::unique_ptr CalypStream::getCurrFrame( std::unique_ptr buffer ) { if( buffer == nullptr ) @@ -646,23 +664,28 @@ auto CalypStream::getCurrFrame() -> CalypFrame* return d->frameFifo.front().get(); } +bool CalypStream::isEof() +{ + if( d->iCurrFrameNum + 1 >= (long)( d->handler->m_uiTotalNumberFrames ) ) + { + return true; + } + return false; +} + bool CalypStream::setNextFrame() { - bool bEndOfSeq = false; - - if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) + if( isEof() ) { - d->iCurrFrameNum++; - if( !d->bLoadAll ) - { - d->frameFifo.pop_front(); - } + return true; } - else + d->iCurrFrameNum++; + if( !d->bLoadAll ) { - bEndOfSeq = true; + assert( d->frameFifo.size() > 1 ); + d->frameFifo.pop_front(); } - return bEndOfSeq; + return false; } void CalypStream::readNextFrame() @@ -675,11 +698,6 @@ void CalypStream::readNextFrameFillRGBBuffer() d->readNextFrame( true ); } -auto CalypStream::hasWritingSlot() -> bool -{ - return !d->bLoadAll && d->bufferIdx > 0; -} - /** * @brief Write operations */ @@ -733,7 +751,7 @@ 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->mutex ); if( !d->isInit || new_frame_num >= d->handler->m_uiTotalNumberFrames || long( new_frame_num ) == d->iCurrFrameNum ) return false; diff --git a/lib/CalypStream.h b/lib/CalypStream.h index 60e24a4..b420bb6 100644 --- a/lib/CalypStream.h +++ b/lib/CalypStream.h @@ -98,21 +98,18 @@ public: void getFormat( unsigned int& rWidth, unsigned int& rHeight, int& rInputFormat, unsigned int& rBitsPerPel, int& rEndianness, unsigned int& rFrameRate ) const; + auto hasNextFrame() -> bool; + auto hasWritingSlot() -> bool; + void loadAll(); - - // continuous read using smart ptrs - // auto retrieveNextFrame() -> bool; - - // continuous read control std::unique_ptr getCurrFrame( std::unique_ptr buffer ); auto getCurrFrameAsset() -> std::shared_ptr; auto getCurrFrame() -> CalypFrame*; + bool isEof(); bool setNextFrame(); void readNextFrame(); void readNextFrameFillRGBBuffer(); - auto hasWritingSlot() -> bool; - void writeFrame( const CalypFrame& pcFrame ); bool saveFrame( const ClpString& filename );