Commit a573e87d authored by Hugo Beauzee-Luyssen's avatar Hugo Beauzee-Luyssen

Another step in clipworkflow refactoring

parent ff6f5745
......@@ -68,7 +68,6 @@ void WorkflowFileRenderer::run()
m_isRendering = true;
m_stopping = false;
m_mainWorkflow->setFullSpeedRender( true );
m_mainWorkflow->startRender();
m_mediaPlayer->play();
}
......
......@@ -207,7 +207,6 @@ void WorkflowRenderer::startPreview()
//FIXME:: check if this doesn't require Qt::QueuedConnection
connect( m_mediaPlayer, SIGNAL( stopped() ), this, SLOT( __videoStopped() ) );
m_mainWorkflow->setFullSpeedRender( false );
m_mainWorkflow->startRender();
m_isRendering = true;
m_paused = false;
......
......@@ -64,6 +64,7 @@ void* AudioClipWorkflow::getOutput( ClipWorkflow::GetMode mode )
if ( mode == ClipWorkflow::Get )
qCritical() << "A sound buffer should never be asked with 'Get' mode";
StackedBuffer<AudioSample*>* buff = new StackedBuffer<AudioSample*>( m_computedBuffers.pop(), &m_availableBuffers, true );
ClipWorkflow::getOutput( mode );
return buff;
}
......@@ -123,3 +124,13 @@ void AudioClipWorkflow::unlock( AudioClipWorkflow* cw, uint8_t* pcm_buffe
cw->commonUnlock();
}
uint32_t AudioClipWorkflow::getAvailableBuffers() const
{
return m_availableBuffers.count();
}
uint32_t AudioClipWorkflow::getComputedBuffers() const
{
return m_computedBuffers.count();
}
......@@ -43,6 +43,10 @@ class AudioClipWorkflow : public ClipWorkflow
void* getUnlockCallback();
virtual void* getOutput( ClipWorkflow::GetMode mode );
protected:
virtual uint32_t getAvailableBuffers() const;
virtual uint32_t getComputedBuffers() const;
private:
QReadWriteLock* m_computedBuffersLock;
Pool<AudioSample*> m_computedBuffers;
......
......@@ -60,15 +60,11 @@ void ClipWorkflow::checkStateChange()
m_state = m_requiredState;
// qDebug() << '[' << (void*)this << "] Applying required state change:" << m_state;
m_requiredState = ClipWorkflow::None;
checkSynchronisation( m_state );
}
}
void ClipWorkflow::initialize( bool preloading /*= false*/ )
void ClipWorkflow::initialize()
{
// qDebug() << "Setting state to initializing";
setState( Initializing );
// qDebug() << "State is Initializing.";
if ( m_clip->getParent()->getFileType() == Media::Image )
m_vlcMedia = new LibVLCpp::Media( "fake:///" + m_clip->getParent()->getFileInfo()->absoluteFilePath() );
else
......@@ -79,36 +75,18 @@ void ClipWorkflow::initialize( bool preloading /*= false*/ )
m_mediaPlayer = MemoryPool<LibVLCpp::MediaPlayer>::getInstance()->get();
m_mediaPlayer->setMedia( m_vlcMedia );
if ( preloading == true )
connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ), Qt::DirectConnection );
else
connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( loadingComplete() ), Qt::DirectConnection );
connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( loadingComplete() ), Qt::DirectConnection );
connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ), Qt::DirectConnection );
m_mediaPlayer->play();
}
void ClipWorkflow::pauseAfterPlaybackStarted()
{
adjustBegin();
disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) );
connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ), Qt::DirectConnection );
m_mediaPlayer->pause();
}
void ClipWorkflow::loadingComplete()
{
// qDebug() << "Loading complete, setting begin.";
adjustBegin();
disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( loadingComplete() ) );
setState( Ready );
// qDebug() << "State is Ready";
}
void ClipWorkflow::initializedMediaPlayer()
{
disconnect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ) );
setState( Ready );
QMutexLocker lock( m_initWaitCond->getMutex() );
setState( Rendering );
m_initWaitCond->wake();
}
void ClipWorkflow::adjustBegin()
......@@ -117,12 +95,6 @@ void ClipWorkflow::adjustBegin()
m_mediaPlayer->setTime( m_clip->getBegin() / m_clip->getParent()->getFps() * 1000 );
}
bool ClipWorkflow::isReady() const
{
QReadLocker lock( m_stateLock );
return m_state == ClipWorkflow::Ready;
}
bool ClipWorkflow::isEndReached() const
{
QReadLocker lock( m_stateLock );
......@@ -140,29 +112,6 @@ ClipWorkflow::State ClipWorkflow::getState() const
return m_state;
}
void ClipWorkflow::startRender( bool startInPausedMode )
{
{
QMutexLocker lock( m_initWaitCond->getMutex() );
if ( isReady() == false )
{
// qDebug() << "Waiting for clipworkflow to be ready";
m_initWaitCond->waitLocked();
}
}
// qDebug() << "ClipWorkflow is ready";
if ( startInPausedMode == false )
{
m_mediaPlayer->play();
// qDebug() << "Setting state: Rendering";
setState( Rendering );
}
else
{
setState( Paused );
}
}
void ClipWorkflow::clipEndReached()
{
setState( EndReached );
......@@ -205,35 +154,11 @@ bool ClipWorkflow::isRendering() const
return m_state == ClipWorkflow::Rendering;
}
bool ClipWorkflow::isSleeping() const
{
QReadLocker lock( m_stateLock );
return m_state == ClipWorkflow::Sleeping;
}
void ClipWorkflow::checkSynchronisation( State newState )
{
switch ( newState )
{
case Ready:
{
QMutexLocker lock( m_initWaitCond->getMutex() );
m_initWaitCond->wake();
break ;
}
default:
break ;
}
}
void ClipWorkflow::setState( State state )
{
{
QWriteLocker lock( m_stateLock );
QWriteLocker lock( m_stateLock );
// qDebug() << '[' << (void*)this << "] Setting state to" << state;
m_state = state;
}
checkSynchronisation( state );
m_state = state;
}
void ClipWorkflow::queryStateChange( State newState )
......@@ -247,25 +172,9 @@ QReadWriteLock* ClipWorkflow::getStateLock()
return m_stateLock;
}
void ClipWorkflow::pause()
{
connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ), Qt::DirectConnection );
setState( Pausing );
m_mediaPlayer->pause();
QMutexLocker lock( m_requiredStateLock );
m_requiredState = ClipWorkflow::None;
}
void ClipWorkflow::unpause()
{
queryStateChange( ClipWorkflow::Rendering );
connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( unpausedMediaPlayer() ), Qt::DirectConnection );
m_mediaPlayer->pause();
}
void ClipWorkflow::waitForCompleteInit()
{
if ( isReady() == false )
if ( isRendering() == false )
{
QMutexLocker lock( m_initWaitCond->getMutex() );
m_initWaitCond->waitLocked();
......@@ -277,35 +186,23 @@ LibVLCpp::MediaPlayer* ClipWorkflow::getMediaPlayer()
return m_mediaPlayer;
}
void ClipWorkflow::pausedMediaPlayer()
void* ClipWorkflow::getOutput( ClipWorkflow::GetMode )
{
disconnect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ) );
setState( Paused );
emit paused();
}
void ClipWorkflow::unpausedMediaPlayer()
{
disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( unpausedMediaPlayer() ) );
emit unpaused();
//If we have more empty buffers than computed ones, refill our stack.
if ( getComputedBuffers() > getAvailableBuffers() )
{
//Assume the media player was paused in this case...
//FIXME: this is probably a very bad idea...
m_mediaPlayer->pause();
}
//Keep the compiler happy, but we don't use this return value.
return NULL;
}
void ClipWorkflow::commonUnlock()
{
m_stateLock->lockForWrite();
if ( m_state == Rendering )
{
m_state = Sleeping;
m_stateLock->unlock();
m_stateLock->lockForWrite();
if ( m_state == Sleeping )
m_state = Rendering;
m_stateLock->unlock();
}
else
m_stateLock->unlock();
if ( getAvailableBuffers() == 0 )
m_mediaPlayer->pause();
checkStateChange();
}
......
......@@ -41,15 +41,15 @@ class ClipWorkflow : public QObject
enum State
{
None = -1,
/// \brief Used when the clipworkflow hasn't been started yet
Stopped, //0
Initializing, //1
Ready, //2
Rendering, //3
Sleeping, //4
Pausing, //5
Paused, //6
Stopping, //7
EndReached, //8
/// \brief Used when the clipworkflow is launched and active
Rendering, //1
/// \brief Used when stopping
Stopping, //2
/// \brief Used when end is reached, IE no more frame has to be rendered, but the trackworkflow
/// may eventually ask for some.
EndReached, //3
};
/**
......@@ -71,16 +71,10 @@ class ClipWorkflow : public QObject
* therefore, you can call this method blindly, without taking care
* of the rendering process advancement.
*/
virtual void* getOutput( ClipWorkflow::GetMode mode ) = 0;
virtual void* getOutput( ClipWorkflow::GetMode mode );
virtual void initVlcOutput() = 0;
void initialize( bool preloading = false );
void initialize();
/**
* Return true ONLY if the state is equal to Ready.
* If the state is Rendering, EndReached or anything else, this will
* return false.
*/
bool isReady() const;
/**
* Return true ONLY if the state is equal to EndReached.
* In any other cases, this will return false.
......@@ -99,8 +93,6 @@ class ClipWorkflow : public QObject
*/
bool isRendering() const;
bool isSleeping() const;
/**
* Returns the current workflow state.
* Be carrefull, as this function is NOT thread safe, and return the
......@@ -109,13 +101,6 @@ class ClipWorkflow : public QObject
*/
State getState() const;
/**
* This method start the effective render, ie calling the play() method
* on the media player.
* If the media player isn't ready, this method waits.
*/
void startRender( bool startInPausedMode );
/**
\brief Returns the Clip this workflow instance is based
uppon, so that you can query information on it.
......@@ -126,7 +111,6 @@ class ClipWorkflow : public QObject
\brief Stop this workflow.
*/
void stop();
void pause();
void setTime( qint64 time );
/**
......@@ -145,8 +129,6 @@ class ClipWorkflow : public QObject
*/
QReadWriteLock* getStateLock();
void unpause();
void waitForCompleteInit();
virtual void* getLockCallback() = 0;
......@@ -156,12 +138,13 @@ class ClipWorkflow : public QObject
private:
void setState( State state );
void checkSynchronisation( State newState );
void adjustBegin();
protected:
void computePtsDiff( qint64 pts );
void commonUnlock();
virtual uint32_t getAvailableBuffers() const = 0;
virtual uint32_t getComputedBuffers() const = 0;
private:
LibVLCpp::MediaPlayer* m_mediaPlayer;
......@@ -203,24 +186,10 @@ class ClipWorkflow : public QObject
void checkStateChange();
private slots:
/**
* \brief This slot is used when preloading, to pause the mediaplayer once fully loaded.
*/
void pauseAfterPlaybackStarted();
/**
* \brief When preloading, this slot is used to mark that the media player has been paused again.
*/
void initializedMediaPlayer();
void loadingComplete();
void pausedMediaPlayer();
void unpausedMediaPlayer();
public slots:
void clipEndReached();
signals:
void paused();
void unpaused();
};
#endif // CLIPWORKFLOW_H
......@@ -414,12 +414,6 @@ void MainWorkflow::clear()
emit cleared();
}
void MainWorkflow::setFullSpeedRender( bool value )
{
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
m_tracks[i]->setFullSpeedRender( value );
}
void MainWorkflow::tracksPaused()
{
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
......
......@@ -139,7 +139,6 @@ class MainWorkflow : public QObject, public Singleton<MainWorkflow>
*/
Clip* getClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType );
void setFullSpeedRender( bool value );
int getTrackCount( MainWorkflow::TrackType trackType ) const;
uint32_t getWidth() const;
......
......@@ -244,12 +244,6 @@ void TrackHandler::clear()
m_length = 0;
}
void TrackHandler::setFullSpeedRender( bool value )
{
for ( unsigned int i = 0; i < m_trackCount; ++i )
m_tracks[i]->setFullSpeedRender( value );
}
bool TrackHandler::isPaused() const
{
return m_paused;
......
......@@ -60,7 +60,6 @@ class TrackHandler : public QObject
void unmuteTrack( unsigned int trackId );
Clip* getClip( const QUuid& uuid, unsigned int trackId );
void clear();
void setFullSpeedRender( bool value );
//FIXME: remove this. This should go by the effect engine.
AudioClipWorkflow::AudioSample* getTmpAudioBuffer() { return m_tmpAudioBuffer; }
......
</
......@@ -134,69 +134,28 @@ void TrackWorkflow::renderClip( ClipWorkflow* cw, qint64 currentFrame,
// qDebug() << "Rendering clip" << cw << "state:" << cw->getState() << "Type:" << m_trackType;
if ( cw->getState() == ClipWorkflow::Rendering )
{
//The rendering state meens... whell it means that the frame is
//beeing rendered, so we wait.
cw->getStateLock()->unlock();
{
QMutexLocker lock( cw->getRenderCondWait()->getMutex() );
cw->waitForCompleteRender();
}
//This way we can trigger the appropriate if just below.
//by restoring the initial state of the function, and just pretend that
//nothing happened.
cw->getStateLock()->lockForRead();
}
//If frame has been rendered :
if ( cw->getState() == ClipWorkflow::Sleeping )
{
cw->getStateLock()->unlock();
if ( needRepositioning == true )
adjustClipTime( currentFrame, start, cw );
QMutexLocker lock( cw->getSleepMutex() );
cw->wake();
}
else if ( cw->getState() == ClipWorkflow::Stopped )
{
cw->getStateLock()->unlock();
cw->initialize();
cw->startRender( m_paused );
if ( start != currentFrame || cw->getClip()->getBegin() != 0 ) //Clip was not started as its real begining
{
adjustClipTime( currentFrame, start, cw );
}
//FIXME: comment this part ?!
if ( m_paused == true )
clipWorkflowRenderCompleted( cw );
}
else if ( cw->getState() == ClipWorkflow::Ready ||
cw->getState() == ClipWorkflow::Initializing )
{
//If the state is Initializing, then the workflow will wait.
//Otherwise, it will start directly.
cw->getStateLock()->unlock();
cw->startRender( false );
if ( needRepositioning == true )
{
adjustClipTime( currentFrame, start, cw );
}
}
else if ( cw->getState() == ClipWorkflow::EndReached )
{
cw->getStateLock()->unlock();
clipWorkflowRenderCompleted( cw );
//The stopClipWorkflow() method will take care of that.
}
else if ( cw->getState() == ClipWorkflow::Paused )
{
cw->getStateLock()->unlock();
if ( needRepositioning == true )
{
adjustClipTime( currentFrame, start, cw );
}
clipWorkflowRenderCompleted( cw );
}
else
{
cw->getStateLock()->unlock();
......@@ -210,7 +169,7 @@ void TrackWorkflow::preloadClip( ClipWorkflow* cw )
if ( cw->getState() == ClipWorkflow::Stopped )
{
cw->getStateLock()->unlock();
cw->initialize( true );
cw->initialize();
return ;
}
cw->getStateLock()->unlock();
......@@ -226,48 +185,15 @@ void TrackWorkflow::stopClipWorkflow( ClipWorkflow* cw )
cw->getStateLock()->unlock();
return ;
}
if ( cw->getState() == ClipWorkflow::Sleeping ||
cw->getState() == ClipWorkflow::Ready ||
cw->getState() == ClipWorkflow::EndReached )
if ( cw->getState() == ClipWorkflow::EndReached ||
cw->getState() == ClipWorkflow::Rendering )
{
cw->getStateLock()->unlock();
{
QMutexLocker lock( cw->getSleepMutex() );
cw->queryStateChange( ClipWorkflow::Stopping );
}
cw->wake();
cw->stop();
}
else if ( cw->getState() == ClipWorkflow::Rendering )
{
cw->getStateLock()->unlock();
{
QMutexLocker lock( cw->getRenderCondWait()->getMutex() );
cw->waitForCompleteRender();
}
{
QMutexLocker lock( cw->getSleepMutex() );
cw->queryStateChange( ClipWorkflow::Stopping );
}
cw->wake();
cw->stop();
}
else if ( cw->getState() == ClipWorkflow::Initializing )
{
cw->getStateLock()->unlock();
cw->waitForCompleteInit();
cw->stop();
}
else if ( cw->getState() == ClipWorkflow::Paused )
{
cw->getStateLock()->unlock();
cw->queryStateChange( ClipWorkflow::Stopping );
cw->wake();
cw->stop();
}
else
{
qDebug() << "Unexpected ClipWorkflow::State when stopping :" << cw->getState();
qCritical() << "Unexpected ClipWorkflow::State when stopping :" << cw->getState();
cw->getStateLock()->unlock();
}
}
......@@ -359,41 +285,7 @@ bool TrackWorkflow::getOutput( qint64 currentFrame )
void TrackWorkflow::pause()
{
QReadLocker lock( m_clipsLock );
QMap<qint64, ClipWorkflow*>::iterator it = m_clips.begin();
QMap<qint64, ClipWorkflow*>::iterator end = m_clips.end();
bool pauseRequired = false;
m_nbClipToPause = 0;
for ( ; it != end; ++it )
{
ClipWorkflow* cw = it.value();
cw->getStateLock()->lockForRead();
if ( cw->getState() == ClipWorkflow::Stopped )
{
cw->getStateLock()->unlock();
continue ;
}
else if ( cw->getState() != ClipWorkflow::Paused )
{
cw->getStateLock()->unlock();
m_nbClipToPause.fetchAndAddAcquire( 1 );
cw->pause();
pauseRequired = true;
}
else
{
//This should never be used.
qDebug() << "Asking to pause in an already paused state";
cw->getStateLock()->unlock();
}
}
if ( pauseRequired == false )
{
clipWorkflowPaused();
}
m_paused = true;
}
void TrackWorkflow::moveClip( const QUuid& id, qint64 startingFrame )
......@@ -499,54 +391,9 @@ void* TrackWorkflow::getSynchroneOutput()
return m_synchroneRenderBuffer;
}
void TrackWorkflow::clipWorkflowPaused()
{
m_nbClipToPause.fetchAndAddAcquire( -1 );
if ( m_nbClipToPause <= 0 )
{
m_paused = true;
emit trackPaused();
}
}
void TrackWorkflow::unpause()
{
QReadLocker lock( m_clipsLock );
QMap<qint64, ClipWorkflow*>::iterator it = m_clips.begin();
QMap<qint64, ClipWorkflow*>::iterator end = m_clips.end();
bool unpauseRequired = false;
m_nbClipToUnpause = 0;
for ( ; it != end; ++it )
{
ClipWorkflow* cw = it.value();
cw->getStateLock()->lockForRead();
if ( cw->getState() == ClipWorkflow::Paused )
{
cw->getStateLock()->unlock();
m_nbClipToUnpause.fetchAndAddAcquire( 1 );
cw->unpause();
unpauseRequired = true;
}
else
{
cw->getStateLock()->unlock();
}
}
if ( unpauseRequired == false )
clipWorkflowUnpaused();
}
void TrackWorkflow::clipWorkflowUnpaused()
{