diff --git a/src/Workflow/ClipWorkflow.cpp b/src/Workflow/ClipWorkflow.cpp index 7e2c95f1636f2900905a282c8b03726998e9e14d..61cc35b548f23bc442193b88f363c56b4924e5a9 100644 --- a/src/Workflow/ClipWorkflow.cpp +++ b/src/Workflow/ClipWorkflow.cpp @@ -32,26 +32,37 @@ ClipWorkflow::ClipWorkflow( Clip::Clip* clip, QMutex* condMutex, QWaitCondition* m_waitCond( waitCond ), m_mediaPlayer(NULL), m_isReady( false ), - m_endReached( false ) + m_endReached( false ), + m_stopScheduled( false ) { - m_mutex = new QReadWriteLock(); + m_renderCompleteMutex = new QReadWriteLock(); m_buffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4]; m_initMutex = new QReadWriteLock(); m_endReachedLock = new QReadWriteLock(); + m_stopScheduledMutex = new QReadWriteLock(); } ClipWorkflow::~ClipWorkflow() { delete[] m_buffer; - delete m_mutex; + delete m_renderCompleteMutex; delete m_initMutex; delete m_endReachedLock; + delete m_stopScheduledMutex; } bool ClipWorkflow::renderComplete() const { - QReadLocker lock( m_mutex ); - return m_renderComplete; + QReadLocker lock( m_renderCompleteMutex ); + QReadLocker lock2( m_endReachedLock ); + + return ( m_renderComplete || ( m_endReached == true) ); +} + +void ClipWorkflow::scheduleStop() +{ + QWriteLocker lock( m_stopScheduledMutex ); + m_stopScheduled = true; } unsigned char* ClipWorkflow::getOutput() @@ -67,7 +78,7 @@ void ClipWorkflow::lock( ClipWorkflow* clipWorkflow, void** pp_ret ) //In any case, we give vlc a buffer to render in... //If we don't, segmentation fault will catch us and eat our brain !! ahem... - qDebug() << "Locking in ClipWorkflow::lock"; +// qDebug() << "Locking in ClipWorkflow::lock"; *pp_ret = clipWorkflow->m_buffer; } @@ -75,34 +86,30 @@ void ClipWorkflow::unlock( ClipWorkflow* clipWorkflow ) { if ( clipWorkflow->m_isReady == true ) { + QMutexLocker lock5( clipWorkflow->m_condMutex ); { - QReadLocker lock( clipWorkflow->m_endReachedLock ); + QWriteLocker lock( clipWorkflow->m_endReachedLock ); + if ( clipWorkflow->m_endReached == true ) { - qDebug() << "UnLocking in ClipWorkflow::unlock"; + qDebug() << "UnLocking in ClipWorkflow::unlock (endReached == true)"; return ; } - } - { - QWriteLocker lock2( clipWorkflow->m_mutex ); + QReadLocker lock2( clipWorkflow->m_stopScheduledMutex ); + if ( clipWorkflow->m_stopScheduled == true ) + { + qDebug() << "UnLocking in ClipWorkflow::unlock (stopScheduled == true)"; + return ; + } + QWriteLocker lock3( clipWorkflow->m_renderCompleteMutex ); clipWorkflow->m_renderComplete = true; + + if ( clipWorkflow->m_mediaPlayer->getPosition() > clipWorkflow->m_clip->getEnd() ) + clipWorkflow->m_endReached = true; } - - if ( clipWorkflow->m_mediaPlayer->getPosition() > clipWorkflow->m_clip->getEnd() ) - { - QWriteLocker lock2( clipWorkflow->m_endReachedLock ); - clipWorkflow->m_endReached = true; - } - - QMutexLocker lock( clipWorkflow->m_condMutex ); clipWorkflow->m_waitCond->wait( clipWorkflow->m_condMutex ); } - qDebug() << "UnLocking in ClipWorkflow::unlock"; -} - -void ClipWorkflow::setRenderComplete() -{ - +// qDebug() << "UnLocking in ClipWorkflow::unlock"; } void ClipWorkflow::setVmem() @@ -128,6 +135,7 @@ void ClipWorkflow::setVmem() void ClipWorkflow::initialize( LibVLCpp::MediaPlayer* mediaPlayer ) { + reinitFlags(); setVmem(); m_mediaPlayer = mediaPlayer; m_mediaPlayer->setMedia( m_clip->getParent()->getVLCMedia() ); @@ -207,20 +215,11 @@ const Clip* ClipWorkflow::getClip() const void ClipWorkflow::stop() { - Q_ASSERT( m_mediaPlayer != NULL ); - { - QWriteLocker lock2( m_mutex ); - m_renderComplete = false; - } - { - QWriteLocker lock2( m_endReachedLock ); - m_endReached = true; - } - { - QWriteLocker lock( m_initMutex); - m_isReady = false; - } + qDebug() << "Calling mediaPlayer::stop()"; m_mediaPlayer->stop(); + qDebug() << "Succesfully called mediaPlayer::stop()"; + Q_ASSERT( m_mediaPlayer != NULL ); + reinitFlags(); m_mediaPlayer = NULL; qDebug() << "Stoped ClipWorkflow"; } @@ -234,3 +233,23 @@ bool ClipWorkflow::isStopped() const { return ( m_mediaPlayer == NULL ); } + +void ClipWorkflow::reinitFlags() +{ + { + QWriteLocker lock2( m_renderCompleteMutex ); + m_renderComplete = false; + } + { + QWriteLocker lock2( m_endReachedLock ); + m_endReached = false; + } + { + QWriteLocker lock( m_initMutex); + m_isReady = false; + } + { + QWriteLocker lock( m_stopScheduledMutex ); + m_stopScheduled = false; + } +} diff --git a/src/Workflow/ClipWorkflow.h b/src/Workflow/ClipWorkflow.h index bbda3329d628a6bbbf0c00c6a1ccb948ace38fe6..f9ecc7553ad4a067db3614280b8f44d69b7e57c2 100644 --- a/src/Workflow/ClipWorkflow.h +++ b/src/Workflow/ClipWorkflow.h @@ -45,6 +45,11 @@ class ClipWorkflow : public QObject ClipWorkflow( Clip* clip, QMutex* condMutex, QWaitCondition* waitCond ); virtual ~ClipWorkflow(); + /** + * Will return true if the render is completed or the end of the clip has been + * reached. + * If the workflow is still rendering, this will return false. + */ bool renderComplete() const; unsigned char* getOutput(); void initialize( LibVLCpp::MediaPlayer* mediaPlayer ); @@ -67,24 +72,31 @@ class ClipWorkflow : public QObject */ bool isStopped() const; + void scheduleStop(); + private: static void lock( ClipWorkflow* clipWorkflow, void** pp_ret ); static void unlock( ClipWorkflow* clipWorkflow ); void setVmem(); - void setRenderComplete(); + void reinitFlags(); private: Clip* m_clip; - QReadWriteLock* m_mutex; + QReadWriteLock* m_renderCompleteMutex; bool m_renderComplete; unsigned char* m_buffer; + QMutex* m_condMutex; QWaitCondition* m_waitCond; + LibVLCpp::MediaPlayer* m_mediaPlayer; + QReadWriteLock* m_initMutex; bool m_isReady; - bool m_endReached; QReadWriteLock* m_endReachedLock; + bool m_endReached; + QReadWriteLock* m_stopScheduledMutex; + bool m_stopScheduled; public slots: void pauseAfterPlaybackStarted(); diff --git a/src/Workflow/TrackWorkflow.cpp b/src/Workflow/TrackWorkflow.cpp index aca54ea3aaf9c97fb2a59f194f14f59b06966e55..9e1b2fa248d4c56c1af49b714e169dba30c22d2d 100644 --- a/src/Workflow/TrackWorkflow.cpp +++ b/src/Workflow/TrackWorkflow.cpp @@ -137,13 +137,13 @@ unsigned char* TrackWorkflow::getOutput( qint64 currentFrame ) QReadLocker lock( m_currentLock ); -// qDebug() << "Frame nb" << currentFrame; + qDebug() << "Frame nb" << currentFrame; clipsRemaining = checkNextClip( currentFrame ); if ( m_current == m_clips.end() ) { if ( clipsRemaining == false ) { -// qDebug() << "End Reached"; + qDebug() << "End Reached"; emit endReached(); } // qDebug() << "Stil no clip at this time, going to the next frame"; @@ -154,6 +154,8 @@ unsigned char* TrackWorkflow::getOutput( qint64 currentFrame ) { m_waitCondition->wakeAll(); + // We wait until the end of the render. If the clip reach end, this + // will also return true. while ( m_current.value()->renderComplete() == false ) usleep( 20 ); if ( m_current.value()->isEndReached() == false ) @@ -172,9 +174,26 @@ unsigned char* TrackWorkflow::getOutput( qint64 currentFrame ) void TrackWorkflow::stopCurrentClipWorkflow() { + qDebug() << "About to stopCurrentClipWorkflow()"; //Awaking renderer thread to avoid dead lock + m_current.value()->scheduleStop(); + m_waitCondition->wakeAll(); if ( m_current.value()->isStopped() == false ) m_current.value()->stop(); + qDebug() << "Stopped stopCurrentClipWorkflow();"; +} + +void TrackWorkflow::initializeClipWorkflow( ClipWorkflow* cw ) +{ + //>Launching the initialization + qDebug()<< "Initializing clip workflow (initializeClipWorkflow())"; + cw->initialize( m_mediaPlayer ); + //And then wait for it to be ready + while ( cw->isReady() == false ) + usleep( 20 ); + //Once it is, we actually start the render + cw->startRender(); + qDebug() << "End of clip workflow reinitialization"; } void TrackWorkflow::setPosition( float pos ) @@ -202,7 +221,7 @@ void TrackWorkflow::setPosition( float pos ) if ( it.key() <= frame && ( it.key() + it.value()->getClip()->getLength() ) > frame ) { - qDebug() << "Found new current clip workflow"; +// qDebug() << "Found new current clip workflow"; break; } else if ( next == m_clips.end() && it.key() > frame ) @@ -214,13 +233,13 @@ void TrackWorkflow::setPosition( float pos ) next = it; if ( next != m_clips.begin() ) { - qDebug() << "Next clip isn't the first one"; +// qDebug() << "Next clip isn't the first one"; next = next - 1; //Since the iterator must point to the previous video } else { next = end; - qDebug() << "Next clip is the first of the track"; +// qDebug() << "Next clip is the first of the track"; } // in order to checkNextClip() to work. it = end; @@ -229,36 +248,45 @@ void TrackWorkflow::setPosition( float pos ) ++it; } - if ( it == m_clips.end() ) + //No clip was found : + if ( it == end ) { + //We should use the next clip, however, we use the clip just before + //the next. + //We also stop the current clip if it was started. if ( m_current != end ) { stopCurrentClipWorkflow(); } m_current = next; } + // If the clip found is the current, we just change the position of the + // media player else if ( it == m_current ) { + //The clip may have been stoped (if we reached end but came back at it) + if ( it.value()->isStopped() ) + { + initializeClipWorkflow( it.value() ); + } qDebug() << "Changing the position of the current clip"; - //We're changing the position of the current clip it.value()->setPosition( (float)( frame - it.key() ) / (float)(it.value()->getClip()->getLength()) ); //Awaking renderers to avoid them to be stuck inside of the lock... // qDebug() << "Waking all renderer threads"; m_waitCondition->wakeAll(); } + // Else, we found a clip that is not the current one. else - { - qDebug() << "Switching to other Clip"; + { +// qDebug() << "Switching to other Clip"; + //First, we stop the current workflow. if ( m_current != end ) { stopCurrentClipWorkflow(); -// m_waitCondition->wakeAll(); } - - it.value()->initialize( m_mediaPlayer ); - while ( it.value()->isReady() == false ) - usleep( 20 ); - it.value()->startRender(); + //We initialize the new workflow + initializeClipWorkflow( it.value() ); + //And this is now our current clip m_current = it; // qDebug() << "Switched current clip workflow"; } diff --git a/src/Workflow/TrackWorkflow.h b/src/Workflow/TrackWorkflow.h index d23a71a6e586c3ab76727810ba9e13d5af8f7c00..ef599eb4146940bf43de9a33e473a2765cf1030d 100644 --- a/src/Workflow/TrackWorkflow.h +++ b/src/Workflow/TrackWorkflow.h @@ -69,6 +69,7 @@ class TrackWorkflow : public QObject bool checkNextClip( qint64 currentFrame ); void computeLength(); void stopCurrentClipWorkflow(); + void initializeClipWorkflow( ClipWorkflow* cw ); private: QMap m_clips; diff --git a/src/gui/RenderPreviewWidget.cpp b/src/gui/RenderPreviewWidget.cpp index d0ce338096ee7fd14c83f8825a48a7fbd028f71d..e9d056edcd1d45c4a38a8640ae9c3187815bb715 100644 --- a/src/gui/RenderPreviewWidget.cpp +++ b/src/gui/RenderPreviewWidget.cpp @@ -76,6 +76,7 @@ void RenderPreviewWidget::unlock( void* ) void RenderPreviewWidget::stopPreview() { + //This might be called multiple times, but this is due to Qt message loop m_mediaPlayer->stop(); m_isRendering = false; qDebug() << "Stopped";