diff --git a/.gitignore b/.gitignore index 154a643..6ed9357 100644 --- a/.gitignore +++ b/.gitignore @@ -144,4 +144,6 @@ doc/ # CLang compile_commands.json -build_release/* \ No newline at end of file + +# Build dirs +build* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d8e84..ec1860f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ OPTION(BUILD_EXAMPLES "Build Examples" OFF) OPTION(BUILD_DOC "Build Documentation" OFF) OPTION(BUILD_TESTS "Build Google Tests" OFF) OPTION(BUILD_TESTS_CATCH2 "Build Catch2 Tests" OFF) +OPTION(BUILD_WITH_SANITIZERS "Build with sanitizers options" OFF) OPTION(USE_FERVOR "Add Fervor support" OFF) @@ -250,6 +251,9 @@ IF(USE_WERROR) ENDIF() SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") +IF(BUILD_WITH_SANITIZERS) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fsanitize=undefined") +ENDIF() # #################################################################################################################################################### # Configure targets diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e114a70..c68ac29 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,7 +9,7 @@ INCLUDE_DIRECTORIES( OPTION(USE_QTDBUS "Build with QtDBus" ON) OPTION(USE_FERVOR "Add Fervor support" OFF) -OPTION(USE_RESOURCES "Handle streams in separate threads" ON) +OPTION(CALYP_MANAGED_RESOURCES "Handle streams in separate threads" ON) ADD_SUBDIRECTORY(external) diff --git a/app/CalypAppModuleIf.cpp b/app/CalypAppModuleIf.cpp index 8fd5ee0..6e83c21 100644 --- a/app/CalypAppModuleIf.cpp +++ b/app/CalypAppModuleIf.cpp @@ -33,21 +33,38 @@ #include "lib/CalypStream.h" CalypAppModuleIf::CalypAppModuleIf( QObject* parent, QAction* action, CalypModulePtr&& module ) - : m_bIsRunning( false ) - , m_pcModuleAction( action ) - , m_pcModule( std ::move( module ) ) - , m_pcDisplaySubWindow( NULL ) - , m_pcDockWidget( NULL ) - , m_pcModuleDock( NULL ) - , m_pcModuleStream( NULL ) - , m_pcProcessedFrame( NULL ) - , m_dMeasurementResult( 0 ) + : m_pcModuleAction( action ), m_pcModule( std ::move( module ) ) { setParent( parent ); - for( int i = 0; i < CLP_MODULE_MAX_NUM_FRAMES; i++ ) + m_frameList.reserve( m_pcModule->m_uiNumberOfFrames ); + m_frameListPtr.reserve( m_pcModule->m_uiNumberOfFrames ); + m_pcSubWindow.resize( m_pcModule->m_uiNumberOfFrames, nullptr ); +} + +CalypAppModuleIf::~CalypAppModuleIf() +{ + while( m_bIsRunning ) { - m_pcSubWindow[i] = NULL; } + + if( m_pcDockWidget ) + { + m_pcDockWidget->close(); + } + + for( auto& window : m_pcSubWindow ) + { + if( window != nullptr ) + window->disableModule( this ); + window = nullptr; + } + if( m_pcModule ) + { + m_pcModule->destroy(); + m_pcModule = nullptr; + } + + //assert( m_pcProcessedFrame.use_count() == 1 ); } void CalypAppModuleIf::update( bool isPlaying ) @@ -97,6 +114,12 @@ bool CalypAppModuleIf::apply( bool isPlaying, bool disableThreads ) } if( !( isPlaying && ( m_pcModule->m_uiModuleRequirements & CLP_MODULE_REQUIRES_SKIP_WHILE_PLAY ) ) ) { + m_frameList.clear(); + for( unsigned int i = 0; i < m_pcModule->m_uiNumberOfFrames; i++ ) + { + m_frameList.push_back( m_pcSubWindow[i]->getCurrFrameAsset() ); + } + #ifdef CALYP_THREADED_MODULES if( !disableThreads ) { @@ -127,28 +150,34 @@ void CalypAppModuleIf::run() { m_bIsRunning = true; m_bSuccess = false; - std::vector apcFrameList; - for( unsigned int i = 0; i < m_pcModule->m_uiNumberOfFrames; i++ ) + + QMutexLocker locker( &m_Mutex ); + + m_frameListPtr.clear(); + for( auto& frame : m_frameList ) { - apcFrameList.push_back( m_pcSubWindow[i]->getCurrFrame() ); + m_frameListPtr.push_back( frame.get() ); } if( m_pcModule->m_iModuleType == CLP_FRAME_PROCESSING_MODULE ) { + CalypFrame* framePtr{ nullptr }; if( m_pcModule->m_iModuleAPI >= CLP_MODULE_API_2 ) { - m_pcProcessedFrame = m_pcModule->process( apcFrameList ); + framePtr = m_pcModule->process( m_frameListPtr ); } else { - m_pcProcessedFrame = m_pcModule->process( m_pcSubWindow[0]->getCurrFrame() ); + framePtr = m_pcModule->process( m_pcSubWindow[0]->getCurrFrame() ); } + assert( framePtr != nullptr ); + m_pcProcessedFrame = std::shared_ptr{ framePtr, []( CalypFrame* ptr ) {} }; } else if( m_pcModule->m_iModuleType == CLP_FRAME_MEASUREMENT_MODULE ) { if( m_pcModule->m_iModuleAPI >= CLP_MODULE_API_2 ) { - m_dMeasurementResult = m_pcModule->measure( apcFrameList ); + m_dMeasurementResult = m_pcModule->measure( m_frameListPtr ); } else { @@ -193,44 +222,22 @@ void CalypAppModuleIf::show() void CalypAppModuleIf::destroy() { - if( m_bIsRunning ) - { - QApplication::setOverrideCursor( Qt::WaitCursor ); - while( m_bIsRunning ) - { - } - QApplication::restoreOverrideCursor(); - } + QApplication::setOverrideCursor( Qt::WaitCursor ); + QMutexLocker locker( &m_Mutex ); + QApplication::restoreOverrideCursor(); + + m_frameList.clear(); + m_frameListPtr.clear(); if( m_pcModuleDock ) { - m_pcModuleDock->close(); + auto* ptr = m_pcModuleDock; m_pcModuleDock = NULL; - } - if( m_pcDockWidget ) - { - m_pcDockWidget->close(); - m_pcDockWidget = NULL; + ptr->close(); } if( m_pcDisplaySubWindow ) - m_pcDisplaySubWindow->closeSubWindow(); - m_pcDisplaySubWindow = NULL; - - for( int i = 0; i < CLP_MODULE_MAX_NUM_FRAMES; i++ ) { - if( m_pcSubWindow[i] ) - { - m_pcSubWindow[i]->disableModule( this ); - m_pcSubWindow[i] = NULL; - } - } - if( m_pcModuleStream ) - { - delete m_pcModuleStream; - m_pcModuleStream = NULL; - } - if( m_pcModule ) - { - m_pcModule->destroy(); - m_pcModule = nullptr; + auto* ptr = m_pcDisplaySubWindow; + m_pcDisplaySubWindow = NULL; + ptr->closeSubWindow(); } } diff --git a/app/CalypAppModuleIf.h b/app/CalypAppModuleIf.h index 16f4fc5..801f39c 100644 --- a/app/CalypAppModuleIf.h +++ b/app/CalypAppModuleIf.h @@ -33,6 +33,7 @@ #include "config.h" #ifdef CALYP_THREADED_MODULES +#include #include #endif @@ -62,24 +63,6 @@ class CalypAppModuleIf friend class ModuleHandleDock; friend class ModulesHandleOptDialog; -private: - bool m_bIsRunning; - bool m_bSuccess; - - QAction* m_pcModuleAction; - CalypModulePtr m_pcModule; - - VideoSubWindow* m_pcSubWindow[CLP_MODULE_MAX_NUM_FRAMES]; - - VideoSubWindow* m_pcDisplaySubWindow; - - QDockWidget* m_pcDockWidget; - ModuleHandleDock* m_pcModuleDock; - - CalypStream* m_pcModuleStream; - CalypFrame* m_pcProcessedFrame; - double m_dMeasurementResult; - public: class EventData : public QEvent { @@ -95,15 +78,9 @@ public: }; CalypAppModuleIf( QObject* parent, QAction* action, CalypModulePtr&& module ); - virtual ~CalypAppModuleIf() {} - QList getSubWindowList() - { - QList arraySubWindows; - for( int i = 0; i < CLP_MODULE_MAX_NUM_FRAMES; i++ ) - if( m_pcSubWindow[i] ) - arraySubWindows.append( m_pcSubWindow[i] ); - return arraySubWindows; - } + ~CalypAppModuleIf(); + + auto getSubWindowList() -> const std::vector& { return m_pcSubWindow; } CalypModuleIf* getModule() { return m_pcModule.get(); } unsigned int getModuleRequirements() { return m_pcModule->m_uiModuleRequirements; } @@ -117,6 +94,32 @@ public: protected: virtual void run(); + +private: + bool m_bIsRunning{ false }; + bool m_bSuccess{ false }; + + QAction* m_pcModuleAction{ nullptr }; + CalypModulePtr m_pcModule{ nullptr }; + + std::vector m_pcSubWindow; + + VideoSubWindow* m_pcDisplaySubWindow{ nullptr }; + + QDockWidget* m_pcDockWidget{ nullptr }; + ModuleHandleDock* m_pcModuleDock{ nullptr }; + + std::unique_ptr m_pcModuleStream{ nullptr }; + + std::vector> m_frameList; + std::vector m_frameListPtr; + + std::shared_ptr m_pcProcessedFrame{ nullptr }; + double m_dMeasurementResult{ 0 }; + +#ifdef CALYP_THREADED_MODULES + QMutex m_Mutex; +#endif }; #endif // __CALYPAPPMODULESIF_H__ diff --git a/app/ModulesHandle.cpp b/app/ModulesHandle.cpp index 01d94e6..3904a2d 100644 --- a/app/ModulesHandle.cpp +++ b/app/ModulesHandle.cpp @@ -184,7 +184,7 @@ void ModulesHandle::updateMenus() if( pcSubWindow ) { - QList apcCurrentModule = pcSubWindow->getModuleArray(); + auto apcCurrentModule = pcSubWindow->getModuleArray(); m_arrayActions[DISABLE_ACT]->setEnabled( apcCurrentModule.size() > 0 ); if( pcSubWindow->getDisplayModule() ) { @@ -276,7 +276,7 @@ void ModulesHandle::activateModule() QString ModuleIfName = pcAction->data().toString(); auto pcCurrModuleIf = CalypModulesFactory::Get()->CreateModule( ModuleIfName.toLocal8Bit().constData() ); - CalypAppModuleIf* pcCurrAppModuleIf = new CalypAppModuleIf( this, pcAction, std::move( pcCurrModuleIf ) ); + auto pcCurrAppModuleIf = std::make_unique( this, pcAction, std::move( pcCurrModuleIf ) ); QList videoSubWindowList; int numberOfFrames = pcCurrAppModuleIf->m_pcModule->m_uiNumberOfFrames; @@ -333,7 +333,7 @@ void ModulesHandle::activateModule() { videoSubWindowList.clear(); qobject_cast( m_pcParent )->printMessage( "Error! Incompatible frames", CLP_LOG_ERROR ); - destroyModuleIf( pcCurrAppModuleIf ); + //destroyModuleIf( pcCurrAppModuleIf ); return; } } @@ -348,7 +348,7 @@ void ModulesHandle::activateModule() { qobject_cast( m_pcParent ) ->printMessage( "Error! There is no windows to apply the module", CLP_LOG_ERROR ); - destroyModuleIf( pcCurrAppModuleIf ); + //destroyModuleIf( pcCurrAppModuleIf ); return; } @@ -359,11 +359,11 @@ void ModulesHandle::activateModule() if( pcCurrAppModuleIf->m_pcModule->m_uiModuleRequirements & CLP_MODULE_REQUIRES_OPTIONS ) { - ModulesHandleOptDialog moduleOptDialog( m_pcParent, pcCurrAppModuleIf ); + ModulesHandleOptDialog moduleOptDialog( m_pcParent, pcCurrAppModuleIf.get() ); if( moduleOptDialog.runConfiguration() == QDialog::Rejected ) { qobject_cast( m_pcParent )->printMessage( "Module canceled by user!", CLP_LOG_WARNINGS ); - destroyModuleIf( pcCurrAppModuleIf ); + //destroyModuleIf( pcCurrAppModuleIf ); return; } } @@ -392,7 +392,7 @@ void ModulesHandle::activateModule() else if( pcCurrAppModuleIf->m_pcModule->m_iModuleType == CLP_FRAME_MEASUREMENT_MODULE ) { pcCurrAppModuleIf->m_pcDisplaySubWindow = NULL; - pcCurrAppModuleIf->m_pcModuleDock = new ModuleHandleDock( m_pcParent, pcCurrAppModuleIf ); + pcCurrAppModuleIf->m_pcModuleDock = new ModuleHandleDock( m_pcParent, pcCurrAppModuleIf.get() ); QString titleDockWidget; titleDockWidget.append( pcCurrAppModuleIf->m_pcModule->m_pchModuleName ); titleDockWidget.append( " Information" ); @@ -404,19 +404,9 @@ void ModulesHandle::activateModule() ->addDockWidget( Qt::RightDockWidgetArea, pcCurrAppModuleIf->m_pcDockWidget ); } - // Associate module with subwindows - if( !pcCurrAppModuleIf->m_pcDisplaySubWindow && !pcCurrAppModuleIf->m_pcModuleDock ) + for( int i = 0; i < videoSubWindowList.size(); i++ ) { - pcCurrAppModuleIf->m_pcSubWindow[0]->enableModule( pcCurrAppModuleIf ); - } - else - { - if( pcCurrAppModuleIf->m_pcDisplaySubWindow ) - pcCurrAppModuleIf->m_pcDisplaySubWindow->enableModule( pcCurrAppModuleIf ); - for( int i = 0; i < videoSubWindowList.size(); i++ ) - { - pcCurrAppModuleIf->m_pcSubWindow[i]->associateModule( pcCurrAppModuleIf ); - } + pcCurrAppModuleIf->m_pcSubWindow[i]->associateModule( pcCurrAppModuleIf.get() ); } // Create Module @@ -439,11 +429,12 @@ void ModulesHandle::activateModule() if( !moduleCreated ) { qobject_cast( m_pcParent )->printMessage( "Error! Module cannot be created", CLP_LOG_ERROR ); - destroyModuleIf( pcCurrAppModuleIf ); + //destroyModuleIf( pcCurrAppModuleIf ); return; } pcCurrAppModuleIf->apply( false, true ); + QCoreApplication::processEvents(); if( pcModuleSubWindow ) @@ -461,7 +452,19 @@ void ModulesHandle::activateModule() videoSubWindowList.at( 0 )->setWindowName( windowName ); } - m_pcCalypAppModuleIfList.append( pcCurrAppModuleIf ); + // Change ownership of the module + if( !pcCurrAppModuleIf->m_pcDisplaySubWindow && !pcCurrAppModuleIf->m_pcModuleDock ) + { + pcCurrAppModuleIf->m_pcSubWindow[0]->enableModule( std::move( pcCurrAppModuleIf ) ); + } + else if( pcCurrAppModuleIf->m_pcDisplaySubWindow ) + { + pcCurrAppModuleIf->m_pcDisplaySubWindow->enableModule( std::move( pcCurrAppModuleIf ) ); + } + else if( pcCurrAppModuleIf->m_pcModuleDock ) + { + pcCurrAppModuleIf->m_pcModuleDock->enableModule( std::move( pcCurrAppModuleIf ) ); + } emit changed(); } @@ -548,12 +551,11 @@ void ModulesHandle::applyAllModuleIf( CalypAppModuleIf* pcCurrModuleIf ) BitsPixel = pcCurrModuleIf->m_pcProcessedFrame->getBitsPel(); FrameRate = pcCurrModuleIf->m_pcSubWindow[0]->getInputStream()->getFrameRate(); - pcCurrModuleIf->m_pcModuleStream = new CalypStream; + pcCurrModuleIf->m_pcModuleStream = std::unique_ptr(); if( !pcCurrModuleIf->m_pcModuleStream->open( fileName.toStdString(), Width, Height, InputFormat, BitsPixel, CLP_LITTLE_ENDIAN, FrameRate, false ) ) { - delete pcCurrModuleIf->m_pcModuleStream; - pcCurrModuleIf->m_pcModuleStream = NULL; + pcCurrModuleIf->m_pcModuleStream = nullptr; return; } } diff --git a/app/ResourceHandle.cpp b/app/ResourceHandle.cpp index c61f7b7..2a76c17 100644 --- a/app/ResourceHandle.cpp +++ b/app/ResourceHandle.cpp @@ -76,11 +76,13 @@ ResourceHandle::ResourceHandle() auto ResourceHandle::addResource() -> std::size_t { + auto resource_id = unique_id; + unique_id++; auto newStreamResource = std::make_shared(); auto newStreamResourceWorker = std::make_unique( newStreamResource ); - m_apcStreamResourcesList.push_back( newStreamResource ); - m_apcStreamResourcesWorkersList.push_back( std::move( newStreamResourceWorker ) ); - return m_apcStreamResourcesList.size() - 1; + m_apcStreamResourcesList[resource_id] = newStreamResource; + m_apcStreamResourcesWorkersList[resource_id] = std::move( newStreamResourceWorker ); + return resource_id; } auto ResourceHandle::getResource( CalypStream* ptr ) -> std::size_t @@ -98,7 +100,7 @@ auto ResourceHandle::getResource( CalypStream* ptr ) -> std::size_t auto ResourceHandle::getResourceAsset( std::size_t id ) -> CalypStream* { - if( id < m_apcStreamResourcesList.size() ) + if( m_apcStreamResourcesWorkersList.contains( id ) ) { return m_apcStreamResourcesList[id].get(); } @@ -107,7 +109,7 @@ auto ResourceHandle::getResourceAsset( std::size_t id ) -> CalypStream* void ResourceHandle::removeResource( std::size_t id ) { - if( id >= m_apcStreamResourcesList.size() ) + if( !m_apcStreamResourcesWorkersList.contains( id ) ) { assert( false ); return; @@ -115,15 +117,15 @@ void ResourceHandle::removeResource( std::size_t id ) // Remove worker first m_apcStreamResourcesWorkersList[id]->stop(); - m_apcStreamResourcesWorkersList.erase( m_apcStreamResourcesWorkersList.begin() + id ); + m_apcStreamResourcesWorkersList[id] = nullptr; // Then the underlying stream - m_apcStreamResourcesList.erase( m_apcStreamResourcesList.begin() + id ); + m_apcStreamResourcesList[id] = nullptr; } void ResourceHandle::startResourceWorker( std::size_t id ) { - if( id >= m_apcStreamResourcesList.size() ) + if( !m_apcStreamResourcesWorkersList.contains( id ) ) { assert( false ); return; @@ -136,7 +138,7 @@ void ResourceHandle::startResourceWorker( std::size_t id ) void ResourceHandle::wakeResourceWorker( std::size_t id ) { - if( id >= m_apcStreamResourcesList.size() ) + if( !m_apcStreamResourcesWorkersList.contains( id ) ) { assert( false ); return; diff --git a/app/ResourceHandle.h b/app/ResourceHandle.h index 29c05a6..007e952 100644 --- a/app/ResourceHandle.h +++ b/app/ResourceHandle.h @@ -64,8 +64,9 @@ private: auto addResource() -> std::size_t; private: - std::vector> m_apcStreamResourcesList; - std::vector> m_apcStreamResourcesWorkersList; + std::size_t unique_id{ 0 }; + std::map> m_apcStreamResourcesList; + std::map> m_apcStreamResourcesWorkersList; }; #endif // __RESOURCEHANDLE_H__ diff --git a/app/VideoHandle.cpp b/app/VideoHandle.cpp index 28d53cd..eb33f51 100644 --- a/app/VideoHandle.cpp +++ b/app/VideoHandle.cpp @@ -29,8 +29,10 @@ #include #include #include +#include #include #include +#include #include "FrameNumberWidget.h" #include "FramePropertiesDock.h" @@ -45,18 +47,15 @@ VideoHandle::VideoHandle( QWidget* parent, SubWindowHandle* windowManager ) { m_pcCurrentVideoSubWindow = NULL; m_bIsPlaying = false; - m_pcPlayingTimer = new QTimer; - m_pcFrameRateFeedbackTimer = new QElapsedTimer; + m_pcPlayingTimer = new QTimer( this ); + m_pcFrameRateFeedbackTimer = std::make_unique(); m_pcPlayingTimer->setTimerType( Qt::PreciseTimer ); - connect( m_pcPlayingTimer, SIGNAL( timeout() ), this, SLOT( playEvent() ) ); + connect( m_pcPlayingTimer, &QTimer::timeout, + this, &VideoHandle::playEvent ); m_acPlayingSubWindows.clear(); } -VideoHandle::~VideoHandle() -{ - delete m_pcPlayingTimer; - delete m_pcFrameRateFeedbackTimer; -} +VideoHandle::~VideoHandle() = default; void VideoHandle::createActions() { @@ -363,7 +362,6 @@ void VideoHandle::update() } } m_pcResolutionLabel->setText( resolution ); - m_pcFramePropertiesSideBar->setFrame( m_pcCurrentVideoSubWindow->getCurrFrameAsset(), m_pcCurrentVideoSubWindow->isPlaying() ); m_pcFrameNumInfo->setTotalFrameNum( total_frame_num ); @@ -447,6 +445,10 @@ void VideoHandle::closeSubWindow( SubWindowAbstract* subWindow ) m_arrayActions[VIDEO_LOCK_ACT]->setVisible( false ); } } + if( subWindow == m_pcCurrentVideoSubWindow ) + { + m_pcFramePropertiesSideBar->reset(); + } } void VideoHandle::zoomToFactorAll( const double scale, const QPoint center ) diff --git a/app/VideoHandle.h b/app/VideoHandle.h index 50f95fb..882905e 100644 --- a/app/VideoHandle.h +++ b/app/VideoHandle.h @@ -25,6 +25,7 @@ #ifndef __VIDEOHANDLE_H__ #define __VIDEOHANDLE_H__ +#include #include #include #include @@ -39,13 +40,13 @@ class QDockWidget; class QSignalMapper; class QLabel; class QSlider; -class QElapsedTimer; class SubWindowHandle; class SubWindowAbstract; class VideoSubWindow; class FramePropertiesDock; class FrameNumberWidget; +class QTimer; class VideoHandle : public QObject { @@ -121,9 +122,9 @@ private: QTimer* m_pcPlayingTimer; bool m_bIsPlaying; - unsigned int m_uiNumberPlayedFrames; - unsigned int m_uiRealAverageFrameRate; - QElapsedTimer* m_pcFrameRateFeedbackTimer; + unsigned int m_uiNumberPlayedFrames{ 0 }; + unsigned int m_uiRealAverageFrameRate{ 0 }; + std::unique_ptr m_pcFrameRateFeedbackTimer; void configureFrameRateTimer(); void calculateRealFrameRate(); diff --git a/app/VideoSubWindow.cpp b/app/VideoSubWindow.cpp index fbacffd..75e7866 100644 --- a/app/VideoSubWindow.cpp +++ b/app/VideoSubWindow.cpp @@ -150,8 +150,6 @@ VideoSubWindow::VideoSubWindow( enum VideoSubWindowCategories category, QWidget* , m_pcResourceManager( nullptr ) , m_bWindowBusy( false ) , m_pCurrStream( NULL ) - , m_pcCurrFrame( NULL ) - , m_pcCurrentDisplayModule( NULL ) , m_pcReferenceSubWindow( NULL ) , m_bIsPlaying( false ) , m_pcUpdateTimer( NULL ) @@ -186,7 +184,7 @@ VideoSubWindow::VideoSubWindow( enum VideoSubWindowCategories category, QWidget* m_pcScrollArea->setWidgetResizable( true ); setWidget( m_pcScrollArea ); - m_apcCurrentModule.clear(); + m_associatedModules.clear(); m_pcUpdateTimer = new QTimer(); m_pcUpdateTimer->setInterval( 800 ); @@ -198,9 +196,15 @@ VideoSubWindow::VideoSubWindow( enum VideoSubWindowCategories category, QWidget* VideoSubWindow::~VideoSubWindow() { - disableModule(); - m_pcResourceManager->removeResource( m_uiResourceId ); - //delete m_cViewArea; + std::vector tmpModules = m_associatedModules; + m_associatedModules.clear(); + for( auto module : tmpModules ) + { + module->destroy(); + } + + if( m_pcResourceManager ) + m_pcResourceManager->removeResource( m_uiResourceId ); delete m_pcUpdateTimer; } @@ -275,8 +279,8 @@ QSize VideoSubWindow::sizeHint() const QSize VideoSubWindow::sizeHint( const QSize& maxSize ) const { QSize isize; - if( m_pcCurrFrame ) - isize = QSize( m_pcCurrFrame->getWidth() + 50, m_pcCurrFrame->getHeight() + 50 ); + if( m_pcCurrFrameAsset ) + isize = QSize( m_pcCurrFrameAsset->getWidth() + 50, m_pcCurrFrameAsset->getHeight() + 50 ); else if( m_pCurrStream ) isize = QSize( m_pCurrStream->getWidth() + 50, m_pCurrStream->getHeight() + 50 ); @@ -385,7 +389,7 @@ bool VideoSubWindow::loadFile( QString cFilename, bool bForceDialog ) var.setValue( BitsPel ); appSettings.setValue( "VideoSubWindow/LastBitsPerPixel", var ); -#ifdef USE_RESOURCES +#ifdef CALYP_MANAGED_RESOURCES m_pcResourceManager->startResourceWorker( m_uiResourceId ); #endif @@ -417,7 +421,7 @@ bool VideoSubWindow::loadFile( CalypFileInfo* streamInfo ) m_sStreamInfo = *streamInfo; -#ifdef USE_RESOURCES +#ifdef CALYP_MANAGED_RESOURCES m_pcResourceManager->startResourceWorker( m_uiResourceId ); #endif @@ -437,15 +441,15 @@ void VideoSubWindow::updateVideoWindowInfo() if( m_pcCurrentDisplayModule ) { m_cStreamInformation = "Module"; - QList arraySubWindows = m_pcCurrentDisplayModule->getSubWindowList(); + const auto& arraySubWindows = m_pcCurrentDisplayModule->getSubWindowList(); QStringList windowInfoList; if( arraySubWindows.size() > 0 ) { - for( int i = 0; i < arraySubWindows.size(); i++ ) + for( std::size_t i = 0; i < arraySubWindows.size(); i++ ) { - if( arraySubWindows.at( i )->getWindowName() != getWindowName() ) + if( arraySubWindows[i]->getWindowName() != getWindowName() ) { - windowInfoList.append( QString( "Input %1 - " + arraySubWindows.at( i )->getWindowName() ).arg( i + 1 ) ); + windowInfoList.append( QString( "Input %1 - " + arraySubWindows[i]->getWindowName() ).arg( i + 1 ) ); } } } @@ -454,7 +458,6 @@ void VideoSubWindow::updateVideoWindowInfo() QStringList list = QString::fromStdString( m_pcCurrentDisplayModule->moduleInfo() ).split( '\n' ); windowInfoList.append( list ); } - // qDebug( ) << sourceWindowList; if( windowInfoList.size() > 0 ) { m_pcVideoInfo->setInformationTopLeft( windowInfoList ); @@ -466,16 +469,14 @@ void VideoSubWindow::updateVideoWindowInfo() QString m_cCodedName = QString::fromStdString( m_pCurrStream->getCodecName() ); m_cStreamInformation = m_cFormatName + " | " + m_cCodedName; } - //#if 0 - if( m_pcCurrFrame ) + if( m_pcCurrFrameAsset ) { - QString m_cPelFmtName = QString::fromStdString( m_pcCurrFrame->getPelFmtName() ); + QString m_cPelFmtName = QString::fromStdString( m_pcCurrFrameAsset->getPelFmtName() ); if( m_pCurrStream ) if( !m_pCurrStream->isNative() ) m_cPelFmtName += "*"; m_cStreamInformation += " | " + m_cPelFmtName; } - //#endif if( m_cStreamInformation.isEmpty() ) { m_cStreamInformation = " "; @@ -643,13 +644,14 @@ void VideoSubWindow::updateSelectedArea( QRect area ) * Functions to enable a module in the * current SubWindow */ -void VideoSubWindow::enableModule( CalypAppModuleIf* pcModule ) +void VideoSubWindow::enableModule( std::unique_ptr&& pcModule ) { - if( m_pcCurrentDisplayModule ) + auto it = std::find( m_associatedModules.begin(), m_associatedModules.end(), pcModule.get() ); + if( it != m_associatedModules.end() ) { - disableModule( m_pcCurrentDisplayModule ); + m_associatedModules.erase( it ); } - m_pcCurrentDisplayModule = pcModule; + m_pcCurrentDisplayModule = std::move( pcModule ); updateVideoWindowInfo(); } @@ -658,41 +660,50 @@ void VideoSubWindow::disableModule( CalypAppModuleIf* pcModule ) bool bRefresh = false; if( pcModule ) { - int modIdx = m_apcCurrentModule.indexOf( pcModule ); - if( modIdx != -1 ) + auto it = std::find( m_associatedModules.begin(), m_associatedModules.end(), pcModule ); + if( it != m_associatedModules.end() ) { - m_apcCurrentModule.removeAt( modIdx ); - ModulesHandle::destroyModuleIf( pcModule ); - bRefresh |= true; - } - if( pcModule == m_pcCurrentDisplayModule ) - { - pcModule = m_pcCurrentDisplayModule; - m_pcCurrentDisplayModule = 0; - ModulesHandle::destroyModuleIf( pcModule ); - setWindowName( QFileInfo( m_cFilename ).fileName() ); - bRefresh |= true; - } - } - else - { - QList apcCurrentModule = m_apcCurrentModule; - for( int i = 0; i < apcCurrentModule.size(); i++ ) - { - m_apcCurrentModule.removeOne( apcCurrentModule.at( i ) ); - ModulesHandle::destroyModuleIf( apcCurrentModule.at( i ) ); - bRefresh |= true; - } - assert( m_apcCurrentModule.size() == 0 ); - if( m_pcCurrentDisplayModule ) - { - pcModule = m_pcCurrentDisplayModule; - m_pcCurrentDisplayModule = NULL; - ModulesHandle::destroyModuleIf( pcModule ); - setWindowName( QFileInfo( m_cFilename ).fileName() ); + m_associatedModules.erase( it ); bRefresh |= true; } } + // if( pcModule ) + // { + // int modIdx = m_apcCurrentModule.indexOf( pcModule ); + // if( modIdx != -1 ) + // { + // m_apcCurrentModule.removeAt( modIdx ); + // ModulesHandle::destroyModuleIf( pcModule ); + // bRefresh |= true; + // } + // if( pcModule == m_pcCurrentDisplayModule ) + // { + // pcModule = m_pcCurrentDisplayModule; + // m_pcCurrentDisplayModule = 0; + // ModulesHandle::destroyModuleIf( pcModule ); + // setWindowName( QFileInfo( m_cFilename ).fileName() ); + // bRefresh |= true; + // } + // } + // else + // { + // QList apcCurrentModule = m_apcCurrentModule; + // for( int i = 0; i < apcCurrentModule.size(); i++ ) + // { + // m_apcCurrentModule.removeOne( apcCurrentModule.at( i ) ); + // ModulesHandle::destroyModuleIf( apcCurrentModule.at( i ) ); + // bRefresh |= true; + // } + // assert( m_apcCurrentModule.size() == 0 ); + // if( m_pcCurrentDisplayModule ) + // { + // pcModule = m_pcCurrentDisplayModule; + // m_pcCurrentDisplayModule = NULL; + // ModulesHandle::destroyModuleIf( pcModule ); + // setWindowName( QFileInfo( m_cFilename ).fileName() ); + // bRefresh |= true; + // } + // } if( bRefresh ) { refreshFrame(); @@ -702,7 +713,7 @@ void VideoSubWindow::disableModule( CalypAppModuleIf* pcModule ) void VideoSubWindow::associateModule( CalypAppModuleIf* pcModule ) { - m_apcCurrentModule.append( pcModule ); + m_associatedModules.push_back( pcModule ); } bool VideoSubWindow::hasRunningModule() @@ -712,9 +723,9 @@ bool VideoSubWindow::hasRunningModule() { bRet |= m_pcCurrentDisplayModule->isRunning(); } - for( int i = 0; i < m_apcCurrentModule.size() && !bRet; i++ ) + for( int i = 0; i < m_associatedModules.size() && !bRet; i++ ) { - bRet |= m_apcCurrentModule.at( i )->isRunning(); + bRet |= m_associatedModules.at( i )->isRunning(); } return bRet; } @@ -724,16 +735,19 @@ void VideoSubWindow::setFillWindow( bool bFlag ) m_pcVideoInfo->setBusyWindow( bFlag ); } -void VideoSubWindow::setCurrFrame( CalypFrame* pcCurrFrame ) +std::shared_ptr VideoSubWindow::getCurrFrameAsset() { - m_pcCurrFrame = pcCurrFrame; - m_cViewArea->setImage( m_pcCurrFrame ); -} + if( m_pcCurrFrameAsset == nullptr && m_pCurrStream != nullptr ) + { + m_pcCurrFrameAsset = m_pCurrStream->getCurrFrameAsset(); + } + return m_pcCurrFrameAsset; +}; void VideoSubWindow::setCurrFrame( std::shared_ptr pcCurrFrame ) { - m_pcCurrDisplayFrame = pcCurrFrame; - m_cViewArea->setImage( m_pcCurrDisplayFrame.get() ); + m_pcCurrFrameAsset = pcCurrFrame; + m_cViewArea->setImage( m_pcCurrFrameAsset.get() ); } void VideoSubWindow::refreshFrameOperation() @@ -741,26 +755,23 @@ void VideoSubWindow::refreshFrameOperation() bool bSetFrame = false; if( m_pCurrStream ) { -#ifdef USE_RESOURCES - m_pcCurrFrame = m_pCurrStream->getCurrFrameAsset().get(); -#else - m_pcCurrFrame = m_pCurrStream->getCurrFrame(); -#endif + m_pcCurrFrameAsset = m_pCurrStream->getCurrFrameAsset(); + bSetFrame |= true; } - bSetFrame = m_pcCurrFrame ? true : false; + if( m_pcCurrentDisplayModule ) { m_bWindowBusy = true; - m_pcCurrentDisplayModule->apply( m_bIsPlaying, !m_bIsPlaying && m_apcCurrentModule.size() ); + m_pcCurrentDisplayModule->apply( m_bIsPlaying, !m_bIsPlaying && m_associatedModules.size() ); bSetFrame = false; } if( bSetFrame ) { - m_cViewArea->setImage( m_pcCurrFrame ); + m_cViewArea->setImage( m_pcCurrFrameAsset.get() ); } - for( int i = 0; i < m_apcCurrentModule.size(); i++ ) + for( int i = 0; i < m_associatedModules.size(); i++ ) { - m_apcCurrentModule.at( i )->update( m_bIsPlaying ); + m_associatedModules.at( i )->update( m_bIsPlaying ); } } @@ -781,7 +792,7 @@ void VideoSubWindow::refreshFrame( bool bThreaded ) bool VideoSubWindow::goToNextFrame( bool bThreaded ) { -#ifdef USE_RESOURCES +#ifdef CALYP_MANAGED_RESOURCES bool bEndOfSeq = m_pCurrStream->retrieveNextFrame(); m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); if( !bEndOfSeq ) @@ -819,10 +830,10 @@ bool VideoSubWindow::save( QString filename ) bool iRet = false; QApplication::setOverrideCursor( Qt::WaitCursor ); - CalypFrame* saveFrame = m_pcCurrFrame; + CalypFrame* saveFrame = m_pcCurrFrameAsset.get(); if( m_cSelectedArea.isValid() ) { - saveFrame = new CalypFrame( m_pcCurrFrame, m_cSelectedArea.x(), m_cSelectedArea.y(), m_cSelectedArea.width(), + saveFrame = new CalypFrame( m_pcCurrFrameAsset.get(), m_cSelectedArea.x(), m_cSelectedArea.y(), m_cSelectedArea.width(), m_cSelectedArea.height() ); } if( !saveFrame ) @@ -847,7 +858,7 @@ bool VideoSubWindow::saveStream( QString filename ) void VideoSubWindow::setPlaying( bool isPlaying ) { m_bIsPlaying = isPlaying; - for( auto module : m_apcCurrentModule ) + for( auto module : m_associatedModules ) { module->setPlaying( isPlaying ); } @@ -896,10 +907,15 @@ void VideoSubWindow::pause() void VideoSubWindow::seekAbsoluteEvent( unsigned int new_frame_num ) { - m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); if( m_pCurrStream ) + { if( m_pCurrStream->seekInput( new_frame_num ) ) refreshFrame(); + +#ifdef CALYP_MANAGED_RESOURCES + m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); +#endif + } } void VideoSubWindow::seekRelativeEvent( bool bIsFoward ) @@ -914,7 +930,7 @@ void VideoSubWindow::seekRelativeEvent( bool bIsFoward ) else { bRefresh = m_pCurrStream->seekInputRelative( bIsFoward ); -#ifdef USE_RESOURCES +#ifdef CALYP_MANAGED_RESOURCES m_pcResourceManager->wakeResourceWorker( m_uiResourceId ); #endif } @@ -1071,8 +1087,8 @@ void VideoSubWindow::scaleView( double scale, QPoint center ) void VideoSubWindow::scaleView( const QSize& size, QPoint center ) { QSize imgViewSize; - if( m_pcCurrFrame ) - imgViewSize = QSize( m_pcCurrFrame->getWidth(), m_pcCurrFrame->getHeight() ); + if( m_pcCurrFrameAsset ) + imgViewSize = QSize( m_pcCurrFrameAsset->getWidth(), m_pcCurrFrameAsset->getHeight() ); else imgViewSize = QSize( m_pCurrStream->getWidth(), m_pCurrStream->getHeight() ); QSize newSize = imgViewSize; @@ -1102,22 +1118,22 @@ void VideoSubWindow::scaleView( const QSize& size, QPoint center ) void VideoSubWindow::updatePixelValueStatusBar( const QPoint& pos ) { - if( m_pcCurrFrame ) + if( m_pcCurrFrameAsset ) { int iWidth, iHeight; int posX = pos.x(); int posY = pos.y(); QString strStatus; - iWidth = m_pcCurrFrame->getWidth(); - iHeight = m_pcCurrFrame->getHeight(); + iWidth = m_pcCurrFrameAsset->getWidth(); + iHeight = m_pcCurrFrameAsset->getHeight(); if( ( posX < iWidth ) && ( posX >= 0 ) && ( posY < iHeight ) && ( posY >= 0 ) ) { strStatus = QString( "(%1,%2) " ).arg( posX ).arg( posY ); - int colorSpace = m_pcCurrFrame->getColorSpace(); - CalypPixel pixelValue = m_pcCurrFrame->getPixel( pos.x(), pos.y() ); + int colorSpace = m_pcCurrFrameAsset->getColorSpace(); + CalypPixel pixelValue = m_pcCurrFrameAsset->getPixel( pos.x(), pos.y() ); switch( colorSpace ) { case CLP_COLOR_GRAY: diff --git a/app/VideoSubWindow.h b/app/VideoSubWindow.h index f6be66c..d39da5a 100644 --- a/app/VideoSubWindow.h +++ b/app/VideoSubWindow.h @@ -31,6 +31,7 @@ #include #include +#include "CalypAppModuleIf.h" #include "CommonDefs.h" #include "SubWindowAbstract.h" #include "ViewArea.h" @@ -84,13 +85,12 @@ private: CalypFileInfo m_sStreamInfo; std::size_t m_uiResourceId; CalypStream* m_pCurrStream; - std::shared_ptr m_pcCurrDisplayFrame; - - CalypFrame* m_pcCurrFrame; + std::shared_ptr m_pcCurrFrameAsset; + //CalypFrame* m_pcCurrFrame; QRect m_cSelectedArea; - CalypAppModuleIf* m_pcCurrentDisplayModule; - QList m_apcCurrentModule; + std::unique_ptr m_pcCurrentDisplayModule{ nullptr }; + std::vector m_associatedModules; VideoSubWindow* m_pcReferenceSubWindow; @@ -139,21 +139,20 @@ public: void seekAbsoluteEvent( unsigned int new_frame_num ); void seekRelativeEvent( bool bIsFoward ); - void setCurrFrame( CalypFrame* pcCurrFrame ); void setCurrFrame( std::shared_ptr pcCurrFrame ); CalypFileInfo getStreamInfo() { return m_sStreamInfo; } QString getStreamInformation() { return m_cStreamInformation; } const CalypStream* getInputStream() { return m_pCurrStream; } const CalypStream* getCurrStream() { return m_pCurrStream; } - CalypFrame* getCurrFrame() { return m_pcCurrFrame; } - std::shared_ptr getCurrFrameAsset() { return m_pCurrStream->getCurrFrameAsset(); }; + CalypFrame* getCurrFrame() { return m_pcCurrFrameAsset.get(); } + std::shared_ptr getCurrFrameAsset(); ViewArea* getViewArea() { return m_cViewArea; } void setRefSubWindow( VideoSubWindow* subWindow ) { m_pcReferenceSubWindow = NULL; if( subWindow ) - if( m_pcCurrFrame->haveSameFmt( subWindow->getCurrFrame() ) ) + if( m_pcCurrFrameAsset->haveSameFmt( subWindow->getCurrFrame() ) ) m_pcReferenceSubWindow = subWindow; } @@ -162,17 +161,17 @@ public: * Functions to enable a module in the * current SubWindow */ - void enableModule( CalypAppModuleIf* pcModule ); + void enableModule( std::unique_ptr&& pcModule ); void disableModule( CalypAppModuleIf* pcModule = NULL ); void associateModule( CalypAppModuleIf* pcModule ); - CalypAppModuleIf* getDisplayModule() { return m_pcCurrentDisplayModule; } - QList getModuleArray() + CalypAppModuleIf* getDisplayModule() { return m_pcCurrentDisplayModule.get(); } + QVector getModuleArray() { - QList apcModulesArray; + QVector apcModulesArray; if( m_pcCurrentDisplayModule ) - apcModulesArray.append( m_pcCurrentDisplayModule ); - apcModulesArray.append( m_apcCurrentModule ); + apcModulesArray.append( m_pcCurrentDisplayModule.get() ); + apcModulesArray.append( QVector::fromStdVector( m_associatedModules ) ); return apcModulesArray; } diff --git a/app/docks/FramePropertiesDock.cpp b/app/docks/FramePropertiesDock.cpp index 2ef18fb..7035418 100644 --- a/app/docks/FramePropertiesDock.cpp +++ b/app/docks/FramePropertiesDock.cpp @@ -230,6 +230,8 @@ FramePropertiesDock::FramePropertiesDock( QWidget* parent, bool* pbMainPlaySwitc statisticsLayout->addWidget( labelStdDevValue, gridRow++, 1 ); statisticsLayout->addWidget( medianLabel, gridRow, 0 ); statisticsLayout->addWidget( labelMedianValue, gridRow++, 1 ); + statisticsLayout->addWidget( percentileLabel, gridRow, 0 ); + statisticsLayout->addWidget( labelPercentileValue, gridRow++, 1 ); statisticsLayout->addWidget( entropyLabel, gridRow, 0 ); statisticsLayout->addWidget( labelEntropyValue, gridRow++, 1 ); @@ -278,11 +280,15 @@ QSize FramePropertiesDock::sizeHint() const void FramePropertiesDock::reset() { + m_pcFrame = nullptr; + m_pcSelectedFrame = nullptr; + m_bHasFrame = false; m_cSelectionArea = QRect(); m_iLastFrameType = -1; + labelRangeValue->clear(); labelNEBinsValue->clear(); labelMeanValue->clear(); labelPixelsValue->clear(); @@ -290,6 +296,7 @@ void FramePropertiesDock::reset() labelCountValue->clear(); labelMedianValue->clear(); labelPercentileValue->clear(); + labelEntropyValue->clear(); // Remove the histogram data from memory histogramWidget->reset(); diff --git a/app/docks/ModuleHandleDock.cpp b/app/docks/ModuleHandleDock.cpp index a74c57f..c9c118d 100644 --- a/app/docks/ModuleHandleDock.cpp +++ b/app/docks/ModuleHandleDock.cpp @@ -33,7 +33,7 @@ #include "ModulesHandle.h" ModuleHandleDock::ModuleHandleDock( QWidget* parent, CalypAppModuleIf* moduleIf ) - : QWidget( parent ), m_pcCurrModuleIf( moduleIf ) + : QWidget( parent ) { // ----------------- Dock definition ----------------- @@ -58,7 +58,12 @@ ModuleHandleDock::ModuleHandleDock( QWidget* parent, CalypAppModuleIf* moduleIf setEnabled( true ); } -ModuleHandleDock::~ModuleHandleDock() {} +ModuleHandleDock::~ModuleHandleDock() = default; + +void ModuleHandleDock::enableModule( std::unique_ptr&& module ) +{ + m_pcCurrModuleIf = std::move( module ); +} void ModuleHandleDock::setModuleReturnValue( double value ) { @@ -69,11 +74,9 @@ void ModuleHandleDock::setModuleReturnValue( double value ) void ModuleHandleDock::visibilityChangedSlot( bool visiblity ) { - if( !visiblity && m_pcCurrModuleIf ) + if( !visiblity ) { - CalypAppModuleIf* pcCurrentModule = m_pcCurrModuleIf; - m_pcCurrModuleIf = NULL; - ModulesHandle::destroyModuleIf( pcCurrentModule ); + m_pcCurrModuleIf = nullptr; } } diff --git a/app/docks/ModuleHandleDock.h b/app/docks/ModuleHandleDock.h index b388862..167470e 100644 --- a/app/docks/ModuleHandleDock.h +++ b/app/docks/ModuleHandleDock.h @@ -42,12 +42,13 @@ public: ModuleHandleDock( QWidget* parent, CalypAppModuleIf* moduleIf ); ~ModuleHandleDock(); + void enableModule( std::unique_ptr&& module ); void setModuleReturnValue( double value ); QSize sizeHint() const; private: - CalypAppModuleIf* m_pcCurrModuleIf; + std::unique_ptr m_pcCurrModuleIf; bool m_bIsVisible; QLabel* labelModulueValueLabel; diff --git a/app/widgets/HistogramWidget.cpp b/app/widgets/HistogramWidget.cpp index eb21767..2674091 100644 --- a/app/widgets/HistogramWidget.cpp +++ b/app/widgets/HistogramWidget.cpp @@ -49,6 +49,11 @@ public: m_parent = parent; } + void reset() + { + m_pcFrame = nullptr; + } + void setup( std::shared_ptr frame ) { m_pcFrame = frame; @@ -230,8 +235,10 @@ void HistogramWidget::reset() d->guideVisible = false; d->clearFlag = HistogramWidgetPrivate::HistogramNone; // Remove histogram data from memory. - m_fullImage = NULL; - m_selectionImage = NULL; + m_fullImage = nullptr; + m_selectionImage = nullptr; + m_imageWorker->setup( nullptr ); + m_selectionWorker->setup( nullptr ); update(); } diff --git a/config.h.in b/config.h.in index 31c2469..89b328c 100644 --- a/config.h.in +++ b/config.h.in @@ -56,6 +56,6 @@ #cmakedefine USE_FERVOR /* Use a resource manager to manage streams in different threads */ -#cmakedefine USE_RESOURCES +#cmakedefine CALYP_MANAGED_RESOURCES #endif // __CONFIG_CALYP_H__ diff --git a/lib/CalypStream.cpp b/lib/CalypStream.cpp index 32c9997..04e4590 100644 --- a/lib/CalypStream.cpp +++ b/lib/CalypStream.cpp @@ -26,6 +26,7 @@ #include "CalypStream.h" #include +#include #include #include "CalypFrame.h" @@ -102,7 +103,8 @@ std::vector CalypStream::stdResolutionSizes() class CalypStreamBufferPrivate { private: - std::vector m_apcFrameBuffer; + std::vector m_framePool; + std::deque m_frameBuffer; std::int64_t m_iSize; std::int64_t m_iReadIndex; std::int64_t m_iWriteIndex; @@ -110,12 +112,12 @@ private: public: CalypStreamBufferPrivate( std::size_t size, unsigned int width, unsigned int height, int pelFormat, unsigned int bitsPixel, bool hasNegative ) { - m_apcFrameBuffer.reserve( size ); + m_framePool.reserve( size ); for( std::size_t i = 0; i < size; i++ ) { - m_apcFrameBuffer.push_back( CalypFrame{ width, height, pelFormat, bitsPixel, hasNegative } ); + m_framePool.push_back( CalypFrame{ width, height, pelFormat, bitsPixel, hasNegative } ); } - m_iSize = std::ssize( m_apcFrameBuffer ); + m_iSize = std::ssize( m_framePool ); m_iReadIndex = -1; m_iWriteIndex = 0; } @@ -124,16 +126,16 @@ public: void increase( std::size_t newSize ) { - m_apcFrameBuffer.reserve( newSize ); + m_framePool.reserve( newSize ); for( std::size_t i = m_iSize; i < newSize; i++ ) { - m_apcFrameBuffer.push_back( CalypFrame{ m_apcFrameBuffer[0].getWidth(), - m_apcFrameBuffer[0].getHeight(), - m_apcFrameBuffer[0].getPelFormat(), - m_apcFrameBuffer[0].getBitsPel(), - m_apcFrameBuffer[0].getHasNegativeValues() } ); + m_framePool.push_back( CalypFrame{ m_framePool[0].getWidth(), + m_framePool[0].getHeight(), + m_framePool[0].getPelFormat(), + m_framePool[0].getBitsPel(), + m_framePool[0].getHasNegativeValues() } ); } - m_iSize = std::ssize( m_apcFrameBuffer ); + m_iSize = std::ssize( m_framePool ); } void setIndex( std::int64_t i ) @@ -151,52 +153,54 @@ public: assert( m_iWriteIndex >= 0 ); m_iReadIndex = 0; } - CalypFrame& frame( int i ) { return m_apcFrameBuffer.at( i ); } + CalypFrame& frame( int i ) { return m_framePool.at( i ); } CalypFrame& currentRead() { - assert( m_iReadIndex >= 0 && m_iReadIndex < m_iSize ); - return m_apcFrameBuffer.at( m_iReadIndex ); + assert( m_iReadIndex < m_iWriteIndex && ( m_iReadIndex % m_iSize ) < m_iSize ); + return m_framePool.at( m_iReadIndex % m_iSize ); } - const CalypFrame& ref() { return m_apcFrameBuffer.at( m_iWriteIndex ); } + const CalypFrame& ref() { return m_framePool.at( m_iWriteIndex % m_iSize ); } CalypFrame& readOneFrame() { - assert( m_iReadIndex >= 0 && m_iReadIndex < m_iSize ); - CalypFrame& frameToRead = m_apcFrameBuffer.at( m_iReadIndex ); + assert( m_iReadIndex < m_iWriteIndex && ( m_iReadIndex % m_iSize ) < m_iSize ); + CalypFrame& frameToRead = m_framePool.at( m_iReadIndex % m_iSize ); m_iReadIndex = nextIndex( m_iReadIndex ); return frameToRead; } CalypFrame& writeOneFrame() { - assert( m_iReadIndex != m_iWriteIndex ); - CalypFrame& frameToWrite = m_apcFrameBuffer.at( m_iWriteIndex ); + assert( m_iWriteIndex > m_iReadIndex && ( m_iReadIndex % m_iSize ) != ( m_iWriteIndex % m_iSize ) ); + CalypFrame& frameToWrite = m_framePool.at( m_iWriteIndex % m_iSize ); m_iWriteIndex = nextIndex( m_iWriteIndex ); return frameToWrite; } bool hasWritingSlot() { - if( m_iWriteIndex != m_iReadIndex ) + if( ( m_iReadIndex % m_iSize ) != ( m_iWriteIndex % m_iSize ) ) return true; return false; } std::shared_ptr retrieveFrame() { - auto ptr = std::make_shared( std::move( m_apcFrameBuffer[m_iReadIndex] ) ); - m_apcFrameBuffer[m_iReadIndex] = CalypFrame{ ptr->getWidth(), - ptr->getHeight(), - ptr->getPelFormat(), - ptr->getBitsPel(), - ptr->getHasNegativeValues() }; + assert( m_iReadIndex < m_iWriteIndex && ( m_iReadIndex % m_iSize ) < m_iSize ); + auto ptr = std::make_shared( std::move( m_framePool[m_iReadIndex % m_iSize] ) ); + m_framePool[m_iReadIndex % m_iSize] = CalypFrame{ ptr->getWidth(), + ptr->getHeight(), + ptr->getPelFormat(), + ptr->getBitsPel(), + ptr->getHasNegativeValues() }; m_iReadIndex = nextIndex( m_iReadIndex ); return ptr; } private: - inline int nextIndex( std::int64_t curr ) { return curr + 1 >= m_iSize ? 0 : curr + 1; } + //inline int nextIndex( std::int64_t curr ) { return curr + 1 >= m_iSize ? 0 : curr + 1; } + inline int nextIndex( std::int64_t curr ) { return curr + 1; } }; class CalypStream::CalypStreamPrivate @@ -210,8 +214,9 @@ public: CalypStreamHandlerIf* handler; CreateStreamHandlerFn pfctCreateHandler; - std::unique_ptr frameBuffer; - std::shared_ptr currentFrame; + std::vector framePool; + std::deque> frameFifo; + std::size_t bufferIdx{ 0 }; ClpString cFilename; long long int iCurrFrameNum; @@ -221,7 +226,6 @@ public: { handler = nullptr; pfctCreateHandler = nullptr; - frameBuffer = nullptr; isInput = true; isInit = false; bLoadAll = false; @@ -249,7 +253,21 @@ public: isInit = false; } - bool readFrame( CalypFrame& frame ) + 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( CalypFrame{ framePool[0].getWidth(), + framePool[0].getHeight(), + framePool[0].getPelFormat(), + framePool[0].getBitsPel(), + framePool[0].getHasNegativeValues() } ); + } + } + + bool readNextFrame( bool fillRgbBuffer = false ) { if( !isInit || !isInput || handler->m_uiCurrFrameFileIdx >= handler->m_uiTotalNumberFrames ) return false; @@ -257,11 +275,23 @@ public: if( bLoadAll ) return true; + assert( bufferIdx > 0 ); + bufferIdx--; + CalypFrame& frame = framePool[bufferIdx]; + if( !handler->read( frame ) ) { throw CalypFailure( "CalypStream", "Cannot read frame from stream" ); return false; } + if( fillRgbBuffer ) + { + frame.fillRGBBuffer(); + } + frameFifo.push_back( + std::shared_ptr{ + new CalypFrame{ std::move( frame ) }, + [this]( CalypFrame* p ) { framePool[bufferIdx] = std::move( *p ); bufferIdx++; } } ); return true; } }; @@ -415,8 +445,11 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei std::size_t bufferSize = d->isInput ? 4 : 1; try { - d->frameBuffer = std::make_unique( bufferSize, d->handler->m_uiWidth, d->handler->m_uiHeight, - d->handler->m_iPixelFormat, d->handler->m_uiBitsPerPixel, hasNegative ); + 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 } ); + } } catch( CalypFailure& e ) { @@ -425,7 +458,10 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - d->handler->m_uiNBytesPerFrame = d->frameBuffer->ref().getBytesPerFrame(); + d->frameFifo.clear(); + d->bufferIdx = d->framePool.size(); + + d->handler->m_uiNBytesPerFrame = d->framePool[0].getBytesPerFrame(); // Some handlers need to know how long is a frame to get frame number d->handler->calculateFrameNumber(); @@ -437,7 +473,7 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - if( !d->handler->configureBuffer( d->frameBuffer->ref() ) ) + if( !d->handler->configureBuffer( d->framePool[0] ) ) { d->close(); throw CalypFailure( "CalypStream", "Cannot allocated buffers" ); @@ -461,9 +497,9 @@ bool CalypStream::reload() throw CalypFailure( "CalypStream", "Cannot open stream " + d->cFilename + " with the " + ClpString( d->handler->m_pchHandlerName ) + " handler" ); } - d->handler->m_uiNBytesPerFrame = d->frameBuffer->ref().getBytesPerFrame(); + d->handler->m_uiNBytesPerFrame = d->framePool[0].getBytesPerFrame(); d->handler->calculateFrameNumber(); - d->handler->configureBuffer( d->frameBuffer->ref() ); + 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 ) @@ -554,7 +590,7 @@ void CalypStream::loadAll() try { - d->frameBuffer->increase( d->handler->m_uiTotalNumberFrames ); + d->increasePool( d->handler->m_uiTotalNumberFrames ); } catch( CalypFailure& e ) { @@ -565,56 +601,49 @@ void CalypStream::loadAll() seekInput( 0 ); for( unsigned int i = 2; i < d->handler->m_uiTotalNumberFrames; i++ ) { - d->readFrame( d->frameBuffer->frame( i ) ); + d->readNextFrame( false ); } d->bLoadAll = true; d->iCurrFrameNum = 0; } -// auto CalypStream::getNextFrame() -> CalypFrame& +// auto CalypStream::retrieveNextFrame() -> bool // { -// CalypFrame& frameToTead = d->frameBuffer->readOneFrame(); -// d->readFrame( d->frameBuffer->writeOneFrame() ); -// return frameToTead; +// 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; // } -auto CalypStream::retrieveNextFrame() -> bool +std::unique_ptr CalypStream::getCurrFrame( std::unique_ptr buffer ) { - 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(); - } + if( buffer == nullptr ) + buffer = std::make_unique( *d->frameFifo.front() ); else - { - bEndOfSeq = true; - } - return bEndOfSeq; + buffer->copyFrom( *d->frameFifo.front() ); + return buffer; } auto CalypStream::getCurrFrameAsset() -> std::shared_ptr { - if( d->currentFrame == nullptr ) - { - d->currentFrame = d->frameBuffer->retrieveFrame(); - } - return d->currentFrame; + if( d->bLoadAll ) + return d->frameFifo[d->iCurrFrameNum]; + return d->frameFifo.front(); } -CalypFrame* CalypStream::getCurrFrame( CalypFrame* pyuv_image ) +auto CalypStream::getCurrFrame() -> CalypFrame* { - if( pyuv_image == NULL ) - pyuv_image = new CalypFrame( d->frameBuffer->currentRead() ); - else - pyuv_image->copyFrom( d->frameBuffer->currentRead() ); - return pyuv_image; -} - -CalypFrame* CalypStream::getCurrFrame() -{ - return &d->frameBuffer->currentRead(); + if( d->bLoadAll ) + return d->frameFifo[d->iCurrFrameNum].get(); + return d->frameFifo.front().get(); } bool CalypStream::setNextFrame() @@ -623,8 +652,11 @@ bool CalypStream::setNextFrame() if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) { - d->frameBuffer->readOneFrame(); d->iCurrFrameNum++; + if( !d->bLoadAll ) + { + d->frameFifo.pop_front(); + } } else { @@ -635,32 +667,22 @@ bool CalypStream::setNextFrame() void CalypStream::readNextFrame() { - d->readFrame( d->frameBuffer->writeOneFrame() ); + d->readNextFrame(); } void CalypStream::readNextFrameFillRGBBuffer() { - const std::lock_guard lock( d->mutex ); - - CalypFrame& frameToWrite = d->frameBuffer->writeOneFrame(); - d->readFrame( frameToWrite ); - frameToWrite.fillRGBBuffer(); - return; + d->readNextFrame( true ); } auto CalypStream::hasWritingSlot() -> bool { - return d->frameBuffer->hasWritingSlot(); + return !d->bLoadAll && d->bufferIdx > 0; } /** * @brief Write operations */ -void CalypStream::writeFrame() -{ - writeFrame( *getCurrFrame() ); -} - void CalypStream::writeFrame( const CalypFrame& pcFrame ) { if( !d->handler->write( pcFrame ) ) @@ -699,7 +721,7 @@ bool CalypStream::seekInputRelative( bool bIsFoward ) if( bIsFoward ) { bRet = !setNextFrame(); - d->readFrame( d->frameBuffer->writeOneFrame() ); + d->readNextFrame(); } else { @@ -716,24 +738,20 @@ bool CalypStream::seekInput( unsigned long new_frame_num ) 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 ) - { - d->frameBuffer->setIndex( d->iCurrFrameNum ); return true; - } if( !d->handler->seek( d->iCurrFrameNum ) ) { throw CalypFailure( "CalypStream", "Cannot seek file into desired position" ); } - d->currentFrame = nullptr; - d->frameBuffer->reset(); - d->readFrame( d->frameBuffer->writeOneFrame() ); + d->readNextFrame(); if( d->handler->m_uiTotalNumberFrames > 1 ) - d->readFrame( d->frameBuffer->writeOneFrame() ); - d->frameBuffer->startRead(); + d->readNextFrame(); return true; } diff --git a/lib/CalypStream.h b/lib/CalypStream.h index a7f7b1a..60e24a4 100644 --- a/lib/CalypStream.h +++ b/lib/CalypStream.h @@ -101,19 +101,18 @@ public: void loadAll(); // continuous read using smart ptrs - auto retrieveNextFrame() -> bool; - auto getCurrFrameAsset() -> std::shared_ptr; + // auto retrieveNextFrame() -> bool; // continuous read control - CalypFrame* getCurrFrame( CalypFrame* ); - CalypFrame* getCurrFrame(); + std::unique_ptr getCurrFrame( std::unique_ptr buffer ); + auto getCurrFrameAsset() -> std::shared_ptr; + auto getCurrFrame() -> CalypFrame*; bool setNextFrame(); void readNextFrame(); void readNextFrameFillRGBBuffer(); auto hasWritingSlot() -> bool; - void writeFrame(); void writeFrame( const CalypFrame& pcFrame ); bool saveFrame( const ClpString& filename );