diff --git a/.gitignore b/.gitignore index d175192..154a643 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,4 @@ doc/ # CLang compile_commands.json +build_release/* \ No newline at end of file diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1fcfb28..6efa880 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -43,6 +43,7 @@ SET(Calyp_App_SRCS MdiSubWindow.cpp SubWindowAbstract.cpp # Module Video + ResourceHandle.cpp VideoHandle.cpp VideoSubWindow.cpp ViewArea.cpp diff --git a/app/MainWindow.cpp b/app/MainWindow.cpp index 7c4935a..b0d604b 100644 --- a/app/MainWindow.cpp +++ b/app/MainWindow.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "AboutDialog.h" #include "ModulesHandle.h" @@ -58,6 +59,8 @@ MainWindow::MainWindow() m_pDBusAdaptor = new DBusAppAdaptor( this ); #endif + m_appResourceHandle = std::make_unique(); + m_pcWindowHandle = new SubWindowHandle( this ); m_appModuleVideo = new VideoHandle( this, m_pcWindowHandle ); @@ -196,6 +199,8 @@ void MainWindow::loadFile( QString fileName, CalypFileInfo* pStreamInfo ) return; } videoSubWindow = new VideoSubWindow( VideoSubWindow::VIDEO_STREAM_SUBWINDOW ); // createSubWindow(); + videoSubWindow->setResourceManaget( m_appResourceHandle.get() ); + if( !pStreamInfo ) { int idx = findCalypStreamInfo( m_aRecentFileStreamInfo, fileName ); diff --git a/app/MainWindow.h b/app/MainWindow.h index b4cb5e4..fc6bfaf 100644 --- a/app/MainWindow.h +++ b/app/MainWindow.h @@ -36,16 +36,17 @@ #ifndef __MAINWINDOW_H__ #define __MAINWINDOW_H__ +#include +#include +#include + #include "CommonDefs.h" #include "VideoSubWindow.h" #include "config.h" #ifdef USE_QTDBUS #include "DBusAppAdaptor.h" #endif - -#include -#include -#include +#include "ResourceHandle.h" class QCloseEvent; class QDragEnterEvent; @@ -158,6 +159,7 @@ private: * Quality * Modules */ + std::unique_ptr m_appResourceHandle; VideoHandle* m_appModuleVideo; QualityHandle* m_appModuleQuality; ModulesHandle* m_appModuleExtensions; diff --git a/app/ResourceHandle.cpp b/app/ResourceHandle.cpp new file mode 100644 index 0000000..0779e68 --- /dev/null +++ b/app/ResourceHandle.cpp @@ -0,0 +1,130 @@ +/* This file is a part of Calyp project + * Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com) + * Luis Lucas (luisfrlucas@gmail.com) + * Joao Santos (joaompssantos@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 ResourceHandle.cpp + * \brief Handle resources + */ + +#include "ResourceHandle.h" + +#include +#include +#include +#include +#include +#include +#include + +ResourceWorker::ResourceWorker( std::shared_ptr stream ) +{ + m_pcStream = stream; +} + +void ResourceWorker::stop() +{ + m_bStop = true; + wait(); +} + +void ResourceWorker::run() +{ + while( !m_bStop ) + { + m_pcStream->readNextFrameFillRGBBuffer(); + while( !m_bStop && !m_pcStream->hasWritingSlot() ) + ; // Keep + } +} + +ResourceHandle::ResourceHandle() +{ +} + +auto ResourceHandle::addResource() -> CalypStream* +{ + auto newStreamResource = std::make_shared(); + auto newStreamResourceWorker = std::make_unique( newStreamResource ); + CalypStream* ptr = newStreamResource.get(); + + m_apcStreamResourcesList.push_back( newStreamResource ); + m_apcStreamResourcesWorkersList.push_back( std::move( newStreamResourceWorker ) ); + return ptr; +} + +auto ResourceHandle::getResource( CalypStream* ptr ) -> CalypStream* +{ + if( ptr != nullptr ) + { + for( auto& resource_ptr : m_apcStreamResourcesList ) + { + if( resource_ptr.get() == ptr ) + return resource_ptr.get(); + } + } + return addResource(); +} + +void ResourceHandle::removeResource( CalypStream* ptr ) +{ + std::optional posToRemove; + for( std::size_t i = 0; i < m_apcStreamResourcesList.size(); i++ ) + { + if( m_apcStreamResourcesList[i].get() == ptr ) + { + posToRemove = i; + break; + } + } + if( !posToRemove.has_value() ) + { + assert( false ); + return; + } + + // Remove worker first + m_apcStreamResourcesWorkersList[*posToRemove]->stop(); + m_apcStreamResourcesWorkersList.erase( m_apcStreamResourcesWorkersList.begin() + *posToRemove ); + + // Then the underlying stream + m_apcStreamResourcesList.erase( m_apcStreamResourcesList.begin() + *posToRemove ); +} + +void ResourceHandle::startResourceWorker( CalypStream* ptr ) +{ + std::optional position; + for( std::size_t i = 0; i < m_apcStreamResourcesList.size(); i++ ) + { + if( m_apcStreamResourcesList[i].get() == ptr ) + { + position = i; + break; + } + } + if( !position.has_value() ) + { + assert( false ); + return; + } + m_apcStreamResourcesWorkersList[*position]->setObjectName( + "RW-" + + QFileInfo( QString::fromStdString( m_apcStreamResourcesList[*position]->getFileName() ) ).completeBaseName() ); + m_apcStreamResourcesWorkersList[*position]->start(); +} \ No newline at end of file diff --git a/app/ResourceHandle.h b/app/ResourceHandle.h new file mode 100644 index 0000000..6ba7f46 --- /dev/null +++ b/app/ResourceHandle.h @@ -0,0 +1,64 @@ +/* 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 ResourceHandle.h + * \brief Handle multiple sub-windows + */ + +#ifndef __RESOURCEHANDLE_H__ +#define __RESOURCEHANDLE_H__ + +#include +#include + +#include "CommonDefs.h" +#include "lib/CalypStream.h" + +class ResourceWorker : public QThread +{ +private: + std::shared_ptr m_pcStream; + bool m_bStop{ false }; + +public: + ResourceWorker( std::shared_ptr stream ); + void stop(); + void run(); +}; + +class ResourceHandle +{ +public: + ResourceHandle(); + ~ResourceHandle() = default; + + auto getResource( CalypStream* ptr ) -> CalypStream*; + void removeResource( CalypStream* ptr ); + void startResourceWorker( CalypStream* ptr ); + +private: + auto addResource() -> CalypStream*; + +private: + std::vector> m_apcStreamResourcesList; + std::vector> m_apcStreamResourcesWorkersList; +}; + +#endif // __RESOURCEHANDLE_H__ diff --git a/app/VideoSubWindow.cpp b/app/VideoSubWindow.cpp index cb8c743..813ece1 100644 --- a/app/VideoSubWindow.cpp +++ b/app/VideoSubWindow.cpp @@ -32,9 +32,11 @@ #include "ConfigureFormatDialog.h" #include "ModulesHandle.h" #include "QtConcurrent/qtconcurrentrun.h" +#include "ResourceHandle.h" #include "SubWindowAbstract.h" //#define QT_NO_CONCURRENT +//#define USE_CALYPSTREAM_RETRIEVE /** * \brief Functions to control data stream from stream information @@ -146,6 +148,7 @@ protected: VideoSubWindow::VideoSubWindow( enum VideoSubWindowCategories category, QWidget* parent ) : SubWindowAbstract( parent, SubWindowAbstract::VIDEO_SUBWINDOW | category ) + , m_pcResourceManager( nullptr ) , m_bWindowBusy( false ) , m_pCurrStream( NULL ) , m_pcCurrFrame( NULL ) @@ -196,12 +199,10 @@ VideoSubWindow::VideoSubWindow( enum VideoSubWindowCategories category, QWidget* VideoSubWindow::~VideoSubWindow() { - m_pcCurrFrame = NULL; disableModule(); - delete m_cViewArea; + m_pcResourceManager->removeResource( m_pCurrStream ); + //delete m_cViewArea; delete m_pcUpdateTimer; - if( m_pCurrStream ) - delete m_pCurrStream; } /** @@ -319,6 +320,8 @@ void VideoSubWindow::refreshSubWindow() bool VideoSubWindow::loadFile( QString cFilename, bool bForceDialog ) { + assert( m_pcResourceManager != nullptr ); + ConfigureFormatDialog formatDialog( this ); unsigned int Width = 0, Height = 0, BitsPel = 8, FrameRate = 30; int Endianness = CLP_LITTLE_ENDIAN; @@ -327,11 +330,9 @@ bool VideoSubWindow::loadFile( QString cFilename, bool bForceDialog ) if( m_pCurrStream ) m_pCurrStream->getFormat( Width, Height, InputFormat, BitsPel, Endianness, FrameRate ); + else + m_pCurrStream = m_pcResourceManager->getResource( nullptr ); - if( !m_pCurrStream ) - { - m_pCurrStream = new CalypStream; - } bool bConfig = true; if( !bForceDialog ) { @@ -383,6 +384,10 @@ bool VideoSubWindow::loadFile( QString cFilename, bool bForceDialog ) var.setValue( BitsPel ); appSettings.setValue( "VideoSubWindow/LastBitsPerPixel", var ); +#ifdef USE_CALYPSTREAM_RETRIEVE + m_pcResourceManager->startResourceWorker( m_pCurrStream ); +#endif + QApplication::restoreOverrideCursor(); refreshFrame(); @@ -397,10 +402,9 @@ bool VideoSubWindow::loadFile( QString cFilename, bool bForceDialog ) bool VideoSubWindow::loadFile( CalypFileInfo* streamInfo ) { - if( !m_pCurrStream ) - { - m_pCurrStream = new CalypStream; - } + assert( m_pcResourceManager != nullptr ); + + m_pCurrStream = m_pcResourceManager->getResource( m_pCurrStream ); if( !m_pCurrStream->open( streamInfo->m_cFilename.toStdString(), streamInfo->m_uiWidth, streamInfo->m_uiHeight, streamInfo->m_iPelFormat, streamInfo->m_uiBitsPelPixel, streamInfo->m_iEndianness, @@ -411,6 +415,10 @@ bool VideoSubWindow::loadFile( CalypFileInfo* streamInfo ) m_sStreamInfo = *streamInfo; +#ifdef USE_CALYPSTREAM_RETRIEVE + m_pcResourceManager->startResourceWorker( m_pCurrStream ); +#endif + QApplication::restoreOverrideCursor(); refreshFrame(); @@ -723,11 +731,15 @@ void VideoSubWindow::setCurrFrame( CalypFrame* pcCurrFrame ) void VideoSubWindow::refreshFrameOperation() { bool bSetFrame = false; - if( m_pCurrStream ) + if( m_pcCurrStreamFrame != nullptr ) + { + m_pcCurrFrame = m_pcCurrStreamFrame.get(); + } + else if( m_pCurrStream ) { m_pcCurrFrame = m_pCurrStream->getCurrFrame(); - bSetFrame = m_pcCurrFrame ? true : false; } + bSetFrame = m_pcCurrFrame ? true : false; if( m_pcCurrentDisplayModule ) { m_bWindowBusy = true; @@ -761,6 +773,13 @@ void VideoSubWindow::refreshFrame( bool bThreaded ) bool VideoSubWindow::goToNextFrame( bool bThreaded ) { +#ifdef USE_CALYPSTREAM_RETRIEVE + m_pcCurrStreamFrame = m_pCurrStream->retrieveNextFrame(); + if( m_pcCurrStreamFrame == nullptr ) + return true; + refreshFrame(); + return false; +#else #ifndef QT_NO_CONCURRENT m_cRefreshResult.waitForFinished(); m_cReadResult.waitForFinished(); @@ -783,6 +802,7 @@ bool VideoSubWindow::goToNextFrame( bool bThreaded ) } } return bEndOfSeq; +#endif } bool VideoSubWindow::save( QString filename ) @@ -867,6 +887,7 @@ void VideoSubWindow::pause() void VideoSubWindow::seekAbsoluteEvent( unsigned int new_frame_num ) { + m_pcCurrStreamFrame = nullptr; if( m_pCurrStream ) if( m_pCurrStream->seekInput( new_frame_num ) ) refreshFrame(); @@ -883,7 +904,15 @@ void VideoSubWindow::seekRelativeEvent( bool bIsFoward ) } else { + m_pcCurrStreamFrame = nullptr; bRefresh = m_pCurrStream->seekInputRelative( bIsFoward ); +#ifdef USE_CALYPSTREAM_RETRIEVE + if( bRefresh ) + { + m_pcCurrStreamFrame = m_pCurrStream->retrieveNextFrame(); + bRefresh &= m_pcCurrStreamFrame != nullptr; + } +#endif } } if( bRefresh ) diff --git a/app/VideoSubWindow.h b/app/VideoSubWindow.h index b9e8df7..75b29b7 100644 --- a/app/VideoSubWindow.h +++ b/app/VideoSubWindow.h @@ -41,6 +41,7 @@ class QScrollArea; class VideoInformation; class VideoSubWindow; +class ResourceHandle; class CalypAppModuleIf; typedef struct @@ -65,6 +66,8 @@ class VideoSubWindow : public SubWindowAbstract Q_OBJECT private: + ResourceHandle* m_pcResourceManager; + bool m_bWindowBusy; QScrollArea* m_pcScrollArea; @@ -80,6 +83,7 @@ private: QString m_cStreamInformation; CalypFileInfo m_sStreamInfo; CalypStream* m_pCurrStream; + std::shared_ptr m_pcCurrStreamFrame; CalypFrame* m_pcCurrFrame; QRect m_cSelectedArea; @@ -111,6 +115,8 @@ public: VideoSubWindow( enum VideoSubWindowCategories category, QWidget* parent = 0 ); ~VideoSubWindow(); + void setResourceManaget( ResourceHandle* resourceManager ) { m_pcResourceManager = resourceManager; } + void updateVideoWindowInfo(); bool loadFile( QString cFilename, bool bForceDialog = false ); diff --git a/app/ViewArea.cpp b/app/ViewArea.cpp index 043f114..ff70629 100644 --- a/app/ViewArea.cpp +++ b/app/ViewArea.cpp @@ -73,7 +73,7 @@ void ViewArea::setImage( CalypFrame* pcFrame ) { m_pcCurrFrame = pcFrame; m_uiPixelHalfScale = 1 << ( m_pcCurrFrame->getBitsPel() - 1 ); - m_pcCurrFrame->fillRGBBuffer(); + pcFrame->fillRGBBuffer(); QImage qimg = QImage( m_pcCurrFrame->getRGBBuffer(), m_pcCurrFrame->getWidth(), m_pcCurrFrame->getHeight(), QImage::Format_ARGB32 ); setImage( QPixmap::fromImage( qimg ) ); @@ -1091,6 +1091,6 @@ void ViewArea::updateMask( const QRect& rect ) break; } default: /* Do Nothing */ - ; + ; } } diff --git a/app/ViewArea.h b/app/ViewArea.h index 5b370aa..757cb0a 100644 --- a/app/ViewArea.h +++ b/app/ViewArea.h @@ -150,7 +150,7 @@ private: QPoint viewToWindow( const QPoint& pt ) const; QRect viewToWindow( const QRect& rc ) const; - CalypFrame* m_pcCurrFrame; + const CalypFrame* m_pcCurrFrame; ClpPel m_uiPixelHalfScale; diff --git a/lib/CalypDefs.h b/lib/CalypDefs.h index 971e05b..d5d66d4 100644 --- a/lib/CalypDefs.h +++ b/lib/CalypDefs.h @@ -26,6 +26,7 @@ #ifndef __CALYPDEFS_H__ #define __CALYPDEFS_H__ +#include #include #include #include diff --git a/lib/CalypStream.cpp b/lib/CalypStream.cpp index a2ff4e4..74c5a07 100644 --- a/lib/CalypStream.cpp +++ b/lib/CalypStream.cpp @@ -25,6 +25,9 @@ // Self #include "CalypStream.h" +#include +#include + #include "CalypFrame.h" #include "CalypStreamHandlerIf.h" #include "LibMemory.h" @@ -100,23 +103,29 @@ class CalypStreamBufferPrivate { private: std::vector m_apcFrameBuffer; - unsigned int m_uiIndex; + std::int64_t m_iSize; + std::int64_t m_iReadIndex; + std::int64_t m_iWriteIndex; public: - CalypStreamBufferPrivate( unsigned int size, unsigned int width, unsigned int height, int pelFormat, unsigned int bitsPixel, bool hasNegative ) + CalypStreamBufferPrivate( std::size_t size, unsigned int width, unsigned int height, int pelFormat, unsigned int bitsPixel, bool hasNegative ) { - for( unsigned int i = 0; i < size; i++ ) + m_apcFrameBuffer.reserve( size ); + for( std::size_t i = 0; i < size; i++ ) { m_apcFrameBuffer.push_back( CalypFrame{ width, height, pelFormat, bitsPixel, hasNegative } ); } - m_uiIndex = 0; + m_iSize = std::ssize( m_apcFrameBuffer ); + m_iReadIndex = -1; + m_iWriteIndex = 0; } ~CalypStreamBufferPrivate() = default; - void increase( unsigned int newSize ) + void increase( std::size_t newSize ) { - for( unsigned int i = m_apcFrameBuffer.size(); i < newSize; i++ ) + m_apcFrameBuffer.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(), @@ -124,30 +133,84 @@ public: m_apcFrameBuffer[0].getBitsPel(), m_apcFrameBuffer[0].getHasNegativeValues() } ); } + m_iSize = std::ssize( m_apcFrameBuffer ); + } + + void setIndex( std::int64_t i ) + { + m_iWriteIndex = m_iReadIndex = i; + m_iWriteIndex = nextIndex( m_iWriteIndex ); + } + void reset() + { + m_iReadIndex = -1; + m_iWriteIndex = 0; + } + void startRead() + { + assert( m_iWriteIndex >= 0 ); + m_iReadIndex = 0; } - unsigned int size() { return m_apcFrameBuffer.size(); } - void setIndex( unsigned int i ) { m_uiIndex = i; } CalypFrame& frame( int i ) { return m_apcFrameBuffer.at( i ); } - CalypFrame& current() { return m_apcFrameBuffer.at( m_uiIndex ); } - CalypFrame& next() { return m_apcFrameBuffer.at( nextIndex() ); } - void setNextFrame() { m_uiIndex = nextIndex(); } + CalypFrame& currentRead() + { + assert( m_iReadIndex >= 0 && m_iReadIndex < m_iSize ); + return m_apcFrameBuffer.at( m_iReadIndex ); + } + + const CalypFrame& ref() { return m_apcFrameBuffer.at( m_iWriteIndex ); } + + CalypFrame& readOneFrame() + { + assert( m_iReadIndex >= 0 && m_iReadIndex < m_iSize ); + CalypFrame& frameToRead = m_apcFrameBuffer.at( m_iReadIndex ); + m_iReadIndex = nextIndex( m_iReadIndex ); + return frameToRead; + } + CalypFrame& writeOneFrame() + { + assert( m_iReadIndex != m_iWriteIndex ); + CalypFrame& frameToWrite = m_apcFrameBuffer.at( m_iWriteIndex ); + m_iWriteIndex = nextIndex( m_iWriteIndex ); + return frameToWrite; + } + + bool hasWritingSlot() + { + if( m_iWriteIndex != m_iReadIndex ) + 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() }; + m_iReadIndex = nextIndex( m_iReadIndex ); + return ptr; + } private: - inline int nextIndex() { return m_uiIndex + 1 >= m_apcFrameBuffer.size() ? 0 : m_uiIndex + 1; } - inline int prevIndex() { return m_uiIndex - 1 < 0 ? m_apcFrameBuffer.size() - 1 : m_uiIndex - 1; } + inline int nextIndex( std::int64_t curr ) { return curr + 1 >= m_iSize ? 0 : curr + 1; } }; class CalypStream::CalypStreamPrivate { public: + std::mutex mutex; + bool isInit; bool isInput; CalypStreamHandlerIf* handler; CreateStreamHandlerFn pfctCreateHandler; - CalypStreamBufferPrivate* frameBuffer; + std::unique_ptr frameBuffer; ClpString cFilename; long long int iCurrFrameNum; @@ -164,10 +227,12 @@ public: iCurrFrameNum = -1; cFilename = ""; } + ~CalypStreamPrivate() { close(); } + void close() { if( !isInit ) @@ -178,12 +243,26 @@ public: handler->closeHandler(); handler->Delete(); } - if( frameBuffer ) - delete frameBuffer; bLoadAll = false; isInit = false; } + + bool readFrame( CalypFrame& frame ) + { + if( !isInit || !isInput || handler->m_uiCurrFrameFileIdx >= handler->m_uiTotalNumberFrames ) + return false; + + if( bLoadAll ) + return true; + + if( !handler->read( frame ) ) + { + throw CalypFailure( "CalypStream", "Cannot read frame from stream" ); + return false; + } + return true; + } }; std::vector CalypStreamFormat::getExts() @@ -332,10 +411,11 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei } // Keep past, current and future frames + std::size_t bufferSize = d->isInput ? 4 : 1; try { - d->frameBuffer = new CalypStreamBufferPrivate( d->isInput ? 3 : 1, d->handler->m_uiWidth, d->handler->m_uiHeight, - d->handler->m_iPixelFormat, d->handler->m_uiBitsPerPixel, hasNegative ); + d->frameBuffer = std::make_unique( bufferSize, d->handler->m_uiWidth, d->handler->m_uiHeight, + d->handler->m_iPixelFormat, d->handler->m_uiBitsPerPixel, hasNegative ); } catch( CalypFailure& e ) { @@ -344,7 +424,7 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - d->handler->m_uiNBytesPerFrame = d->frameBuffer->current().getBytesPerFrame(); + d->handler->m_uiNBytesPerFrame = d->frameBuffer->ref().getBytesPerFrame(); // Some handlers need to know how long is a frame to get frame number d->handler->calculateFrameNumber(); @@ -356,7 +436,7 @@ bool CalypStream::open( ClpString filename, unsigned int width, unsigned int hei return d->isInit; } - if( !d->handler->configureBuffer( d->frameBuffer->current() ) ) + if( !d->handler->configureBuffer( d->frameBuffer->ref() ) ) { close(); throw CalypFailure( "CalypStream", "Cannot allocated buffers" ); @@ -380,9 +460,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->current().getBytesPerFrame(); + d->handler->m_uiNBytesPerFrame = d->frameBuffer->ref().getBytesPerFrame(); d->handler->calculateFrameNumber(); - d->handler->configureBuffer( d->frameBuffer->current() ); + d->handler->configureBuffer( d->frameBuffer->ref() ); 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 ) @@ -467,6 +547,10 @@ void CalypStream::getFormat( unsigned int& rWidth, unsigned int& rHeight, int& r } } +/** + * @brief Read operations + */ + void CalypStream::loadAll() { if( d->bLoadAll || !d->isInput ) @@ -483,33 +567,89 @@ void CalypStream::loadAll() } seekInput( 0 ); - for( unsigned int i = 2; i < d->frameBuffer->size(); i++ ) + for( unsigned int i = 2; i < d->handler->m_uiTotalNumberFrames; i++ ) { - readFrame( d->frameBuffer->frame( i ) ); + d->readFrame( d->frameBuffer->frame( i ) ); } d->bLoadAll = true; d->iCurrFrameNum = 0; } -bool CalypStream::readFrame( CalypFrame& frame ) +CalypFrame* CalypStream::getCurrFrame( CalypFrame* pyuv_image ) { - if( !d->isInit || !d->isInput || d->handler->m_uiCurrFrameFileIdx >= d->handler->m_uiTotalNumberFrames ) - return false; - - if( d->bLoadAll ) - return true; - - if( !d->handler->read( frame ) ) - { - throw CalypFailure( "CalypStream", "Cannot read frame from stream" ); - return false; - } - return true; + 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(); +} + +auto CalypStream::getNextFrame() -> CalypFrame& +{ + CalypFrame& frameToTead = d->frameBuffer->readOneFrame(); + d->readFrame( d->frameBuffer->writeOneFrame() ); + return frameToTead; +} + +auto CalypStream::retrieveNextFrame() -> std::shared_ptr +{ + const std::lock_guard lock( d->mutex ); + + if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) + { + d->iCurrFrameNum++; + return d->frameBuffer->retrieveFrame(); + } + return nullptr; +} + +bool CalypStream::setNextFrame() +{ + bool bEndOfSeq = false; + + if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) + { + d->frameBuffer->readOneFrame(); + d->iCurrFrameNum++; + } + else + { + bEndOfSeq = true; + } + return bEndOfSeq; +} + +void CalypStream::readNextFrame() +{ + d->readFrame( d->frameBuffer->writeOneFrame() ); +} + +void CalypStream::readNextFrameFillRGBBuffer() +{ + const std::lock_guard lock( d->mutex ); + + CalypFrame& frameToWrite = d->frameBuffer->writeOneFrame(); + d->readFrame( frameToWrite ); + frameToWrite.fillRGBBuffer(); + return; +} + +auto CalypStream::hasWritingSlot() -> bool +{ + return d->frameBuffer->hasWritingSlot(); +} + +/** + * @brief Write operations + */ void CalypStream::writeFrame() { - writeFrame( d->frameBuffer->current() ); + writeFrame( *getCurrFrame() ); } void CalypStream::writeFrame( const CalypFrame& pcFrame ) @@ -523,7 +663,7 @@ void CalypStream::writeFrame( const CalypFrame& pcFrame ) bool CalypStream::saveFrame( const ClpString& filename ) { - return saveFrame( filename, d->frameBuffer->current() ); + return saveFrame( filename, *getCurrFrame() ); } bool CalypStream::saveFrame( const ClpString& filename, const CalypFrame& saveFrame ) @@ -539,53 +679,9 @@ bool CalypStream::saveFrame( const ClpString& filename, const CalypFrame& saveFr return true; } -bool CalypStream::setNextFrame() -{ - bool bEndOfSeq = false; - - if( d->iCurrFrameNum + 1 < (long)( d->handler->m_uiTotalNumberFrames ) ) - { - d->frameBuffer->setNextFrame(); - d->iCurrFrameNum++; - } - else - { - bEndOfSeq = true; - } - return bEndOfSeq; -} - -void CalypStream::readNextFrame() -{ - readFrame( d->frameBuffer->next() ); -} - -void CalypStream::readNextFrameFillRGBBuffer() -{ - readNextFrame(); - d->frameBuffer->next().fillRGBBuffer(); - return; -} - -CalypFrame* CalypStream::getCurrFrame( CalypFrame* pyuv_image ) -{ - if( pyuv_image == NULL ) - pyuv_image = new CalypFrame( d->frameBuffer->current() ); - else - pyuv_image->copyFrom( d->frameBuffer->current() ); - return pyuv_image; -} - -CalypFrame* CalypStream::getCurrFrame() -{ - return &d->frameBuffer->current(); -} - -const CalypFrame& CalypStream::getCurrFrameConst() const -{ - return d->frameBuffer->current(); -} - +/** + * @brief Seek operations + */ bool CalypStream::seekInputRelative( bool bIsFoward ) { if( !d->isInit || !d->isInput ) @@ -595,7 +691,7 @@ bool CalypStream::seekInputRelative( bool bIsFoward ) if( bIsFoward ) { bRet = !setNextFrame(); - readFrame( d->frameBuffer->next() ); + d->readFrame( d->frameBuffer->writeOneFrame() ); } else { @@ -623,10 +719,10 @@ bool CalypStream::seekInput( unsigned long new_frame_num ) throw CalypFailure( "CalypStream", "Cannot seek file into desired position" ); } - d->frameBuffer->setIndex( 0 ); - readFrame( d->frameBuffer->current() ); + d->frameBuffer->reset(); + d->readFrame( d->frameBuffer->writeOneFrame() ); if( d->handler->m_uiTotalNumberFrames > 1 ) - readFrame( d->frameBuffer->next() ); - + d->readFrame( d->frameBuffer->writeOneFrame() ); + d->frameBuffer->startRead(); return true; } diff --git a/lib/CalypStream.h b/lib/CalypStream.h index dd15a32..1ecb499 100644 --- a/lib/CalypStream.h +++ b/lib/CalypStream.h @@ -26,11 +26,12 @@ #ifndef __CALYPSTREAM_H__ #define __CALYPSTREAM_H__ +#include #include #include "CalypDefs.h" +#include "CalypFrame.h" -class CalypFrame; class CalypStreamHandlerIf; typedef CalypStreamHandlerIf* ( *CreateStreamHandlerFn )( void ); @@ -96,27 +97,29 @@ public: void loadAll(); + CalypFrame* getCurrFrame( CalypFrame* ); + CalypFrame* getCurrFrame(); + + // continuous read using smart ptrs + auto retrieveNextFrame() -> std::shared_ptr; + + // continuous read control + auto getNextFrame() -> CalypFrame&; + bool setNextFrame(); + void readNextFrame(); + void readNextFrameFillRGBBuffer(); + + auto hasWritingSlot() -> bool; + void writeFrame(); void writeFrame( const CalypFrame& pcFrame ); bool saveFrame( const ClpString& filename ); static bool saveFrame( const ClpString& filename, const CalypFrame& saveFrame ); - CalypFrame* getCurrFrame( CalypFrame* ); - - // continuous read control - bool setNextFrame(); - void readNextFrame(); - void readNextFrameFillRGBBuffer(); - CalypFrame* getCurrFrame(); - const CalypFrame& getCurrFrameConst() const; - bool seekInputRelative( bool bIsFoward ); bool seekInput( unsigned long new_frame_num ); -private: - bool readFrame( CalypFrame& frame ); - private: class CalypStreamPrivate; std::unique_ptr d; diff --git a/tools/CalypTools.cpp b/tools/CalypTools.cpp index 2408f5f..c8d3021 100644 --- a/tools/CalypTools.cpp +++ b/tools/CalypTools.cpp @@ -246,7 +246,7 @@ int CalypTools::Open( int argc, char* argv[] ) if( Opts().hasOpt( "output" ) ) m_pcOutputFileNames.push_back( m_strOutput ); - CalypFrame* pcInputFrame = m_apcInputStreams[0]->getCurrFrame(); + const CalypFrame* pcInputFrame = m_apcInputStreams[0]->getCurrFrame(); CalypStream* pcOutputStream = new CalypStream; try { @@ -479,7 +479,7 @@ int CalypTools::RateReductionOperation() if( ( frame % m_iRateReductionFactor ) == 0 ) { log( CLP_LOG_INFO, "Writing", frame ); - m_apcOutputStreams[0]->writeFrame( m_apcInputStreams[0]->getCurrFrameConst() ); + m_apcOutputStreams[0]->writeFrame( *m_apcInputStreams[0]->getCurrFrame() ); } abEOF = m_apcInputStreams[0]->setNextFrame(); if( !abEOF ) @@ -692,7 +692,6 @@ int CalypTools::ListStatistics() { log( CLP_LOG_RESULT, "\n\x1B[35mCalyp Statistics:\x1B[0m\n\n" ); - CalypFrame* currFrame; bool abEOF; unsigned min[MAX_NUMBER_CHANNELS], max[MAX_NUMBER_CHANNELS]; @@ -706,7 +705,7 @@ int CalypTools::ListStatistics() { log( CLP_LOG_RESULT, "\x1B[34m Frame: %d\x1B[0m\n", frame ); - currFrame = m_apcInputStreams[input]->getCurrFrame(); + auto currFrame = m_apcInputStreams[input]->getCurrFrame(); abEOF = m_apcInputStreams[input]->setNextFrame(); if( !abEOF ) {