diff --git a/.gitignore b/.gitignore index d8fcc1b..f7f835b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Created by https://www.gitignore.io/api/c++,clion,linux # Edit at https://www.gitignore.io/?templates=c++,clion,linux deps/** +templates/** + ### C++ ### # Prerequisites *.d diff --git a/CMakeLists.txt b/CMakeLists.txt index 60bddde..e87af9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ IF(BUILD_TESTS) FETCHCONTENT_DECLARE( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v2.13.1 + GIT_TAG v2.13.7 ) SET_PACKAGE_PROPERTIES( diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4833524..120bde8 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -3,8 +3,13 @@ # INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/external ${CMAKE_CURRENT_SOURCE_DIR}/dialog - ${CMAKE_CURRENT_SOURCE_DIR}/docks ${CMAKE_CURRENT_SOURCE_DIR}/widgets + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/external + ${CMAKE_CURRENT_SOURCE_DIR}/dialog + ${CMAKE_CURRENT_SOURCE_DIR}/docks + ${CMAKE_CURRENT_SOURCE_DIR}/widgets + ${CMAKE_CURRENT_SOURCE_DIR}/models ) OPTION(USE_QTDBUS "Build with QtDBus" ON) @@ -44,28 +49,30 @@ ADD_DEFINITIONS( # -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_USE_QSTRINGBUILDER ) -SET(Calyp_App_SRCS +SET(Calyp_App_Module_SRCS # Module Video + models/VideostreamResource.cpp ResourceHandle.cpp +) + +SET(Calyp_App_GUI_SRCS + ${Calyp_App_Module_SRCS} + # Models + ModulesHandle.cpp + SubWindowHandle.cpp + VideoHandle.cpp + CalypAppModuleIf.cpp + QualityHandle.cpp # Main main.cpp MainWindow.cpp # Module SubWindow - SubWindowHandle.cpp MdiSubWindow.cpp SubWindowAbstract.cpp - # Module Video - ResourceHandle.cpp - VideoHandle.cpp VideoSubWindow.cpp VideoStreamSubWindow.cpp ModuleSubWindow.cpp ViewArea.cpp GridManager.cpp - # Module Quality - QualityHandle.cpp PlotSubWindow.cpp - # Module Plugins - ModulesHandle.cpp - CalypAppModuleIf.cpp # Dialogs dialog/AboutDialog.cpp dialog/ConfigureFormatDialog.cpp @@ -83,7 +90,7 @@ SET(Calyp_App_SRCS ) IF(USE_QTDBUS) - LIST(APPEND Calyp_App_SRCS DBusAppAdaptor.cpp) + LIST(APPEND Calyp_App_GUI_SRCS DBusAppAdaptor.cpp) ENDIF() SET(Calyp_App_UI "") @@ -158,7 +165,7 @@ IF(WIN32) COMMENT "Add icon on windows platform" ) ENDIF() - ADD_EXECUTABLE(${PROJECT_NAME} ${Calyp_App_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC} ${WINDOWS_RES_FILE}) + ADD_EXECUTABLE(${PROJECT_NAME} ${Calyp_App_GUI_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC} ${WINDOWS_RES_FILE}) ELSEIF(CMAKE_HOST_APPLE) SET(CMAKE_MACOSX_BUNDLE ON) SET(MACOSX_BUNDLE_EXECUTABLE_NAME ${PROJECT_NAME}) @@ -166,9 +173,9 @@ ELSEIF(CMAKE_HOST_APPLE) SET(MACOSX_BUNDLE_BUNDLE_NAME Calyp) SET(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/resources/calyp.icns) SET_SOURCE_FILES_PROPERTIES(${APP_ICON_MACOSX} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") - ADD_EXECUTABLE(${PROJECT_NAME} MACOSX_BUNDLE ${Calyp_App_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC} ${APP_ICON_MACOSX}) + ADD_EXECUTABLE(${PROJECT_NAME} MACOSX_BUNDLE ${Calyp_App_GUI_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC} ${APP_ICON_MACOSX}) ELSE() - ADD_EXECUTABLE(${PROJECT_NAME} ${Calyp_App_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC}) + ADD_EXECUTABLE(${PROJECT_NAME} ${Calyp_App_GUI_SRCS} ${HEADERS_MOC_FILES} ${Calyp_App_UI_Wrap} ${Calyp_App_RCC}) ENDIF() TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${PROJECT_LIBRARY} CalypModules ${APP_LINKER_LIBS} ${QT_LINKER_LIBS} QCustomPlotLib) @@ -178,3 +185,24 @@ INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) INSTALL(FILES resources/calyp.desktop DESTINATION share/applications) INSTALL(FILES resources/calyp.png DESTINATION share/pixmaps) INSTALL(FILES resources/calyp.xml DESTINATION share/mime/packages) + +IF(BUILD_TESTS) + FETCHCONTENT_MAKEAVAILABLE(Catch2) + + SET(Calyp_App_Catch2_Tests_SRCS ${Calyp_App_Module_SRCS} catch2/CalypAppTests.cpp catch2/CalypResourcesTests.cpp) + + ADD_DEFINITIONS(-DCALYP_TEST_DATA_DIR=\"${CALYP_TEST_DATA_DIR}\") + + ADD_EXECUTABLE(CalypAppCatch2Tests ${Calyp_App_Catch2_Tests_SRCS}) + TARGET_LINK_LIBRARIES( + CalypAppCatch2Tests + ${PROJECT_LIBRARY} + CalypModules + ${APP_LINKER_LIBS} + ${QT_LINKER_LIBS} + QCustomPlotLib + Catch2::Catch2 + ) + CATCH_DISCOVER_TESTS(CalypAppCatch2Tests) + +ENDIF() diff --git a/app/MainWindow.cpp b/app/MainWindow.cpp index 9f8ebd9..f5eb5f3 100644 --- a/app/MainWindow.cpp +++ b/app/MainWindow.cpp @@ -36,6 +36,7 @@ #include #include "AboutDialog.h" +#include "ConfigureFormatDialog.h" #include "ModulesHandle.h" #include "QualityHandle.h" #include "SubWindowAbstract.h" @@ -48,8 +49,7 @@ #include "fvupdater.h" #endif -MainWindow::MainWindow() - : m_pcCurrentSubWindow( NULL ), m_pcCurrentVideoSubWindow( NULL ), m_pcAboutDialog( NULL ) +MainWindow::MainWindow() : m_pcCurrentSubWindow( NULL ), m_pcCurrentVideoSubWindow( NULL ), m_pcAboutDialog( NULL ) { setWindowModality( Qt::ApplicationModal ); setWindowModality( Qt::NonModal ); @@ -59,7 +59,7 @@ MainWindow::MainWindow() m_pDBusAdaptor = new DBusAppAdaptor( this ); #endif - m_appResourceHandle = std::make_unique(); + m_appResourceHandle = std::make_unique( this ); m_pcWindowHandle = new SubWindowHandle( this ); @@ -191,49 +191,74 @@ void MainWindow::loadFile( CalypFileInfo pStreamInfo ) loadFile( std::move( filename ), std::move( pStreamInfo ) ); } -void MainWindow::loadFile( QString fileName, std::optional streamInfo ) +void MainWindow::loadFile( QString fileName, std::optional streamInfoOpt ) { if( !QFileInfo( fileName ).exists() ) { printMessage( "File " + fileName + " do not exist!", CLP_LOG_ERROR ); return; } - auto* videoSubWindow = MainWindow::findVideoStreamSubWindow( m_pcWindowHandle, fileName ); - if( videoSubWindow ) + + if( auto* videoSubWindow = MainWindow::findVideoStreamSubWindow( m_pcWindowHandle, fileName ) ) { m_pcWindowHandle->setActiveSubWindow( videoSubWindow ); return; } - videoSubWindow = new VideoStreamSubWindow(); // createSubWindow(); - videoSubWindow->setResourceManaget( m_appResourceHandle.get() ); - if( !streamInfo.has_value() ) + if( !streamInfoOpt.has_value() ) { auto idx = findCalypStreamInfo( m_aRecentFileStreamInfo, fileName ); if( idx >= 0 ) - streamInfo = m_aRecentFileStreamInfo.at( idx ); + streamInfoOpt = m_aRecentFileStreamInfo.at( idx ); } + auto streamInfo = streamInfoOpt.has_value() ? *streamInfoOpt : CalypFileInfo{ .m_cFilename = fileName }; + + auto videoResource = std::make_unique(); + + bool opened = false; try { - bool opened = false; - - if( streamInfo.has_value() ) - { - try - { - opened = videoSubWindow->loadFile( std::move( *streamInfo ) ); - } - catch( CalypFailure& e ) - { - } - } + opened = videoResource->loadFile( streamInfo, false ); if( !opened ) - opened = videoSubWindow->loadFile( fileName ); + { + auto guessed = video_resource_guess_format( streamInfo.m_cFilename, streamInfo.m_uiWidth, streamInfo.m_uiHeight, + streamInfo.m_iPelFormat, streamInfo.m_uiBitsPelPixel, + streamInfo.m_iEndianness, streamInfo.m_uiFrameRate ); + + if( !guessed ) + { + ConfigureFormatDialog formatDialog( this ); + if( streamInfo.m_uiWidth == 0 ) + { + streamInfo.m_uiWidth = m_cLastWidth; + } + if( streamInfo.m_uiHeight == 0 ) + { + streamInfo.m_uiHeight = m_cLastHeight; + } + if( streamInfo.m_uiBitsPelPixel == 0 ) + { + streamInfo.m_uiBitsPelPixel = m_cLastBitPerPixel; + } + if( formatDialog.runConfigureFormatDialog( + QFileInfo( fileName ).fileName(), streamInfo.m_uiWidth, streamInfo.m_uiHeight, streamInfo.m_iPelFormat, + streamInfo.m_uiBitsPelPixel, streamInfo.m_iEndianness, streamInfo.m_uiFrameRate ) != QDialog::Accepted ) + { + return; + } + } + opened = videoResource->loadFile( streamInfo, false ); + } if( opened ) { + auto resource_id = m_appResourceHandle->appendResource( std::move( videoResource ) ); + + auto* videoSubWindow = new VideoStreamSubWindow( m_appResourceHandle.get() ); // createSubWindow(); + videoSubWindow->setResource( resource_id ); + printMessage( "Loading file...", CLP_LOG_INFO ); m_pcWindowHandle->addSubWindow( videoSubWindow ); videoSubWindow->show(); @@ -242,19 +267,14 @@ void MainWindow::loadFile( QString fileName, std::optional stream updateZoomFactorSBox(); - addStreamInfoToRecentList( videoSubWindow->getStreamInfo() ); + addStreamInfoToRecentList( std::move( streamInfo ) ); printMessage( "File loaded", CLP_LOG_INFO ); m_cLastOpenPath = QFileInfo( fileName ).path(); } - else - { - videoSubWindow->close(); - } } catch( CalypFailure& e ) { - videoSubWindow->close(); QString warningMsg = "Cannot open file " + QFileInfo( fileName ).fileName() + " with the following error: \n" + e.what(); QMessageBox::warning( this, QApplication::applicationName(), warningMsg ); @@ -397,27 +417,28 @@ void MainWindow::saveStream() void MainWindow::format() { - if( auto* pcVideoSubWindow = qobject_cast( m_pcCurrentVideoSubWindow ) ) - { - try - { - if( pcVideoSubWindow->loadFile( pcVideoSubWindow->getCurrentFileName(), true ) ) - { - addStreamInfoToRecentList( pcVideoSubWindow->getStreamInfo() ); - } - } - catch( CalypFailure& e ) - { - QString warningMsg = "Cannot change format of " + QFileInfo( pcVideoSubWindow->getCurrentFileName() ).fileName() + - " with the following error: \n" + e.what(); - QMessageBox::warning( this, QApplication::applicationName(), warningMsg ); - printMessage( warningMsg, CLP_LOG_ERROR ); - qDebug() << warningMsg; - m_pcCurrentSubWindow->close(); - } - m_pcCurrentSubWindow = NULL; - updateMainWindow(); - } + // if( auto* pcVideoSubWindow = qobject_cast( m_pcCurrentVideoSubWindow ) ) + // { + // try + // { + // if( pcVideoSubWindow->loadFile( pcVideoSubWindow->getCurrentFileName(), true ) ) + // { + // addStreamInfoToRecentList( pcVideoSubWindow->getStreamInfo() ); + // } + // } + // catch( CalypFailure& e ) + // { + // QString warningMsg = "Cannot change format of " + QFileInfo( pcVideoSubWindow->getCurrentFileName() + // ).fileName() + + // " with the following error: \n" + e.what(); + // QMessageBox::warning( this, QApplication::applicationName(), warningMsg ); + // printMessage( warningMsg, CLP_LOG_ERROR ); + // qDebug() << warningMsg; + // m_pcCurrentSubWindow->close(); + // } + // m_pcCurrentSubWindow = NULL; + // updateMainWindow(); + // } } void MainWindow::reload() @@ -482,11 +503,10 @@ void MainWindow::zoomToFit() void MainWindow::zoomToFitAll() { - VideoSubWindow* videoSubWindow; QList subWindowList = m_pcWindowHandle->findSubWindow( SubWindowAbstract::VIDEO_SUBWINDOW ); for( int i = 0; i < subWindowList.size(); i++ ) { - videoSubWindow = qobject_cast( subWindowList.at( i ) ); + auto* videoSubWindow = qobject_cast( subWindowList.at( i ) ); videoSubWindow->zoomToFit(); } if( m_pcCurrentSubWindow ) @@ -514,10 +534,9 @@ void MainWindow::zoomFromSBox( double zoom ) void MainWindow::updateZoomFactorSBox() { - double factor; if( m_pcCurrentSubWindow ) { - factor = m_pcCurrentSubWindow->getScaleFactor(); + double factor = m_pcCurrentSubWindow->getScaleFactor(); m_pcZoomFactorSBox->setValue( factor * 100 ); } } @@ -902,6 +921,10 @@ void MainWindow::addStreamInfoToRecentList( CalypFileInfo streamInfo ) while( m_aRecentFileStreamInfo.size() > MAX_RECENT_FILES ) m_aRecentFileStreamInfo.remove( m_aRecentFileStreamInfo.size() - 1 ); updateRecentFileActions(); + QSettings appSettings; + QVariant var; + var.setValue( m_aRecentFileStreamInfo ); + appSettings.setValue( "MainWindow/RecentFileList", var ); } void MainWindow::updateRecentFileActions() @@ -961,6 +984,9 @@ void MainWindow::readSettings() resize( size ); m_cLastOpenPath = appSettings.value( "MainWindow/LastOpenPath", QDir::homePath() ).toString(); + m_cLastWidth = appSettings.value( "MainWindow/LastWidth" ).value(); + m_cLastHeight = appSettings.value( "MainWindow/LastHeight" ).value(); + m_cLastBitPerPixel = appSettings.value( "MainWindow/LastBitsPerPixel" ).value(); QVariant value = appSettings.value( "MainWindow/RecentFileList" ); m_aRecentFileStreamInfo = value.value(); @@ -980,6 +1006,9 @@ void MainWindow::writeSettings() appSettings.setValue( "MainWindow/Position", pos() ); appSettings.setValue( "MainWindow/Size", size() ); appSettings.setValue( "MainWindow/LastOpenPath", m_cLastOpenPath ); + appSettings.setValue( "MainWindow/LastWidth", m_cLastWidth ); + appSettings.setValue( "MainWindow/LastHeight", m_cLastHeight ); + appSettings.setValue( "MainWindow/LastBitsPerPixel", m_cLastBitPerPixel ); QVariant var; var.setValue( m_aRecentFileStreamInfo ); diff --git a/app/MainWindow.h b/app/MainWindow.h index 13926e2..555a8de 100644 --- a/app/MainWindow.h +++ b/app/MainWindow.h @@ -49,6 +49,7 @@ #include "DBusAppAdaptor.h" #endif #include "ResourceHandle.h" +#include "VideostreamResource.h" class QCloseEvent; class QDragEnterEvent; @@ -132,6 +133,9 @@ private: VideoSubWindow* m_pcCurrentVideoSubWindow; QString m_cLastOpenPath; + unsigned int m_cLastWidth; + unsigned int m_cLastHeight; + unsigned int m_cLastBitPerPixel; QStringList showFileDialog( bool bRead ); static VideoStreamSubWindow* findVideoStreamSubWindow( const SubWindowHandle* windowManager, diff --git a/app/ResourceHandle.cpp b/app/ResourceHandle.cpp index d802738..6da17ef 100644 --- a/app/ResourceHandle.cpp +++ b/app/ResourceHandle.cpp @@ -35,16 +35,21 @@ #include #include -ResourceWorker::ResourceWorker( std::shared_ptr stream ) - : m_pcStream{ stream } +ResourceWorker::~ResourceWorker() { + stop(); } void ResourceWorker::stop() { + while( m_bStarting ) {} m_bStop = true; - wake(); - wait(); + if( m_bStarted ) + { + wake(); + wait(); + } + m_bStarted = false; } void ResourceWorker::wake() @@ -54,39 +59,71 @@ void ResourceWorker::wake() m_Mutex.unlock(); } +void ResourceWorker::start() +{ + m_bStarting = true; + QThread::start(); +} + void ResourceWorker::run() { m_bStop = false; + m_bStarted = true; + m_bStarting = false; // Loop forever - while( !m_bStop ) + for( ;; ) { - // auto start = std::chrono::steady_clock::now(); - m_pcStream->readNextFrameFillRGBBuffer(); - // 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; - - while( !m_bStop && !m_pcStream->hasWritingSlot() ) + while( !m_bStop && !m_resource->isReady() ) { // Wait here m_Mutex.lock(); m_ResourceIdle.wait( &m_Mutex ); m_Mutex.unlock(); } + + // auto start = std::chrono::steady_clock::now(); + if( m_bStop || !m_resource->iteration() ) + { + break; + } + // 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; } + m_bStarted = false; + m_bStop = false; } -ResourceHandle::ResourceHandle() +class OldStreamResource : public CalypResource { -} +public: + OldStreamResource() = default; + CalypStream m_stream; + auto getResourceName() -> std::string override { return m_stream.getFileName(); }; + auto getResource() -> CalypStream* override { return &m_stream; }; + + auto iteration() -> bool override + { + if( m_stream.getFrameNum() < 2 ) + { + return false; + } + m_stream.readNextFrameFillRGBBuffer(); + return true; + } + auto isReady() -> bool override { return m_stream.hasWritingSlot(); } +}; + +ResourceHandle::ResourceHandle( QObject* parent ) : QObject{ parent } {} +ResourceHandle::~ResourceHandle() = default; auto ResourceHandle::addResource() -> std::size_t { auto resource_id = unique_id; unique_id++; - auto newStreamResource = std::make_shared(); + auto newStreamResource = std::make_shared(); auto newStreamResourceWorker = std::make_unique( newStreamResource ); m_apcStreamResourcesList[resource_id] = newStreamResource; m_apcStreamResourcesWorkersList[resource_id] = std::move( newStreamResourceWorker ); @@ -99,8 +136,11 @@ auto ResourceHandle::getResource( CalypStream* ptr ) -> std::size_t { for( std::size_t i = 0; i < m_apcStreamResourcesList.size(); i++ ) { - if( m_apcStreamResourcesList[i].get() == ptr ) - return i; + if( auto* resource = dynamic_cast( m_apcStreamResourcesList[i].get() ) ) + { + if( &resource->m_stream == ptr ) + return i; + } } } return addResource(); @@ -110,14 +150,24 @@ auto ResourceHandle::getResourceAsset( std::size_t id ) -> CalypStream* { if( m_apcStreamResourcesWorkersList.count( id ) ) { - return m_apcStreamResourcesList[id].get(); + return m_apcStreamResourcesList[id]->getResource(); } return nullptr; } +auto ResourceHandle::appendResource( std::unique_ptr&& resource ) -> std::size_t +{ + auto resource_id = unique_id; + unique_id++; + m_apcStreamResourcesList[resource_id] = std::move( resource ); + m_apcStreamResourcesWorkersList[resource_id] = + std::make_unique( m_apcStreamResourcesList[resource_id] ); + return resource_id; +} + void ResourceHandle::removeResource( std::size_t id ) { - if( !m_apcStreamResourcesWorkersList.count( id ) ) + if( !m_apcStreamResourcesList.count( id ) ) { assert( false ); return; @@ -148,13 +198,9 @@ void ResourceHandle::startResourceWorker( std::size_t id ) assert( false ); return; } - if( m_apcStreamResourcesList[id]->getFrameNum() < 2 ) - { - return; // No work to be done! - } m_apcStreamResourcesWorkersList[id]->setObjectName( "RW-" + - QFileInfo( QString::fromStdString( m_apcStreamResourcesList[id]->getFileName() ) ).completeBaseName() ); + QFileInfo( QString::fromStdString( m_apcStreamResourcesList[id]->getResourceName() ) ).completeBaseName() ); m_apcStreamResourcesWorkersList[id]->start(); } @@ -166,4 +212,4 @@ void ResourceHandle::wakeResourceWorker( std::size_t id ) return; } m_apcStreamResourcesWorkersList[id]->wake(); -} \ No newline at end of file +} diff --git a/app/ResourceHandle.h b/app/ResourceHandle.h index 2d1aeb8..c285aa7 100644 --- a/app/ResourceHandle.h +++ b/app/ResourceHandle.h @@ -26,11 +26,13 @@ #define __RESOURCEHANDLE_H__ #include +#include #include #include #include #include +#include "CalypResource.h" #include "CommonDefs.h" #include "lib/CalypStream.h" @@ -39,35 +41,72 @@ class ResourceWorker : public QThread private: QMutex m_Mutex; QWaitCondition m_ResourceIdle; - std::shared_ptr m_pcStream; + std::shared_ptr m_resource; std::atomic m_bStop{ false }; + std::atomic m_bStarted{ false }; + std::atomic m_bStarting{ false }; public: - ResourceWorker( std::shared_ptr stream ); + ResourceWorker( std::shared_ptr resource ) : m_resource{ std::move( resource ) } {} + ResourceWorker( ResourceWorker&& other ) noexcept = delete; + ResourceWorker& operator=( ResourceWorker&& other ) noexcept = delete; + ResourceWorker( const ResourceWorker& other ) = delete; + ResourceWorker& operator=( const ResourceWorker& other ) = delete; + ~ResourceWorker(); void stop(); void wake(); - void run(); + void start(); + void run() override; + auto mutex() -> QMutex* { return &m_Mutex; } }; -class ResourceHandle +class ResourceWorker; + +class ResourceHandle : public QObject { + Q_OBJECT public: - ResourceHandle(); - ~ResourceHandle() = default; + ResourceHandle( QObject* parent ); + ResourceHandle( ResourceHandle&& other ) noexcept = delete; + ResourceHandle& operator=( ResourceHandle&& other ) noexcept = delete; + ResourceHandle( const ResourceHandle& other ) = delete; + ResourceHandle& operator=( const ResourceHandle& other ) = delete; + ~ResourceHandle(); auto getResource( CalypStream* ptr ) -> std::size_t; auto getResourceAsset( std::size_t id ) -> CalypStream*; + auto appendResource( std::unique_ptr&& resource ) -> std::size_t; + void removeResource( std::size_t id ); void stopResourceWorker( std::size_t id ); void startResourceWorker( std::size_t id ); void wakeResourceWorker( std::size_t id ); + template + auto executeResourceAction( std::size_t id, const std::function& action ) -> bool + { + static_assert( std::is_base_of::value, "T must inherit from CalypResource" ); + if( !m_apcStreamResourcesList.count( id ) ) + { + assert( false ); + return false; + } + bool result{ false }; + if( auto resource = dynamic_cast( m_apcStreamResourcesList[id].get() ) ) + { + QMutexLocker locker( m_apcStreamResourcesWorkersList[id]->mutex() ); + result = action( resource ); + } + m_apcStreamResourcesWorkersList[id]->wake(); + return result; + } + private: auto addResource() -> std::size_t; private: std::size_t unique_id{ 0 }; - std::map> m_apcStreamResourcesList; + std::map> m_apcStreamResourcesList; std::map> m_apcStreamResourcesWorkersList; }; diff --git a/app/VideoHandle.cpp b/app/VideoHandle.cpp index 70c6b42..0ad1f37 100644 --- a/app/VideoHandle.cpp +++ b/app/VideoHandle.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "FrameNumberWidget.h" @@ -45,15 +46,13 @@ #include "lib/CalypFrame.h" VideoHandle::VideoHandle( QWidget* parent, SubWindowHandle* windowManager ) - : m_pcParent( parent ), m_pcMainWindowManager( windowManager ) + : m_pcParent{ parent } + , m_pcMainWindowManager{ windowManager } + , m_pcPlayingTimer{ new QTimer{ this } } + , m_pcFrameRateFeedbackTimer{ std::make_unique() } { - m_pcCurrentVideoSubWindow = NULL; - m_bIsPlaying = false; - m_pcPlayingTimer = new QTimer( this ); - m_pcFrameRateFeedbackTimer = std::make_unique(); m_pcPlayingTimer->setTimerType( Qt::PreciseTimer ); - connect( m_pcPlayingTimer, &QTimer::timeout, - this, &VideoHandle::playEvent ); + connect( m_pcPlayingTimer, &QTimer::timeout, this, &VideoHandle::playEvent ); m_acPlayingSubWindows.clear(); } @@ -61,6 +60,10 @@ VideoHandle::~VideoHandle() = default; void VideoHandle::createActions() { + if( m_pcParent == nullptr ) + { + return; + } m_arrayActions.resize( TOTAL_ACT ); m_arrayActions[PLAY_ACT] = new QAction( "Play", this ); m_arrayActions[PLAY_ACT]->setStatusTip( "Play/Pause" ); @@ -199,6 +202,10 @@ void VideoHandle::createActions() QMenu* VideoHandle::createVideoMenu() { + if( m_pcParent == nullptr ) + { + return nullptr; + } m_pcMenuVideo = new QMenu( "Video", m_pcParent ); m_pcMenuVideo->addAction( m_arrayActions[PLAY_ACT] ); m_pcMenuVideo->addAction( m_arrayActions[STOP_ACT] ); @@ -214,6 +221,10 @@ QMenu* VideoHandle::createVideoMenu() QMenu* VideoHandle::createImageMenu() { + if( m_pcParent == nullptr ) + { + return nullptr; + } m_pcMenuImage = new QMenu( "Image", m_pcParent ); m_menuComponent = m_pcMenuImage->addMenu( "Component" ); m_menuComponent->addActions( m_actionGroupComponent->actions() ); @@ -229,6 +240,10 @@ QMenu* VideoHandle::createImageMenu() QToolBar* VideoHandle::createToolBar() { + if( m_pcParent == nullptr ) + { + return nullptr; + } m_toolbarVideo = new QToolBar( tr( "Video" ) ); m_toolbarVideo->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea ); m_toolbarVideo->addAction( m_arrayActions[PLAY_ACT] ); @@ -251,6 +266,10 @@ QToolBar* VideoHandle::createToolBar() QDockWidget* VideoHandle::createDock() { + if( m_pcParent == nullptr ) + { + return nullptr; + } m_pcFramePropertiesSideBar = new FramePropertiesDock( m_pcParent, &m_bIsPlaying ); m_pcFramePropertiesDock = new QDockWidget( tr( "Frame Information" ), m_pcParent ); m_pcFramePropertiesDock->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea ); @@ -262,6 +281,10 @@ QDockWidget* VideoHandle::createDock() QWidget* VideoHandle::createStatusBarMessage() { + if( m_pcParent == nullptr ) + { + return nullptr; + } QWidget* pcStatusBarWidget = new QWidget; QHBoxLayout* mainlayout = new QHBoxLayout; @@ -507,14 +530,11 @@ void VideoHandle::addSubWindow( VideoSubWindow* window ) window->getViewArea()->setTool( m_uiViewTool ); window->getViewArea()->setGridVisible( m_arrayActions[SHOW_GRID_ACT]->isChecked() ); - connect( window, &SubWindowAbstract::aboutToClose, - this, &VideoHandle::closeSubWindow ); + connect( window, &SubWindowAbstract::aboutToClose, this, &VideoHandle::closeSubWindow ); - connect( window, &SubWindowAbstract::zoomFactorChanged, - this, &VideoHandle::zoomToFactorAll ); + connect( window, &SubWindowAbstract::zoomFactorChanged, this, &VideoHandle::zoomToFactorAll ); - connect( window, &SubWindowAbstract::scrollBarMoved, - this, &VideoHandle::moveAllScrollBars ); + connect( window, &SubWindowAbstract::scrollBarMoved, this, &VideoHandle::moveAllScrollBars ); connect( window->getViewArea(), SIGNAL( selectionChanged( QRect ) ), this, SLOT( updateSelectionArea( QRect ) ) ); } @@ -540,18 +560,15 @@ void VideoHandle::closeSubWindow( SubWindowAbstract* subWindow ) void VideoHandle::zoomToFactorAll( const double scale, const QPoint center ) { - double factor; - if( m_arrayActions[VIDEO_ZOOM_LOCK_ACT]->isChecked() ) { - factor = m_pcCurrentVideoSubWindow->getScaleFactor(); + double factor = m_pcCurrentVideoSubWindow->getScaleFactor(); - SubWindowAbstract* subWindow; QList subWindowList = m_pcMainWindowManager->findSubWindow( SubWindowAbstract::VIDEO_SUBWINDOW ); for( int i = 0; i < subWindowList.size(); i++ ) { - subWindow = subWindowList.at( i ); + SubWindowAbstract* subWindow = subWindowList.at( i ); if( m_pcCurrentVideoSubWindow == subWindow ) continue; else @@ -605,12 +622,12 @@ void VideoHandle::moveAllScrollBars( const double& horRatio, const double& verRa { if( m_arrayActions[VIDEO_ZOOM_LOCK_ACT]->isChecked() && m_pcCurrentVideoSubWindow ) { - VideoSubWindow* videoSubWindow; - QList subWindowList = m_pcMainWindowManager->findSubWindow( SubWindowAbstract::VIDEO_SUBWINDOW ); + QList subWindowList = + m_pcMainWindowManager->findSubWindow( SubWindowAbstract::VIDEO_SUBWINDOW ); for( int i = 0; i < subWindowList.size(); i++ ) { - videoSubWindow = qobject_cast( subWindowList.at( i ) ); + VideoSubWindow* videoSubWindow = qobject_cast( subWindowList.at( i ) ); if( m_pcCurrentVideoSubWindow == videoSubWindow ) continue; else @@ -624,15 +641,14 @@ void VideoHandle::moveAllScrollBars( const double& horRatio, const double& verRa unsigned long VideoHandle::getMaxFrameNumber() { - unsigned long currFrames; - unsigned long maxFrames = INT_MAX; + std::uint64_t maxFrames = std::numeric_limits::max(); if( m_pcCurrentVideoSubWindow ) { if( m_acPlayingSubWindows.contains( qobject_cast( m_pcCurrentVideoSubWindow ) ) ) { for( int i = 0; i < m_acPlayingSubWindows.size(); i++ ) { - currFrames = m_acPlayingSubWindows.at( i )->getFrameNum(); + auto currFrames = m_acPlayingSubWindows.at( i )->getFrameNum(); if( currFrames < maxFrames ) maxFrames = currFrames; } @@ -751,9 +767,12 @@ void VideoHandle::stop() void VideoHandle::calculateRealFrameRate() { double average_time_between_frames_ms = m_uiNumberPlayedFrames > 0 ? 1000.0 / m_uiRealAverageFrameRate : 0; - double time_elapsed_since_last_frame_ms = m_pcFrameRateFeedbackTimer->elapsed(); - average_time_between_frames_ms = double( average_time_between_frames_ms * m_uiNumberPlayedFrames + time_elapsed_since_last_frame_ms ) / double( m_uiNumberPlayedFrames + 1 ); - m_uiRealAverageFrameRate = 1000.0 / average_time_between_frames_ms; + auto time_elapsed_since_last_frame_ms = static_cast( m_pcFrameRateFeedbackTimer->elapsed() ); + average_time_between_frames_ms = + double( average_time_between_frames_ms * m_uiNumberPlayedFrames + time_elapsed_since_last_frame_ms ) / + double( m_uiNumberPlayedFrames + 1 ); + m_uiRealAverageFrameRate = + std::round( static_cast( 1000.0 / average_time_between_frames_ms ) ); m_uiNumberPlayedFrames++; m_pcFrameRateFeedbackTimer->restart(); } @@ -796,7 +815,8 @@ void VideoHandle::playEvent() } catch( const char* msg ) { - QString warningMsg = "Error while playing " + m_pcCurrentVideoSubWindow->getWindowName() + " with the following error: \n" + msg; + QString warningMsg = + "Error while playing " + m_pcCurrentVideoSubWindow->getWindowName() + " with the following error: \n" + msg; QMessageBox::warning( m_pcParent, QApplication::applicationName(), warningMsg ); qDebug() << warningMsg; stop(); diff --git a/app/VideoHandle.h b/app/VideoHandle.h index 92bd824..f00acc4 100644 --- a/app/VideoHandle.h +++ b/app/VideoHandle.h @@ -122,11 +122,11 @@ private: QLabel* m_pcVideoFormatLabel; QLabel* m_pcResolutionLabel; - QPointer m_pcCurrentVideoSubWindow; + QPointer m_pcCurrentVideoSubWindow{ nullptr }; QVector m_acPlayingSubWindows; QTimer* m_pcPlayingTimer; - bool m_bIsPlaying; + bool m_bIsPlaying{ false }; unsigned int m_uiNumberPlayedFrames{ 0 }; unsigned int m_uiRealAverageFrameRate{ 0 }; diff --git a/app/VideoStreamSubWindow.cpp b/app/VideoStreamSubWindow.cpp index 271a8af..e8c11ea 100644 --- a/app/VideoStreamSubWindow.cpp +++ b/app/VideoStreamSubWindow.cpp @@ -37,58 +37,11 @@ #define QT_NO_CONCURRENT -/** - * \brief Functions to control data stream from stream information - */ - -QDataStream& operator<<( QDataStream& out, const CalypFileInfoVector& array ) -{ - CalypFileInfo d; - out << array.size(); - for( int i = 0; i < array.size(); i++ ) - { - d = array.at( i ); - out << d.m_cFilename << d.m_uiWidth << d.m_uiHeight << d.m_iPelFormat << d.m_uiBitsPelPixel << d.m_iEndianness - << d.m_uiFrameRate << d.m_uiFileSize << d.m_bForceRaw; - } - return out; -} - -QDataStream& operator>>( QDataStream& in, CalypFileInfoVector& array ) -{ - CalypFileInfo d; - int array_size{ 0 }; - in >> array_size; - for( int i = 0; i < array_size; i++ ) - { - in >> d.m_cFilename; - in >> d.m_uiWidth; - in >> d.m_uiHeight; - in >> d.m_iPelFormat; - in >> d.m_uiBitsPelPixel; - in >> d.m_iEndianness; - in >> d.m_uiFrameRate; - in >> d.m_uiFileSize; - in >> d.m_bForceRaw; - array.append( d ); - } - return in; -} - -auto findCalypStreamInfo( const CalypFileInfoVector& array, const QString& filename ) -> int -{ - for( int i = 0; i < array.size(); i++ ) - if( array.at( i ).m_cFilename == filename ) - return i; - return -1; -} - -VideoStreamSubWindow::VideoStreamSubWindow( QWidget* parent ) +VideoStreamSubWindow::VideoStreamSubWindow( ResourceHandle* resourceManager, QWidget* parent ) : VideoSubWindow( VideoSubWindow::VIDEO_STREAM_SUBWINDOW, parent ) - , m_pcResourceManager( nullptr ) - , m_pCurrStream( NULL ) - , m_bIsPlaying( false ) - + , m_pcResourceManager{ resourceManager } + , m_pCurrStream{ NULL } + , m_bIsPlaying{ false } { } @@ -159,83 +112,11 @@ void VideoStreamSubWindow::loadAll() QApplication::restoreOverrideCursor(); } -bool VideoStreamSubWindow::loadFile( QString cFilename, bool bForceDialog ) +void VideoStreamSubWindow::setResource( std::size_t id ) { - assert( m_pcResourceManager != nullptr ); - - ConfigureFormatDialog formatDialog( this ); - unsigned int Width = 0, Height = 0, BitsPel = 8, FrameRate = 30; - int Endianness = CLP_LITTLE_ENDIAN; - auto InputFormat = ClpPixelFormats::YUV420p; - QSettings appSettings; - - if( m_pCurrStream ) - m_pCurrStream->getFormat( Width, Height, InputFormat, BitsPel, Endianness, FrameRate ); - else - m_uiResourceId = m_pcResourceManager->getResource( nullptr ); - + m_uiResourceId = id; m_pCurrStream = m_pcResourceManager->getResourceAsset( m_uiResourceId ); - bool bConfig = true; - if( !bForceDialog ) - { - bConfig = guessFormat( cFilename, Width, Height, InputFormat, BitsPel, Endianness, FrameRate ); - if( bConfig ) - { - // Pre-load values with last opened file - Width = appSettings.value( "VideoStreamSubWindow/LastWidth" ).value(); - Height = appSettings.value( "VideoStreamSubWindow/LastHeight" ).value(); - BitsPel = appSettings.value( "VideoStreamSubWindow/LastBitsPerPixel" ).value(); - } - } - bool bRet{ false }; - bool forceRaw{ false }; - for( int iPass = 0; iPass < 2 && !bRet; iPass++ ) - { - if( iPass || bConfig ) - { - if( formatDialog.runConfigureFormatDialog( QFileInfo( cFilename ).fileName(), Width, Height, InputFormat, BitsPel, - Endianness, FrameRate ) == QDialog::Rejected ) - { - return false; - } - } - try - { - bRet = m_pCurrStream->open( cFilename.toStdString(), Width, Height, InputFormat, BitsPel, Endianness, FrameRate, - iPass == 1, CalypStream::Type::Input ); - forceRaw = iPass > 0; - } - catch( CalypFailure& e ) - { - if( iPass > 0 ) - throw( e ); - } - } - - if( !bRet ) - { - return false; - } - - m_sStreamInfo.m_cFilename = cFilename; - m_sStreamInfo.m_uiWidth = Width; - m_sStreamInfo.m_uiHeight = Height; - m_sStreamInfo.m_iPelFormat = static_cast( InputFormat ); - m_sStreamInfo.m_uiBitsPelPixel = BitsPel; - m_sStreamInfo.m_iEndianness = Endianness; - m_sStreamInfo.m_uiFrameRate = FrameRate; - m_sStreamInfo.m_uiFileSize = QFileInfo( cFilename ).size(); - m_sStreamInfo.m_bForceRaw = forceRaw; - - QVariant var; - var.setValue( Width ); - appSettings.setValue( "VideoStreamSubWindow/LastWidth", var ); - var.setValue( Height ); - appSettings.setValue( "VideoStreamSubWindow/LastHeight", var ); - var.setValue( BitsPel ); - appSettings.setValue( "VideoStreamSubWindow/LastBitsPerPixel", var ); - #ifdef CALYP_MANAGED_RESOURCES m_pcResourceManager->startResourceWorker( m_uiResourceId ); #endif @@ -244,198 +125,137 @@ bool VideoStreamSubWindow::loadFile( QString cFilename, bool bForceDialog ) refreshFrame(); - m_cFilename = cFilename; + m_cFilename = QString::fromStdString( m_pCurrStream->getFileName() ); updateVideoWindowInfo(); setWindowName( QFileInfo( m_cFilename ).fileName() ); - - return true; } -bool VideoStreamSubWindow::loadFile( CalypFileInfo streamInfo ) -{ - assert( m_pcResourceManager != nullptr ); +// bool VideoStreamSubWindow::loadFile( QString cFilename, bool bForceDialog ) +// { +// assert( m_pcResourceManager != nullptr ); - m_uiResourceId = m_pcResourceManager->getResource( m_pCurrStream ); - m_pCurrStream = m_pcResourceManager->getResourceAsset( m_uiResourceId ); +// ConfigureFormatDialog formatDialog( this ); +// unsigned int Width = 0, Height = 0, BitsPel = 8, FrameRate = 30; +// int Endianness = CLP_LITTLE_ENDIAN; +// auto InputFormat = ClpPixelFormats::YUV420p; +// QSettings appSettings; - if( !m_pCurrStream->open( streamInfo.m_cFilename.toStdString(), streamInfo.m_uiWidth, streamInfo.m_uiHeight, - static_cast( streamInfo.m_iPelFormat ), streamInfo.m_uiBitsPelPixel, - streamInfo.m_iEndianness, streamInfo.m_uiFrameRate, streamInfo.m_bForceRaw, - CalypStream::Type::Input ) ) - { - return false; - } +// if( m_pCurrStream ) +// m_pCurrStream->getFormat( Width, Height, InputFormat, BitsPel, Endianness, FrameRate ); +// else +// m_uiResourceId = m_pcResourceManager->getResource( nullptr ); - m_cFilename = streamInfo.m_cFilename; - m_sStreamInfo = std::move( streamInfo ); +// m_pCurrStream = m_pcResourceManager->getResourceAsset( m_uiResourceId ); -#ifdef CALYP_MANAGED_RESOURCES - m_pcResourceManager->startResourceWorker( m_uiResourceId ); -#endif +// bool bConfig = true; +// if( !bForceDialog ) +// { +// bConfig = guessFormat( cFilename, Width, Height, InputFormat, BitsPel, Endianness, FrameRate ); +// if( bConfig ) +// { +// // Pre-load values with last opened file +// Width = appSettings.value( "VideoStreamSubWindow/LastWidth" ).value(); +// Height = appSettings.value( "VideoStreamSubWindow/LastHeight" ).value(); +// BitsPel = appSettings.value( "VideoStreamSubWindow/LastBitsPerPixel" ).value(); +// } +// } +// bool bRet{ false }; +// bool forceRaw{ false }; +// for( int iPass = 0; iPass < 2 && !bRet; iPass++ ) +// { +// if( iPass || bConfig ) +// { +// if( formatDialog.runConfigureFormatDialog( QFileInfo( cFilename ).fileName(), Width, Height, InputFormat, +// BitsPel, +// Endianness, FrameRate ) == QDialog::Rejected ) +// { +// return false; +// } +// } +// try +// { +// bRet = m_pCurrStream->open( cFilename.toStdString(), Width, Height, InputFormat, BitsPel, Endianness, +// FrameRate, +// iPass == 1, CalypStream::Type::Input ); +// forceRaw = iPass > 0; +// } +// catch( CalypFailure& e ) +// { +// if( iPass > 0 ) +// throw( e ); +// } +// } - QApplication::restoreOverrideCursor(); +// if( !bRet ) +// { +// return false; +// } - refreshFrame(); +// m_sStreamInfo.m_cFilename = cFilename; +// m_sStreamInfo.m_uiWidth = Width; +// m_sStreamInfo.m_uiHeight = Height; +// m_sStreamInfo.m_iPelFormat = InputFormat; +// m_sStreamInfo.m_uiBitsPelPixel = BitsPel; +// m_sStreamInfo.m_iEndianness = Endianness; +// m_sStreamInfo.m_uiFrameRate = FrameRate; +// m_sStreamInfo.m_uiFileSize = QFileInfo( cFilename ).size(); +// m_sStreamInfo.m_bForceRaw = forceRaw; - updateVideoWindowInfo(); - setWindowName( QFileInfo( m_cFilename ).fileName() ); - return true; -} +// QVariant var; +// var.setValue( Width ); +// appSettings.setValue( "VideoStreamSubWindow/LastWidth", var ); +// var.setValue( Height ); +// appSettings.setValue( "VideoStreamSubWindow/LastHeight", var ); +// var.setValue( BitsPel ); +// appSettings.setValue( "VideoStreamSubWindow/LastBitsPerPixel", var ); -bool VideoStreamSubWindow::guessFormat( const QString& filename, unsigned int& rWidth, unsigned int& rHeight, - ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPixel, int& rEndianness, - unsigned int& rFrameRate ) -{ - std::vector stdResList = CalypStream::stdResolutionSizes(); - bool bGuessed = true; - bool bGuessedByFilesize = false; - QString FilenameShort = QFileInfo( filename ).fileName(); - QString fileExtension = QFileInfo( filename ).suffix(); +// #ifdef CALYP_MANAGED_RESOURCES +// m_pcResourceManager->startResourceWorker( m_uiResourceId ); +// #endif - if( filename.startsWith( "/dev/" ) ) - { - return false; - } - if( !fileExtension.compare( "yuv", Qt::CaseInsensitive ) || !fileExtension.compare( "rgb", Qt::CaseInsensitive ) || - !fileExtension.compare( "gray", Qt::CaseInsensitive ) ) - { - bGuessed = false; - // Guess pixel format - const auto& formats_list = CalypFrame::supportedPixelFormatListNames(); - for( const auto& [key, name] : formats_list ) - { - if( FilenameShort.contains( QString::fromStdString( std::string( name ) ), Qt::CaseInsensitive ) ) - { - rInputFormat = key; - break; - } - } +// QApplication::restoreOverrideCursor(); - if( rWidth == 0 || rHeight == 0 ) - { - // Guess resolution - match resolution name - int iMatch = -1; - for( unsigned int i = 0; i < stdResList.size(); i++ ) - { - if( FilenameShort.contains( QString::fromStdString( stdResList[i].shortName ) ) ) - { - iMatch = i; - } - } - if( iMatch >= 0 ) - { - rWidth = stdResList[iMatch].uiWidth; - rHeight = stdResList[iMatch].uiHeight; - } +// refreshFrame(); - // Guess resolution - match %dx%d - // QRegularExpressionMatch resolutionMatch = QRegularExpression( "_\\d*x\\d*" ).match( FilenameShort ); - QRegularExpressionMatch resolutionMatch = QRegularExpression( "_[0-9]+x[0-9]+" ).match( FilenameShort ); - if( resolutionMatch.hasMatch() ) - { - QString resolutionString = resolutionMatch.captured( resolutionMatch.lastCapturedIndex() ); - if( resolutionString.startsWith( "_" ) || resolutionString.endsWith( "_" ) ) - { - resolutionString.remove( "_" ); - QStringList resolutionArgs = resolutionString.split( "x" ); - if( resolutionArgs.size() == 2 ) - { - rWidth = resolutionArgs.at( 0 ).toUInt(); - rHeight = resolutionArgs.at( 1 ).toUInt(); - } - } - } - } +// m_cFilename = cFilename; - // Guess resolution by file size - if( rWidth == 0 && rHeight == 0 ) - { - FILE* pF = fopen( filename.toStdString().c_str(), "rb" ); - if( pF ) - { - fseek( pF, 0, SEEK_END ); - unsigned long long int uiFileSize = ftell( pF ); - fclose( pF ); +// updateVideoWindowInfo(); +// setWindowName( QFileInfo( m_cFilename ).fileName() ); - int count = 0; - int match = -1; - for( unsigned int i = 0; i < stdResList.size(); i++ ) - { - auto frame_bytes = - CalypFrame::getBytesPerFrame( stdResList[i].uiWidth, stdResList[i].uiHeight, rInputFormat, 8 ); - auto module = uiFileSize % frame_bytes; - if( module == 0 ) - { - match = i; - count++; - } - } - if( count == 1 ) - { - rWidth = stdResList[match].uiWidth; - rHeight = stdResList[match].uiHeight; - bGuessedByFilesize = true; - } - } - } +// return true; +// } - // [.|_] - // Guess bits per pixel - match %dbpp - QRegularExpressionMatch BppMatch = QRegularExpression( "_[0-9]+bpp" ).match( FilenameShort ); - if( BppMatch.hasMatch() ) - { - QString matchString = BppMatch.captured( BppMatch.lastCapturedIndex() ); - matchString.remove( "_" ); - matchString.remove( "bpp" ); - rBitsPerPixel = matchString.toUInt(); - if( !( rBitsPerPixel > 0 && rBitsPerPixel < 16 ) ) - { - rBitsPerPixel = -1; - } - } - QRegularExpressionMatch BppOnlyMatch = QRegularExpression( "_[0-9]+b" ).match( FilenameShort ); - if( BppOnlyMatch.hasMatch() ) - { - QString matchString = BppOnlyMatch.captured( BppOnlyMatch.lastCapturedIndex() ); - matchString.remove( "_" ); - matchString.remove( "b" ); - rBitsPerPixel = matchString.toUInt(); - if( !( rBitsPerPixel > 0 && rBitsPerPixel < 16 ) ) - { - rBitsPerPixel = -1; - } - } +// bool VideoStreamSubWindow::loadFile( CalypFileInfo streamInfo ) +// { +// assert( m_pcResourceManager != nullptr ); - // Guess frame rate - match %dbpp - QRegularExpressionMatch FpsMatch = QRegularExpression( "_[0-9]+fps" ).match( FilenameShort ); - if( FpsMatch.hasMatch() ) - { - QString matchString = FpsMatch.captured( FpsMatch.lastCapturedIndex() ); - matchString.remove( "_" ); - matchString.remove( "fps" ); - rFrameRate = matchString.toUInt(); - if( rFrameRate < 0 ) - { - rFrameRate = 30; - } - } +// m_uiResourceId = m_pcResourceManager->getResource( m_pCurrStream ); +// m_pCurrStream = m_pcResourceManager->getResourceAsset( m_uiResourceId ); - // Guess Endianness - if( FilenameShort.contains( QStringLiteral( "be" ), Qt::CaseInsensitive ) ) - { - rEndianness = CLP_BIG_ENDIAN; - } - if( FilenameShort.contains( QStringLiteral( "le" ), Qt::CaseInsensitive ) ) - { - rEndianness = CLP_LITTLE_ENDIAN; - } +// if( !m_pCurrStream->open( streamInfo.m_cFilename.toStdString(), streamInfo.m_uiWidth, streamInfo.m_uiHeight, +// static_cast( streamInfo.m_iPelFormat ), streamInfo.m_uiBitsPelPixel, +// streamInfo.m_iEndianness, streamInfo.m_uiFrameRate, streamInfo.m_bForceRaw, +// CalypStream::Type::Input ) ) +// { +// return false; +// } - if( rWidth > 0 && rHeight > 0 && rInputFormat != ClpPixelFormats::Invalid ) - bGuessed = true && !bGuessedByFilesize; - } - return !bGuessed; -} +// m_cFilename = streamInfo.m_cFilename; +// m_sStreamInfo = std::move( streamInfo ); + +// #ifdef CALYP_MANAGED_RESOURCES +// m_pcResourceManager->startResourceWorker( m_uiResourceId ); +// #endif + +// QApplication::restoreOverrideCursor(); + +// refreshFrame(); + +// updateVideoWindowInfo(); +// setWindowName( QFileInfo( m_cFilename ).fileName() ); +// return true; +// } void VideoStreamSubWindow::refreshSubWindow() { diff --git a/app/VideoStreamSubWindow.h b/app/VideoStreamSubWindow.h index 24b9c64..9fcf324 100644 --- a/app/VideoStreamSubWindow.h +++ b/app/VideoStreamSubWindow.h @@ -36,6 +36,7 @@ #include "VideoSubWindow.h" #include "config.h" #include "lib/CalypStream.h" +#include "models/VideostreamResource.h" class QScrollArea; @@ -44,30 +45,12 @@ class VideoStreamSubWindow; class ResourceHandle; class CalypAppModuleIf; -struct CalypFileInfo -{ - QString m_cFilename; - unsigned int m_uiWidth; - unsigned int m_uiHeight; - int m_iPelFormat; - unsigned int m_uiBitsPelPixel; - int m_iEndianness; - unsigned int m_uiFrameRate; - unsigned long long int m_uiFileSize; - bool m_bForceRaw{ false }; -}; -using CalypFileInfoVector = QVector; - -QDataStream& operator<<( QDataStream& out, const CalypFileInfoVector& d ); -QDataStream& operator>>( QDataStream& in, CalypFileInfoVector& d ); -auto findCalypStreamInfo( const CalypFileInfoVector& array, const QString& filename ) -> int; - class VideoStreamSubWindow : public VideoSubWindow { Q_OBJECT public: - VideoStreamSubWindow( QWidget* parent = 0 ); + VideoStreamSubWindow( ResourceHandle* resourceManager, QWidget* parent = 0 ); ~VideoStreamSubWindow(); void resetWindowName() override; @@ -78,12 +61,11 @@ public: void advanceOneFrame() override { goToNextFrame( true ); } auto getFrameNum() -> std::uint64_t override { return m_pCurrStream->getFrameNum(); } - void setResourceManaget( ResourceHandle* resourceManager ) { m_pcResourceManager = resourceManager; } - bool supportsFormatConfiguration() const { return m_pCurrStream->supportsFormatConfiguration(); }; - bool loadFile( QString cFilename, bool bForceDialog = false ); - bool loadFile( CalypFileInfo streamInfo ); + void setResource( std::size_t id ); + // bool loadFile( QString cFilename, bool bForceDialog = false ); + // bool loadFile( CalypFileInfo streamInfo ); void loadAll(); bool saveStream( const QString& filename ); @@ -107,15 +89,12 @@ public: private: bool goToNextFrame( bool bThreaded ); - static bool guessFormat( const QString& filename, unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPixel, - int& rEndianness, unsigned int& rFrameRate ); - private: // NO_LINT ResourceHandle* m_pcResourceManager; + std::size_t m_uiResourceId; QString m_cFilename; CalypFileInfo m_sStreamInfo; - std::size_t m_uiResourceId; CalypStream* m_pCurrStream; QString m_cCurrFileName; @@ -129,7 +108,4 @@ private: // NO_LINT QFuture m_cReadResult; }; -Q_DECLARE_METATYPE( CalypFileInfo ) // NOLINT -Q_DECLARE_METATYPE( CalypFileInfoVector ) // NOLINT - #endif // __VIDEOSTREAMSUBWINDOW_H__ diff --git a/app/catch2/CMakeLists.txt b/app/catch2/CMakeLists.txt new file mode 100644 index 0000000..a79c31c --- /dev/null +++ b/app/catch2/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# CMakeLists for Calyp lis tests using catch2 +# + +FETCHCONTENT_MAKEAVAILABLE(Catch2) + +SET(Calyp_App_Catch2_Tests_SRCS CalypAppTests.cpp CalypResourcesTests.cpp) + +ADD_DEFINITIONS(-DCALYP_TEST_DATA_DIR=\"${CALYP_TEST_DATA_DIR}\") + +ADD_EXECUTABLE(CalypAppCatch2Tests ${Calyp_App_Catch2_Tests_SRCS}) +TARGET_LINK_LIBRARIES( + CalypAppCatch2Tests + ${PROJECT_LIBRARY} + CalypModules + ${APP_LINKER_LIBS} + ${QT_LINKER_LIBS} + QCustomPlotLib + Catch2::Catch2 +) +CATCH_DISCOVER_TESTS(CalypAppCatch2Tests) diff --git a/app/catch2/CalypAppTests.cpp b/app/catch2/CalypAppTests.cpp new file mode 100644 index 0000000..7bff40f --- /dev/null +++ b/app/catch2/CalypAppTests.cpp @@ -0,0 +1,26 @@ +/* This file is a part of plaYUVer project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * \file CalypLibTests.cpp + * \brief CalypLib main test file + */ + +#define CATCH_CONFIG_MAIN +#include diff --git a/app/catch2/CalypResourcesTests.cpp b/app/catch2/CalypResourcesTests.cpp new file mode 100644 index 0000000..c587583 --- /dev/null +++ b/app/catch2/CalypResourcesTests.cpp @@ -0,0 +1,285 @@ +/* This file is a part of plaYUVer project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * \file CalypResourcesTests.cpp + * \brief Resouce handling tests + */ + +#include +#include +#include +#include +#include + +#include "ResourceHandle.h" +#include "lib/CalypFrame.h" +#include "lib/CalypStream.h" +#include "models/VideostreamResource.h" + +using namespace std::chrono_literals; + +constexpr int kFrameRate{ 30 }; +constexpr auto kStreamType = CalypStream::Type::Input; + +auto getFileTestFilename( const char* test_sequence ) -> std::string +{ + return std::string( CALYP_TEST_DATA_DIR ) + std::string( "/" ) + std::string( test_sequence ); +} + +TEST_CASE( "Can construct and destruct a resource", "VideoResource" ) +{ + auto videoResource = std::make_unique(); + CHECK( videoResource != nullptr ); +} + +TEST_CASE( "Can load a YUV file", "VideoResource" ) +{ + constexpr unsigned int kWidth{ 352 }; + constexpr unsigned int kHeight{ 288 }; + constexpr auto kInputFormat{ ClpPixelFormats::YUV420p }; + constexpr unsigned int kBitsPel{ 8 }; + constexpr auto KEndianness{ CLP_LITTLE_ENDIAN }; + + const auto kFilename = getFileTestFilename( "Foreman.yuv" ); + + REQUIRE( std::filesystem::exists( std::filesystem::path( kFilename ) ) ); + + auto resourceHandle = std::make_unique( nullptr ); + + auto videoResource = std::make_unique(); + + CalypFileInfo streamInfo{ .m_cFilename = QString::fromStdString( kFilename ) }; + CHECK_FALSE( videoResource->loadFile( streamInfo, false ) ); + + SECTION( "Now use a valid config" ) + { + streamInfo = CalypFileInfo{ .m_cFilename = QString::fromStdString( kFilename ), + .m_uiWidth = kWidth, + .m_uiHeight = kHeight, + .m_iPelFormat = kInputFormat, + .m_uiBitsPelPixel = kBitsPel, + .m_iEndianness = KEndianness, + .m_uiFrameRate = kFrameRate }; + + REQUIRE( videoResource->loadFile( streamInfo ) ); + + const auto& test_stream = videoResource->getStream(); + + CHECK( test_stream.getWidth() == kWidth ); + CHECK( test_stream.getHeight() == kHeight ); + CHECK( test_stream.getBitsPerPixel() == kBitsPel ); + CHECK( test_stream.getFormatName() == "YUV" ); + CHECK( test_stream.getCodecName() == "Raw Video" ); + CHECK( test_stream.getEndianess() == CLP_BIG_ENDIAN ); + + auto frame = videoResource->getCurrFrame(); + + CHECK( frame->getPixel( 2, 0 ) == CalypPixel{ CLP_COLOR_YUV, 201, 129, 125 } ); + CHECK( frame->getPixel( 336, 278 ) == CalypPixel{ CLP_COLOR_YUV, 99, 111, 142 } ); + } +} + +TEST_CASE( "Can load a MKV file", "VideoResource" ) +{ + constexpr unsigned int kWidth{ 352 }; + constexpr unsigned int kHeight{ 288 }; + constexpr unsigned int kBitsPel{ 8 }; + + const auto kFilename = getFileTestFilename( "Foreman.mkv" ); + + REQUIRE( std::filesystem::exists( std::filesystem::path( kFilename ) ) ); + + auto resourceHandle = std::make_unique( nullptr ); + + auto videoResource = std::make_unique( nullptr ); + + CalypFileInfo streamInfo{ .m_cFilename = QString::fromStdString( kFilename ) }; + REQUIRE( videoResource->loadFile( streamInfo ) ); + + const auto& test_stream = videoResource->getStream(); + + CHECK( test_stream.getWidth() == kWidth ); + CHECK( test_stream.getHeight() == kHeight ); + CHECK( test_stream.getBitsPerPixel() == kBitsPel ); + CHECK( test_stream.getFormatName() == "MKV" ); + CHECK( test_stream.getCodecName() == "h264" ); + CHECK( test_stream.getEndianess() == CLP_BIG_ENDIAN ); + + auto frame = videoResource->getCurrFrame(); + + CHECK( frame->getPixel( 311, 255 ) == CalypPixel{ CLP_COLOR_YUV, 83, 120, 132 } ); +} + +TEST_CASE( "Can load a PNG file", "VideoResource" ) +{ + constexpr unsigned int kWidth{ 352 }; + constexpr unsigned int kHeight{ 288 }; + constexpr unsigned int kBitsPel{ 8 }; + + const auto kFilename = getFileTestFilename( "Foreman.png" ); + + REQUIRE( std::filesystem::exists( std::filesystem::path( kFilename ) ) ); + + auto resourceHandle = std::make_unique( nullptr ); + + auto videoResource = std::make_unique( nullptr ); + + CalypFileInfo streamInfo{ .m_cFilename = QString::fromStdString( kFilename ) }; + + REQUIRE( videoResource->loadFile( streamInfo ) ); + + const auto& test_stream = videoResource->getStream(); + + CHECK( test_stream.getWidth() == kWidth ); + CHECK( test_stream.getHeight() == kHeight ); + CHECK( test_stream.getBitsPerPixel() == kBitsPel ); + CHECK( test_stream.getFormatName() == "PNG" ); + CHECK( test_stream.getCodecName() == "png" ); + CHECK( test_stream.getEndianess() == CLP_BIG_ENDIAN ); + + auto frame = videoResource->getCurrFrame(); + + CHECK( frame->getPixel( 292, 263 ) == CalypPixel{ CLP_COLOR_RGB, 92, 83, 54 } ); +} + +TEST_CASE( "Resource handle can store a video resource", "VideoResource" ) +{ + constexpr unsigned int kWidth{ 352 }; + constexpr unsigned int kHeight{ 288 }; + constexpr auto kInputFormat{ ClpPixelFormats::YUV420p }; + constexpr unsigned int kBitsPel{ 8 }; + constexpr auto KEndianness{ CLP_LITTLE_ENDIAN }; + + const auto kFilename = getFileTestFilename( "Foreman.yuv" ); + + REQUIRE( std::filesystem::exists( std::filesystem::path( kFilename ) ) ); + + auto resourceHandle = std::make_unique( nullptr ); + + CalypFileInfo streamInfo{ .m_cFilename = QString::fromStdString( kFilename ), + .m_uiWidth = kWidth, + .m_uiHeight = kHeight, + .m_iPelFormat = kInputFormat, + .m_uiBitsPelPixel = kBitsPel, + .m_iEndianness = KEndianness, + .m_uiFrameRate = kFrameRate }; + + { + auto videoResource = std::make_unique( nullptr ); + REQUIRE( videoResource != nullptr ); + CHECK( videoResource->loadFile( streamInfo ) ); + CHECK( resourceHandle->appendResource( std::move( videoResource ) ) == 0 ); + } + + auto videoResource = std::make_unique( nullptr ); + REQUIRE( videoResource != nullptr ); + CHECK( videoResource->loadFile( streamInfo ) ); + auto resource_id = resourceHandle->appendResource( std::move( videoResource ) ); + CHECK( resource_id == 1 ); + + SECTION( "Can start and stop resource" ) + { + resourceHandle->startResourceWorker( resource_id ); + std::this_thread::sleep_for( 20ms ); + resourceHandle->stopResourceWorker( resource_id ); + CHECK( true ); + } + + SECTION( "Can start without stopping (RAII will clear resource)" ) + { + resourceHandle->startResourceWorker( resource_id ); + CHECK( true ); + } + + resourceHandle->removeResource( resource_id ); +} + +TEST_CASE( "Resource handle can play a video resource", "VideoResource" ) +{ + constexpr unsigned int kWidth{ 352 }; + constexpr unsigned int kHeight{ 288 }; + constexpr auto kInputFormat{ ClpPixelFormats::YUV420p }; + constexpr unsigned int kBitsPel{ 8 }; + constexpr auto KEndianness{ CLP_LITTLE_ENDIAN }; + + const auto kFilename = getFileTestFilename( "Foreman.yuv" ); + + REQUIRE( std::filesystem::exists( std::filesystem::path( kFilename ) ) ); + + auto resourceHandle = std::make_unique( nullptr ); + + CalypFileInfo streamInfo{ .m_cFilename = QString::fromStdString( kFilename ), + .m_uiWidth = kWidth, + .m_uiHeight = kHeight, + .m_iPelFormat = kInputFormat, + .m_uiBitsPelPixel = kBitsPel, + .m_iEndianness = KEndianness, + .m_uiFrameRate = kFrameRate }; + + auto videoResource = std::make_unique( nullptr ); + REQUIRE( videoResource != nullptr ); + CHECK( videoResource->loadFile( streamInfo ) ); + + auto frame = videoResource->getCurrFrame(); + CHECK( frame->getPixel( 2, 0 ) == CalypPixel{ CLP_COLOR_YUV, 201, 129, 125 } ); + CHECK( frame->getPixel( 336, 278 ) == CalypPixel{ CLP_COLOR_YUV, 99, 111, 142 } ); + + auto resource_id = resourceHandle->appendResource( std::move( videoResource ) ); + + resourceHandle->executeResourceAction( resource_id, []( auto* resource ) { + resource->play(); + return true; + } ); + + resourceHandle->startResourceWorker( resource_id ); + + resourceHandle->executeResourceAction( resource_id, [&frame]( auto* resource ) { + resource->playEvent(); + frame = resource->getCurrFrame(); + return true; + } ); + CHECK( frame->getPixel( 298, 237 ) == CalypPixel{ CLP_COLOR_YUV, 82, 115, 134 } ); + + resourceHandle->executeResourceAction( resource_id, [&frame]( auto* resource ) { + resource->playEvent(); + frame = resource->getCurrFrame(); + return true; + } ); + CHECK_FALSE( frame->getPixel( 298, 237 ) == CalypPixel{ CLP_COLOR_YUV, 82, 115, 134 } ); + + SECTION( "Can Stop" ) + { + resourceHandle->executeResourceAction( resource_id, [&frame]( auto* resource ) { + resource->playEvent(); + frame = resource->getCurrFrame(); + return true; + } ); + + resourceHandle->executeResourceAction( resource_id, [&frame]( auto* resource ) { + resource->stop(); + frame = resource->getCurrFrame(); + return true; + } ); + CHECK( frame->getPixel( 2, 0 ) == CalypPixel{ CLP_COLOR_YUV, 201, 129, 125 } ); + CHECK( frame->getPixel( 336, 278 ) == CalypPixel{ CLP_COLOR_YUV, 99, 111, 142 } ); + } + + resourceHandle->stopResourceWorker( resource_id ); +} \ No newline at end of file diff --git a/app/dialog/ConfigureFormatDialog.cpp b/app/dialog/ConfigureFormatDialog.cpp index 818d367..6a7a1f8 100644 --- a/app/dialog/ConfigureFormatDialog.cpp +++ b/app/dialog/ConfigureFormatDialog.cpp @@ -73,8 +73,7 @@ QDataStream& operator>>( QDataStream& in, CalypStandardResolutionVector& array ) class AddCustomFormat : public QDialog { public: - AddCustomFormat( QWidget* parent = NULL ) - : QDialog( parent, Qt::Dialog | Qt::WindowTitleHint ) + AddCustomFormat( QWidget* parent = NULL ) : QDialog( parent, Qt::Dialog | Qt::WindowTitleHint ) { setWindowModality( Qt::ApplicationModal ); setWindowTitle( "Add custom resolution" ); @@ -137,8 +136,7 @@ private: QSpinBox* m_spinHeight; }; -ConfigureFormatDialog::ConfigureFormatDialog( QWidget* parent ) - : QDialog( parent ) +ConfigureFormatDialog::ConfigureFormatDialog( QWidget* parent ) : QDialog( parent ) { QString Name; unsigned int uiWidth, uiHeight; @@ -402,8 +400,10 @@ auto findPelFormatColorSpace( ClpPixelFormats rInputFormat ) -> std::pair QDialog::DialogCode { // Set default values // setWindowTitle( "Configure resolution for " + Filename ); diff --git a/app/dialog/ConfigureFormatDialog.h b/app/dialog/ConfigureFormatDialog.h index c2a97f5..6c5b3de 100644 --- a/app/dialog/ConfigureFormatDialog.h +++ b/app/dialog/ConfigureFormatDialog.h @@ -51,8 +51,9 @@ class ConfigureFormatDialog : public QDialog public: ConfigureFormatDialog( QWidget* parent = 0 ); - int runConfigureFormatDialog( const QString& Filename, unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, unsigned int& rBits, - int& rEndianess, unsigned int& rFrameRate ); + auto runConfigureFormatDialog( const QString& Filename, unsigned int& rWidth, unsigned int& rHeight, + ClpPixelFormats& rInputFormat, unsigned int& rBits, int& rEndianess, + unsigned int& rFrameRate ) -> QDialog::DialogCode; void readSettings(); void writeSettings(); diff --git a/app/models/CalypResource.h b/app/models/CalypResource.h new file mode 100644 index 0000000..3e739f0 --- /dev/null +++ b/app/models/CalypResource.h @@ -0,0 +1,51 @@ +/* This file is a part of Calyp project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * \file CalypResource.h + * \brief Abstract calyp resource + */ + +#ifndef __CALYPRESOURCE_H__ +#define __CALYPRESOURCE_H__ + +#include + +#include "lib/CalypStream.h" + +class CalypResource +{ +public: + virtual ~CalypResource() = default; + + virtual auto iteration() -> bool = 0; + virtual auto isReady() -> bool = 0; + + virtual auto getResourceName() -> std::string = 0; + [[deprecated( "Do not directly access the resource" )]] virtual auto getResource() -> CalypStream* = 0; + +protected: + CalypResource() = default; + CalypResource( CalypResource&& other ) noexcept = delete; + CalypResource& operator=( CalypResource&& other ) noexcept = delete; + CalypResource( const CalypResource& other ) = delete; + CalypResource& operator=( const CalypResource& other ) = delete; +}; + +#endif // __CALYPRESOURCE_H__ diff --git a/app/models/VideostreamResource.cpp b/app/models/VideostreamResource.cpp new file mode 100644 index 0000000..2ca2ec9 --- /dev/null +++ b/app/models/VideostreamResource.cpp @@ -0,0 +1,373 @@ +/* This file is a part of Calyp project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * \file VideostreamResource.h + * \brief Class to control video playback + */ + +#include "VideostreamResource.h" + +#include + +#include +#include +#include +#include +#include + +#include "lib/CalypFrame.h" + +/** + * \brief Functions to control data stream from stream information + */ + +QDataStream& operator<<( QDataStream& out, const CalypFileInfoVector& array ) +{ + CalypFileInfo d; + out << array.size(); + for( int i = 0; i < array.size(); i++ ) + { + d = array.at( i ); + out << d.m_cFilename << d.m_uiWidth << d.m_uiHeight << static_cast( d.m_iPelFormat ) << d.m_uiBitsPelPixel + << d.m_iEndianness << d.m_uiFrameRate << d.m_uiFileSize << d.m_bForceRaw; + } + return out; +} + +QDataStream& operator>>( QDataStream& in, CalypFileInfoVector& array ) +{ + int array_size{ 0 }; + in >> array_size; + for( int i = 0; i < array_size; i++ ) + { + CalypFileInfo d; + int pelFormat; + in >> d.m_cFilename; + in >> d.m_uiWidth; + in >> d.m_uiHeight; + in >> pelFormat; + in >> d.m_uiBitsPelPixel; + in >> d.m_iEndianness; + in >> d.m_uiFrameRate; + in >> d.m_uiFileSize; + in >> d.m_bForceRaw; + d.m_iPelFormat = static_cast( pelFormat ); + array.append( d ); + } + return in; +} + +auto findCalypStreamInfo( const CalypFileInfoVector& array, const QString& filename ) -> int +{ + for( int i = 0; i < array.size(); i++ ) + if( array.at( i ).m_cFilename == filename ) + return i; + return -1; +} + +VideostreamResource::VideostreamResource( QObject* parent ) : QObject{ parent } {} + +VideostreamResource::~VideostreamResource() = default; + +auto VideostreamResource::iteration() -> bool +{ + m_currStream.readNextFrameFillRGBBuffer(); + return true; +} + +auto VideostreamResource::isReady() -> bool +{ + return m_currStream.hasWritingSlot(); +} + +bool VideostreamResource::loadFile( const QString& cFilename ) +{ + CalypFileInfo streamInfo; + + m_currStream.getFormat( streamInfo.m_uiWidth, streamInfo.m_uiHeight, streamInfo.m_iPelFormat, + streamInfo.m_uiBitsPelPixel, streamInfo.m_iEndianness, streamInfo.m_uiFrameRate ); + + [[maybe_unused]] auto guessed = + video_resource_guess_format( cFilename, streamInfo.m_uiWidth, streamInfo.m_uiHeight, streamInfo.m_iPelFormat, + streamInfo.m_uiBitsPelPixel, streamInfo.m_iEndianness, streamInfo.m_uiFrameRate ); + + if( streamInfo.m_iPelFormat == ClpPixelFormats::Invalid ) + { + streamInfo.m_iPelFormat = ClpPixelFormats::YUV420p; + } + + streamInfo.m_cFilename = cFilename; + + return loadFile( streamInfo ); +} + +bool VideostreamResource::loadFile( const CalypFileInfo& streamInfo, bool optimistic ) +{ + m_sStreamInfo = streamInfo; + ClpPixelFormats inputFormat = static_cast( m_sStreamInfo.m_iPelFormat ); + + try + { + if( !m_currStream.open( streamInfo.m_cFilename.toStdString(), streamInfo.m_uiWidth, streamInfo.m_uiHeight, + inputFormat, streamInfo.m_uiBitsPelPixel, streamInfo.m_iEndianness, + streamInfo.m_uiFrameRate, streamInfo.m_bForceRaw, CalypStream::Type::Input ) ) + { + return false; + } + } + catch( CalypFailure& e ) + { + if( !optimistic ) + { + return false; + } + throw( e ); + } + + m_currStream.getFormat( m_sStreamInfo.m_uiWidth, m_sStreamInfo.m_uiHeight, m_sStreamInfo.m_iPelFormat, + m_sStreamInfo.m_uiBitsPelPixel, m_sStreamInfo.m_iEndianness, m_sStreamInfo.m_uiFrameRate ); + m_sStreamInfo.m_uiFileSize = QFileInfo{ streamInfo.m_cFilename }.size(); + + return true; +} + +auto VideostreamResource::getCurrFrame() -> std::shared_ptr +{ + return m_currStream.getCurrFrameAsset(); +} +bool VideostreamResource::play() +{ + bool isPlaying = false; + if( m_currStream.getFrameNum() > 1 ) + { + isPlaying = true; + } + m_bIsPlaying = isPlaying; + return m_bIsPlaying; +} + +bool VideostreamResource::playEvent() +{ + bool bEndOfSeq = false; + if( m_bIsPlaying ) + { + bEndOfSeq = goToNextFrame( true ); + } + return bEndOfSeq; +} + +void VideostreamResource::pause() +{ + m_bIsPlaying = false; + triggerRefresh(); +} + +void VideostreamResource::seekAbsoluteEvent( unsigned int new_frame_num ) +{ + if( m_currStream.seekInput( new_frame_num ) ) + triggerRefresh(); +} + +void VideostreamResource::seekRelativeEvent( bool bIsForward ) +{ + if( bIsForward ) + { + goToNextFrame( true ); + } + else + { + m_currStream.seekInputRelative( bIsForward ); + triggerRefresh(); + } +} + +void VideostreamResource::stop() +{ + m_bIsPlaying = false; + seekAbsoluteEvent( 0 ); + return; +} + +auto VideostreamResource::goToNextFrame( bool bThreaded ) -> bool +{ + while( !m_currStream.hasNextFrame() && !m_currStream.isEof() ) {} + bool bEndOfSeq = m_currStream.setNextFrame(); + if( !bEndOfSeq ) + { + triggerRefresh(); + } + return bEndOfSeq; +} + +void VideostreamResource::triggerRefresh() {} + +auto video_resource_guess_format( const QString& filename, unsigned int& rWidth, unsigned int& rHeight, + ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPixel, int& rEndianness, + unsigned int& rFrameRate ) -> bool +{ + std::vector stdResList = CalypStream::stdResolutionSizes(); + bool bGuessed = true; + bool bGuessedByFilesize = false; + QString FilenameShort = QFileInfo( filename ).fileName(); + QString fileExtension = QFileInfo( filename ).suffix(); + + if( filename.startsWith( "/dev/" ) ) + { + return true; + } + if( !fileExtension.compare( "yuv", Qt::CaseInsensitive ) || !fileExtension.compare( "rgb", Qt::CaseInsensitive ) || + !fileExtension.compare( "gray", Qt::CaseInsensitive ) ) + { + bGuessed = false; + // Guess pixel format + const auto& formats_list = CalypFrame::supportedPixelFormatListNames(); + for( const auto& [key, name] : formats_list ) + { + if( FilenameShort.contains( QString::fromStdString( std::string( name ) ), Qt::CaseInsensitive ) ) + { + rInputFormat = key; + break; + } + } + + if( rWidth == 0 || rHeight == 0 ) + { + // Guess resolution - match resolution name + int iMatch = -1; + for( unsigned int i = 0; i < stdResList.size(); i++ ) + { + if( FilenameShort.contains( QString::fromStdString( stdResList[i].shortName ) ) ) + { + iMatch = i; + } + } + if( iMatch >= 0 ) + { + rWidth = stdResList[iMatch].uiWidth; + rHeight = stdResList[iMatch].uiHeight; + } + + // Guess resolution - match %dx%d + // QRegularExpressionMatch resolutionMatch = QRegularExpression( "_\\d*x\\d*" ).match( FilenameShort ); + QRegularExpressionMatch resolutionMatch = QRegularExpression( "_[0-9]+x[0-9]+" ).match( FilenameShort ); + if( resolutionMatch.hasMatch() ) + { + QString resolutionString = resolutionMatch.captured( resolutionMatch.lastCapturedIndex() ); + if( resolutionString.startsWith( "_" ) || resolutionString.endsWith( "_" ) ) + { + resolutionString.remove( "_" ); + QStringList resolutionArgs = resolutionString.split( "x" ); + if( resolutionArgs.size() == 2 ) + { + rWidth = resolutionArgs.at( 0 ).toUInt(); + rHeight = resolutionArgs.at( 1 ).toUInt(); + } + } + } + } + + // Guess resolution by file size + if( rWidth == 0 && rHeight == 0 ) + { + FILE* pF = fopen( filename.toStdString().c_str(), "rb" ); + if( pF ) + { + fseek( pF, 0, SEEK_END ); + unsigned long long int uiFileSize = ftell( pF ); + fclose( pF ); + + int count = 0; + int match = -1; + for( unsigned int i = 0; i < stdResList.size(); i++ ) + { + auto frame_bytes = + CalypFrame::getBytesPerFrame( stdResList[i].uiWidth, stdResList[i].uiHeight, rInputFormat, 8 ); + auto module = uiFileSize % frame_bytes; + if( module == 0 ) + { + match = i; + count++; + } + } + if( count == 1 ) + { + rWidth = stdResList[match].uiWidth; + rHeight = stdResList[match].uiHeight; + bGuessedByFilesize = true; + } + } + } + + // [.|_] + // Guess bits per pixel - match %dbpp + QRegularExpressionMatch BppMatch = QRegularExpression( "_[0-9]+bpp" ).match( FilenameShort ); + if( BppMatch.hasMatch() ) + { + QString matchString = BppMatch.captured( BppMatch.lastCapturedIndex() ); + matchString.remove( "_" ); + matchString.remove( "bpp" ); + rBitsPerPixel = matchString.toUInt(); + if( !( rBitsPerPixel > 0 && rBitsPerPixel < 16 ) ) + { + rBitsPerPixel = -1; + } + } + QRegularExpressionMatch BppOnlyMatch = QRegularExpression( "_[0-9]+b" ).match( FilenameShort ); + if( BppOnlyMatch.hasMatch() ) + { + QString matchString = BppOnlyMatch.captured( BppOnlyMatch.lastCapturedIndex() ); + matchString.remove( "_" ); + matchString.remove( "b" ); + rBitsPerPixel = matchString.toUInt(); + if( !( rBitsPerPixel > 0 && rBitsPerPixel < 16 ) ) + { + rBitsPerPixel = -1; + } + } + + // Guess frame rate - match %dbpp + QRegularExpressionMatch FpsMatch = QRegularExpression( "_[0-9]+fps" ).match( FilenameShort ); + if( FpsMatch.hasMatch() ) + { + QString matchString = FpsMatch.captured( FpsMatch.lastCapturedIndex() ); + matchString.remove( "_" ); + matchString.remove( "fps" ); + rFrameRate = matchString.toUInt(); + if( rFrameRate < 0 ) + { + rFrameRate = 30; + } + } + + // Guess Endianness + if( FilenameShort.contains( QStringLiteral( "be" ), Qt::CaseInsensitive ) ) + { + rEndianness = CLP_BIG_ENDIAN; + } + if( FilenameShort.contains( QStringLiteral( "le" ), Qt::CaseInsensitive ) ) + { + rEndianness = CLP_LITTLE_ENDIAN; + } + + if( rWidth > 0 && rHeight > 0 && rInputFormat != ClpPixelFormats::Invalid ) + bGuessed = true && !bGuessedByFilesize; + } + return bGuessed; +} \ No newline at end of file diff --git a/app/models/VideostreamResource.h b/app/models/VideostreamResource.h new file mode 100644 index 0000000..94fb686 --- /dev/null +++ b/app/models/VideostreamResource.h @@ -0,0 +1,105 @@ +/* This file is a part of Calyp project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * \file VideostreamResource.h + * \brief Class to control video playback + */ + +#ifndef __VIDEOSTREAMRESOURCE_H__ +#define __VIDEOSTREAMRESOURCE_H__ + +#include +#include + +#include "CalypResource.h" +#include "CommonDefs.h" +#include "config.h" +#include "lib/CalypStream.h" + +struct CalypFileInfo +{ + QString m_cFilename; + unsigned int m_uiWidth; + unsigned int m_uiHeight; + ClpPixelFormats m_iPelFormat; + unsigned int m_uiBitsPelPixel{ 8 }; + int m_iEndianness{ CLP_LITTLE_ENDIAN }; + unsigned int m_uiFrameRate{ 30 }; + unsigned long long int m_uiFileSize; + bool m_bForceRaw{ false }; +}; +using CalypFileInfoVector = QVector; + +QDataStream& operator<<( QDataStream& out, const CalypFileInfoVector& d ); +QDataStream& operator>>( QDataStream& in, CalypFileInfoVector& d ); +auto findCalypStreamInfo( const CalypFileInfoVector& array, const QString& filename ) -> int; + +class VideostreamResource : public QObject, public CalypResource +{ + Q_OBJECT +public: + VideostreamResource( QObject* parent = nullptr ); + VideostreamResource( VideostreamResource&& other ) noexcept = delete; + VideostreamResource& operator=( VideostreamResource&& other ) noexcept = delete; + VideostreamResource( const VideostreamResource& other ) = delete; + VideostreamResource& operator=( const VideostreamResource& other ) = delete; + ~VideostreamResource(); + + auto getResourceName() -> std::string override { return m_currStream.getFileName(); }; + + auto iteration() -> bool override; + auto isReady() -> bool override; + + auto loadFile( const QString& cFilename ) -> bool; + auto loadFile( const CalypFileInfo& streamInfo, bool optimistic = true ) -> bool; + + auto getResource() -> CalypStream* override { return &m_currStream; }; + auto getStream() const -> const CalypStream& { return m_currStream; }; + auto getCurrFrame() -> std::shared_ptr; + + bool play(); + void pause(); + void stop(); + bool playEvent(); + void seekAbsoluteEvent( unsigned int new_frame_num ); + void seekRelativeEvent( bool bIsForward ); + +private: + auto goToNextFrame( bool bThreaded ) -> bool; + void triggerRefresh(); + + // Q_SIGNALS: + // private Q_SLOTS: + +private: + CalypStream m_currStream; + CalypFileInfo m_sStreamInfo; + + bool m_bIsPlaying; +}; + +auto video_resource_guess_format( const QString& filename, unsigned int& rWidth, unsigned int& rHeight, + ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPixel, int& rEndianness, + unsigned int& rFrameRate ) -> bool; + +Q_DECLARE_METATYPE( CalypFileInfo ) // NOLINT +Q_DECLARE_METATYPE( CalypFileInfoVector ) // NOLINT + +#endif // __VIDEOSTREAMRESOURCE_H__ diff --git a/lib/CalypPixel.cpp b/lib/CalypPixel.cpp index 95204a9..19d3612 100644 --- a/lib/CalypPixel.cpp +++ b/lib/CalypPixel.cpp @@ -36,9 +36,10 @@ constexpr auto kMaxPixelValue{ 255 }; static inline void yuvToRgb( const int& iY, const int& iU, const int& iV, int& iR, int& iG, int& iB ) { - iR = std::clamp( iY + ( ( 1436 * ( iV - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT - iG = std::clamp( iY - ( ( 352 * ( iU - 128 ) + 731 * ( iV - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT - iB = std::clamp( iY + ( ( 1812 * ( iU - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT + iR = std::clamp( iY + ( ( 1436 * ( iV - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT + iG = std::clamp( iY - ( ( 352 * ( iU - 128 ) + 731 * ( iV - 128 ) ) >> 10 ), kMinPixelValue, + kMaxPixelValue ); // NOLINT + iB = std::clamp( iY + ( ( 1812 * ( iU - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT } static inline void rgbToYuv( const int& iR, const int& iG, const int& iB, int& iY, int& iU, int& iV ) @@ -75,10 +76,7 @@ CalypPixel& CalypPixel::operator+=( const CalypPixel& in ) { assert( in.colorSpace() == m_colorSpace ); const auto& other_comp = in.components(); - std::transform( other_comp.begin(), - other_comp.end(), - m_pelComp.begin(), - m_pelComp.begin(), + std::transform( other_comp.begin(), other_comp.end(), m_pelComp.begin(), m_pelComp.begin(), []( auto& p1, auto& p2 ) { return p1 + p2; } ); return *this; } @@ -87,20 +85,14 @@ CalypPixel& CalypPixel::operator-=( const CalypPixel& in ) { assert( in.colorSpace() == m_colorSpace ); const auto& other_comp = in.components(); - std::transform( other_comp.begin(), - other_comp.end(), - m_pelComp.begin(), - m_pelComp.begin(), + std::transform( other_comp.begin(), other_comp.end(), m_pelComp.begin(), m_pelComp.begin(), []( auto& p1, auto& p2 ) { return p1 - p2; } ); return *this; } CalypPixel& CalypPixel::operator*=( const double op ) { - std::transform( m_pelComp.begin(), - m_pelComp.end(), - m_pelComp.begin(), - [&op]( auto& p1 ) { return p1 * op; } ); + std::transform( m_pelComp.begin(), m_pelComp.end(), m_pelComp.begin(), [&op]( auto& p1 ) { return p1 * op; } ); return *this; } @@ -109,10 +101,7 @@ CalypPixel CalypPixel::operator+( const CalypPixel& in ) const assert( in.colorSpace() == m_colorSpace ); const auto& other_comp = in.components(); CalypPixel result{ m_colorSpace }; - std::transform( other_comp.begin(), - other_comp.end(), - m_pelComp.begin(), - result.components().begin(), + std::transform( other_comp.begin(), other_comp.end(), m_pelComp.begin(), result.components().begin(), []( auto& p1, auto& p2 ) { return p1 + p2; } ); return result; } @@ -122,10 +111,7 @@ CalypPixel CalypPixel::operator-( const CalypPixel& in ) const assert( in.colorSpace() == m_colorSpace ); const auto& other_comp = in.components(); CalypPixel result{ m_colorSpace }; - std::transform( other_comp.begin(), - other_comp.end(), - m_pelComp.begin(), - result.components().begin(), + std::transform( other_comp.begin(), other_comp.end(), m_pelComp.begin(), result.components().begin(), []( auto& p1, auto& p2 ) { return p1 - p2; } ); return result; } @@ -134,10 +120,7 @@ CalypPixel CalypPixel::operator*( const double op ) const { CalypPixel result{ m_colorSpace }; auto& comp = result.components(); - std::transform( comp.begin(), - comp.end(), - comp.begin(), - [&op]( auto& p1 ) { return p1 * op; } ); + std::transform( comp.begin(), comp.end(), comp.begin(), [&op]( auto& p1 ) { return p1 * op; } ); return result; } @@ -149,16 +132,16 @@ auto CalypPixel::operator==( const CalypPixel& other ) const -> bool std::ostream& operator<<( std::ostream& os, const CalypPixel& p ) { -#ifdef CLP_DEBUG - if( p.colorSpace() == CLP_COLOR_RGB || p.colorSpace() == CLP_COLOR_YUV ) - { - os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ")"; - } - else - { - os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ", " << p[3] << ")"; - } -#endif + // #ifdef CLP_DEBUG + // if( p.colorSpace() == CLP_COLOR_RGB || p.colorSpace() == CLP_COLOR_YUV ) + // { + // os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ")"; + // } + // else + // { + // os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ", " << p[3] << ")"; + // } + // #endif return os; } diff --git a/lib/CalypStream.cpp b/lib/CalypStream.cpp index 0e7353c..1e6d6da 100644 --- a/lib/CalypStream.cpp +++ b/lib/CalypStream.cpp @@ -113,7 +113,8 @@ struct CalypStreamFrameBuffer : std::enable_shared_from_this> framePool; std::size_t bufferIdx{ 0 }; - CalypStreamFrameBuffer( std::size_t size, unsigned int width, unsigned int height, ClpPixelFormats pelFormat, unsigned int bitsPixel, bool hasNegative ) + CalypStreamFrameBuffer( std::size_t size, unsigned int width, unsigned int height, ClpPixelFormats pelFormat, + unsigned int bitsPixel, bool hasNegative ) { framePool.reserve( size ); for( std::size_t i = 0; i < size; i++ ) @@ -136,10 +137,8 @@ struct CalypStreamFrameBuffer : std::enable_shared_from_this( framePool[0]->getWidth(), - framePool[0]->getHeight(), - framePool[0]->getPelFormat(), - framePool[0]->getBitsPel(), + framePool.push_back( std::make_unique( framePool[0]->getWidth(), framePool[0]->getHeight(), + framePool[0]->getPelFormat(), framePool[0]->getBitsPel(), framePool[0]->getHasNegativeValues() ) ); } bufferIdx += newSize - oldSize; @@ -191,13 +190,11 @@ public: iCurrFrameNum = -1; } - ~CalypStreamPrivate() - { - close(); - } + ~CalypStreamPrivate() { close(); } - bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, unsigned int bitsPel, int endianness, bool hasNegative, - unsigned int frame_rate, bool forceRaw, CalypStream::Type type ) + bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, bool hasNegative, unsigned int frame_rate, bool forceRaw, + CalypStream::Type type ) { if( isInit ) { @@ -256,12 +253,9 @@ public: std::size_t bufferSize = isInput ? 6 : 1; try { - frameBuffer = std::make_shared( bufferSize, - handler->m_uiWidth, - handler->m_uiHeight, - handler->m_iPixelFormat, - handler->m_uiBitsPerPixel, - hasNegative ); + frameBuffer = + std::make_shared( bufferSize, handler->m_uiWidth, handler->m_uiHeight, + handler->m_iPixelFormat, handler->m_uiBitsPerPixel, hasNegative ); } catch( CalypFailure& e ) { @@ -339,7 +333,8 @@ public: { const std::lock_guard lock( stream_mutex ); - if( !isInit || streamType != CalypStream::Type::Input || handler->m_uiCurrFrameFileIdx >= handler->m_uiTotalNumberFrames ) + if( !isInit || streamType != CalypStream::Type::Input || + handler->m_uiCurrFrameFileIdx >= handler->m_uiTotalNumberFrames ) return false; if( bLoadAll ) @@ -376,10 +371,7 @@ std::vector CalypStreamFormat::getExts() return arrayExt; } -CalypStream::CalypStream() - : d{ std::make_unique() } -{ -} +CalypStream::CalypStream() : d{ std::make_unique() } {} CalypStream::~CalypStream() = default; @@ -392,8 +384,9 @@ std::string CalypStream::getCodecName() const return !d->handler ? "" : d->handler->getCodecName(); } -bool CalypStream::open( std::string filename, std::string resolution, std::string input_format_name, unsigned int bitsPel, int endianness, bool hasNegative, - unsigned int frame_rate, CalypStream::Type type ) +bool CalypStream::open( std::string filename, std::string resolution, std::string input_format_name, + unsigned int bitsPel, int endianness, bool hasNegative, unsigned int frame_rate, + CalypStream::Type type ) { unsigned int width = 0; unsigned int height = 0; @@ -412,25 +405,31 @@ bool CalypStream::open( std::string filename, std::string resolution, std::strin { return false; } - return d->open( std::move( filename ), width, height, *input_format, bitsPel, endianness, hasNegative, frame_rate, false, type ); + return d->open( std::move( filename ), width, height, *input_format, bitsPel, endianness, hasNegative, frame_rate, + false, type ); } -bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, unsigned int bitsPel, int endianness, - unsigned int frame_rate, CalypStream::Type type ) +bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, unsigned int frame_rate, CalypStream::Type type ) { - return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, false, frame_rate, false, type ); + return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, false, frame_rate, false, + type ); } -bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, unsigned int bitsPel, int endianness, bool hasNegative, - unsigned int frame_rate, CalypStream::Type type ) +bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, bool hasNegative, unsigned int frame_rate, + CalypStream::Type type ) { - return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, hasNegative, frame_rate, false, type ); + return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, hasNegative, frame_rate, + false, type ); } -bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, unsigned int bitsPel, int endianness, - unsigned int frame_rate, bool forceRaw, CalypStream::Type type ) +bool CalypStream::open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, unsigned int frame_rate, bool forceRaw, + CalypStream::Type type ) { - return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, false, frame_rate, forceRaw, type ); + return d->open( std::move( filename ), width, height, input_format, bitsPel, endianness, false, frame_rate, forceRaw, + type ); } bool CalypStream::supportsFormatConfiguration() @@ -454,8 +453,9 @@ bool CalypStream::reload() d->handler->calculateFrameNumber(); d->handler->configureBuffer( *refFrame ); - if( d->handler->m_uiWidth <= 0 || d->handler->m_uiHeight <= 0 || d->handler->m_iPixelFormat == ClpPixelFormats::Invalid || - d->handler->m_uiBitsPerPixel == 0 || d->handler->m_uiTotalNumberFrames == 0 ) + if( d->handler->m_uiWidth <= 0 || d->handler->m_uiHeight <= 0 || + d->handler->m_iPixelFormat == ClpPixelFormats::Invalid || d->handler->m_uiBitsPerPixel == 0 || + d->handler->m_uiTotalNumberFrames == 0 ) { return false; } @@ -509,8 +509,8 @@ long CalypStream::getCurrFrameNum() const return d->iCurrFrameNum; } -void CalypStream::getFormat( unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPel, int& rEndianness, - unsigned int& rFrameRate ) const +void CalypStream::getFormat( unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, + unsigned int& rBitsPerPel, int& rEndianness, unsigned int& rFrameRate ) const { if( d->isInit ) { @@ -570,7 +570,14 @@ void CalypStream::loadAll() d->iCurrFrameNum = 0; } -std::unique_ptr CalypStream::getCurrFrame( std::unique_ptr buffer ) +auto CalypStream::getCurrFrameAsset() -> std::shared_ptr +{ + if( d->bLoadAll ) + return d->frameFifo[d->iCurrFrameNum]; + return d->frameFifo.front(); +} + +auto CalypStream::getCurrFrame( std::unique_ptr buffer ) const -> std::unique_ptr { if( buffer == nullptr ) buffer = std::make_unique( *d->frameFifo.front() ); @@ -579,13 +586,6 @@ std::unique_ptr CalypStream::getCurrFrame( std::unique_ptr std::shared_ptr -{ - if( d->bLoadAll ) - return d->frameFifo[d->iCurrFrameNum]; - return d->frameFifo.front(); -} - auto CalypStream::getCurrFrame() -> CalypFrame* { if( d->bLoadAll ) diff --git a/lib/CalypStream.h b/lib/CalypStream.h index a78bea7..9201734 100644 --- a/lib/CalypStream.h +++ b/lib/CalypStream.h @@ -88,34 +88,14 @@ public: std::string getFormatName() const; std::string getCodecName() const; - bool open( std::string filename, - std::string resolution, - std::string input_format, - unsigned int bitsPel, - int endianness, - bool hasNegative, - unsigned int frame_rate, - Type type ); - bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, unsigned int bitsPel, int endianness, - unsigned int frame_rate, CalypStream::Type type ); - bool open( std::string filename, - unsigned int width, - unsigned int height, - ClpPixelFormats input_format, - unsigned int bitsPel, - int endianness, - bool hasNegative, - unsigned int frame_rate, - Type type ); - bool open( std::string filename, - unsigned int width, - unsigned int height, - ClpPixelFormats input_format, - unsigned int bitsPel, - int endianness, - unsigned int frame_rate, - bool forceRaw, - Type type ); + bool open( std::string filename, std::string resolution, std::string input_format, unsigned int bitsPel, + int endianness, bool hasNegative, unsigned int frame_rate, Type type ); + bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, unsigned int frame_rate, CalypStream::Type type ); + bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, bool hasNegative, unsigned int frame_rate, Type type ); + bool open( std::string filename, unsigned int width, unsigned int height, ClpPixelFormats input_format, + unsigned int bitsPel, int endianness, unsigned int frame_rate, bool forceRaw, Type type ); bool supportsFormatConfiguration(); bool reload(); @@ -129,15 +109,15 @@ public: int getEndianess() const; long getCurrFrameNum() const; double getFrameRate() const; - void getFormat( unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPel, int& rEndianness, - unsigned int& rFrameRate ) const; + void getFormat( unsigned int& rWidth, unsigned int& rHeight, ClpPixelFormats& rInputFormat, unsigned int& rBitsPerPel, + int& rEndianness, unsigned int& rFrameRate ) const; auto hasNextFrame() -> bool; auto hasWritingSlot() -> bool; void loadAll(); - std::unique_ptr getCurrFrame( std::unique_ptr buffer ); auto getCurrFrameAsset() -> std::shared_ptr; + auto getCurrFrame( std::unique_ptr buffer ) const -> std::unique_ptr; auto getCurrFrame() -> CalypFrame*; bool isEof(); bool setNextFrame(); diff --git a/lib/StreamHandlerRaw.cpp b/lib/StreamHandlerRaw.cpp index a9e141c..9eeb092 100644 --- a/lib/StreamHandlerRaw.cpp +++ b/lib/StreamHandlerRaw.cpp @@ -46,8 +46,7 @@ std::vector StreamHandlerRaw::supportedWriteFormats() END_REGIST_CALYP_SUPPORTED_FMT; } -StreamHandlerRaw::StreamHandlerRaw() - : CalypStreamHandlerIf{ true } +StreamHandlerRaw::StreamHandlerRaw() : CalypStreamHandlerIf{ true } { m_pchHandlerName = "RawVideo"; } @@ -55,9 +54,9 @@ StreamHandlerRaw::StreamHandlerRaw() bool StreamHandlerRaw::openHandler( std::string strFilename, bool bInput ) { m_bIsInput = bInput; - m_pFile = NULL; + m_pFile = nullptr; m_pFile = fopen( strFilename.c_str(), bInput ? "rb" : "wb" ); - if( m_pFile == NULL ) + if( m_pFile == nullptr ) { return false; } @@ -73,6 +72,7 @@ void StreamHandlerRaw::closeHandler() { if( m_pFile ) fclose( m_pFile ); + m_pFile = nullptr; } bool StreamHandlerRaw::configureBuffer( const CalypFrame& pcFrame ) @@ -107,7 +107,8 @@ bool StreamHandlerRaw::read( CalypFrame& pcFrame ) { if( !m_pFile || m_pStreamBuffer.empty() || m_uiNBytesPerFrame == 0 ) return false; - unsigned long long int processed_bytes = fread( m_pStreamBuffer.data(), sizeof( ClpByte ), m_uiNBytesPerFrame, m_pFile ); + unsigned long long int processed_bytes = + fread( m_pStreamBuffer.data(), sizeof( ClpByte ), m_uiNBytesPerFrame, m_pFile ); if( processed_bytes != m_uiNBytesPerFrame ) return false; m_uiCurrFrameFileIdx++; @@ -118,7 +119,8 @@ bool StreamHandlerRaw::read( CalypFrame& pcFrame ) bool StreamHandlerRaw::write( const CalypFrame& pcFrame ) { pcFrame.frameToBuffer( m_pStreamBuffer, m_iEndianness ); - unsigned long long int processed_bytes = fwrite( m_pStreamBuffer.data(), sizeof( ClpByte ), m_uiNBytesPerFrame, m_pFile ); + unsigned long long int processed_bytes = + fwrite( m_pStreamBuffer.data(), sizeof( ClpByte ), m_uiNBytesPerFrame, m_pFile ); if( processed_bytes != m_uiNBytesPerFrame ) return false; return true;