Commit 8a4a97b7 authored by Hugo Beauzee-Luyssen's avatar Hugo Beauzee-Luyssen

Merge branch 'chouquette_frame_by_frame'

Conflicts:
	src/Workflow/ClipWorkflow.cpp
	src/Workflow/MainWorkflow.cpp
	src/Workflow/MainWorkflow.h
	src/Workflow/TrackWorkflow.cpp
	src/Workflow/TrackWorkflow.h
	src/gui/MainWindow.cpp
	src/renderer/WorkflowRenderer.cpp
parents c972ec68 f192e84e
...@@ -28,14 +28,12 @@ ...@@ -28,14 +28,12 @@
ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) : ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) :
m_clip( clip ), m_clip( clip ),
m_buffer( NULL ),
//m_usingBackBuffer( false ),
m_mediaPlayer(NULL), m_mediaPlayer(NULL),
m_state( ClipWorkflow::Stopped ), m_state( ClipWorkflow::Stopped ),
m_requiredState( ClipWorkflow::None ) m_requiredState( ClipWorkflow::None ),
m_rendering( false ),
m_initFlag( false )
{ {
m_buffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
// m_backBuffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
m_stateLock = new QReadWriteLock; m_stateLock = new QReadWriteLock;
m_requiredStateLock = new QMutex; m_requiredStateLock = new QMutex;
m_waitCond = new QWaitCondition; m_waitCond = new QWaitCondition;
...@@ -43,13 +41,13 @@ ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) : ...@@ -43,13 +41,13 @@ ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) :
m_initWaitCond = new WaitCondition; m_initWaitCond = new WaitCondition;
m_renderWaitCond = new WaitCondition; m_renderWaitCond = new WaitCondition;
m_pausingStateWaitCond = new WaitCondition; m_pausingStateWaitCond = new WaitCondition;
// m_backBufferLock = new QReadWriteLock; m_renderLock = new QMutex;
m_buffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
} }
ClipWorkflow::~ClipWorkflow() ClipWorkflow::~ClipWorkflow()
{ {
// delete[] m_backBuffer; delete m_renderLock;
// delete m_backBufferLock;
delete m_pausingStateWaitCond; delete m_pausingStateWaitCond;
delete m_initWaitCond; delete m_initWaitCond;
delete m_condMutex; delete m_condMutex;
...@@ -61,10 +59,9 @@ ClipWorkflow::~ClipWorkflow() ...@@ -61,10 +59,9 @@ ClipWorkflow::~ClipWorkflow()
unsigned char* ClipWorkflow::getOutput() unsigned char* ClipWorkflow::getOutput()
{ {
// QReadLocker lock( m_backBufferLock ); QMutexLocker lock( m_renderLock );
// if ( m_usingBackBuffer == true )
return m_buffer; return m_buffer;
// return m_backBuffer;
} }
void ClipWorkflow::checkStateChange() void ClipWorkflow::checkStateChange()
...@@ -73,7 +70,6 @@ void ClipWorkflow::checkStateChange() ...@@ -73,7 +70,6 @@ void ClipWorkflow::checkStateChange()
QWriteLocker lock2( m_stateLock ); QWriteLocker lock2( m_stateLock );
if ( m_requiredState != ClipWorkflow::None ) if ( m_requiredState != ClipWorkflow::None )
{ {
// qDebug() << "Changed state from" << m_state << "to state" << m_requiredState;
m_state = m_requiredState; m_state = m_requiredState;
m_requiredState = ClipWorkflow::None; m_requiredState = ClipWorkflow::None;
checkSynchronisation( m_state ); checkSynchronisation( m_state );
...@@ -82,55 +78,31 @@ void ClipWorkflow::checkStateChange() ...@@ -82,55 +78,31 @@ void ClipWorkflow::checkStateChange()
void ClipWorkflow::lock( ClipWorkflow* cw, void** pp_ret ) void ClipWorkflow::lock( ClipWorkflow* cw, void** pp_ret )
{ {
// QReadLocker lock( cw->m_backBufferLock ); cw->m_renderLock->lock();
*pp_ret = cw->m_buffer;
// if ( cw->m_usingBackBuffer )
// {
// *pp_ret = cw->m_backBuffer;
// }
// else
// {
*pp_ret = cw->m_buffer;
// }
} }
void ClipWorkflow::unlock( ClipWorkflow* cw ) void ClipWorkflow::unlock( ClipWorkflow* cw )
{ {
cw->m_renderLock->unlock();
cw->m_stateLock->lockForWrite(); cw->m_stateLock->lockForWrite();
// if ( cw->m_oneFrameOnly )
// {
// qDebug() << "One frame only mode is ON :)";
// //Forcing pause after rendering a frame
// cw->m_oneFrameOnly = 0;
// cw->m_state = Paused;
// }
// else
// qDebug() << "One frame only mode is OFF :(";
if ( cw->m_state == Rendering ) if ( cw->m_state == Rendering )
{ {
QMutexLocker lock( cw->m_condMutex ); QMutexLocker lock( cw->m_condMutex );
cw->m_state = Sleeping; cw->m_state = Sleeping;
cw->m_stateLock->unlock(); cw->m_stateLock->unlock();
//Signal that render has been completed.
cw->m_renderWaitCond->wake(); cw->m_renderWaitCond->wake();
cw->emit renderComplete( cw ); cw->emit renderComplete( cw );
// qDebug() << ">>>Entering condwait";
cw->m_waitCond->wait( cw->m_condMutex ); cw->m_waitCond->wait( cw->m_condMutex );
// qDebug() << "Leaved condwait"; // qDebug() << "<<<Leaving condwait";
cw->m_stateLock->lockForWrite(); cw->m_stateLock->lockForWrite();
cw->m_state = Rendering; cw->m_state = Rendering;
// {
// QWriteLocker lock2( cw->m_backBufferLock );
// cw->m_usingBackBuffer = !cw->m_usingBackBuffer;
// }
cw->m_stateLock->unlock();
}
else if ( cw->m_state == Paused )
{
cw->m_stateLock->unlock(); cw->m_stateLock->unlock();
cw->m_waitCond->wait( cw->m_condMutex );
} }
else else
cw->m_stateLock->unlock(); cw->m_stateLock->unlock();
...@@ -171,21 +143,23 @@ void ClipWorkflow::initialize() ...@@ -171,21 +143,23 @@ void ClipWorkflow::initialize()
m_mediaPlayer->play(); m_mediaPlayer->play();
} }
//FIXME: this step is probably useless, due to modification in the TrackWorkflow
void ClipWorkflow::setPositionAfterPlayback() void ClipWorkflow::setPositionAfterPlayback()
{ {
disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ) ); disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ) );
connect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ), Qt::DirectConnection ); connect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ), Qt::DirectConnection );
m_mediaPlayer->setPosition( m_clip->getBegin() ); m_mediaPlayer->setPosition( m_clip->getBegin() );
} }
void ClipWorkflow::pauseAfterPlaybackStarted() void ClipWorkflow::pauseAfterPlaybackStarted()
{ {
disconnect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ) ); disconnect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ) );
//FIXME: it seems that this signal is never connected :o
disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) ); disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) );
connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ), Qt::DirectConnection ); connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ), Qt::DirectConnection );
m_mediaPlayer->pause();
m_mediaPlayer->pause();
} }
void ClipWorkflow::initializedMediaPlayer() void ClipWorkflow::initializedMediaPlayer()
...@@ -200,12 +174,6 @@ bool ClipWorkflow::isReady() const ...@@ -200,12 +174,6 @@ bool ClipWorkflow::isReady() const
return m_state == ClipWorkflow::Ready; return m_state == ClipWorkflow::Ready;
} }
bool ClipWorkflow::isPausing() const
{
QReadLocker lock( m_stateLock );
return m_state == ClipWorkflow::Pausing;
}
bool ClipWorkflow::isEndReached() const bool ClipWorkflow::isEndReached() const
{ {
QReadLocker lock( m_stateLock ); QReadLocker lock( m_stateLock );
...@@ -223,13 +191,20 @@ ClipWorkflow::State ClipWorkflow::getState() const ...@@ -223,13 +191,20 @@ ClipWorkflow::State ClipWorkflow::getState() const
return m_state; return m_state;
} }
void ClipWorkflow::startRender() void ClipWorkflow::startRender( bool startInPausedMode )
{ {
if ( isReady() == false ) if ( isReady() == false )
m_initWaitCond->wait(); m_initWaitCond->wait();
m_mediaPlayer->play(); if ( startInPausedMode == false )
setState( Rendering ); {
m_mediaPlayer->play();
setState( Rendering );
}
else
{
setState( Paused );
}
} }
void ClipWorkflow::clipEndReached() void ClipWorkflow::clipEndReached()
...@@ -254,6 +229,8 @@ void ClipWorkflow::stop() ...@@ -254,6 +229,8 @@ void ClipWorkflow::stop()
QMutexLocker lock( m_requiredStateLock ); QMutexLocker lock( m_requiredStateLock );
m_requiredState = ClipWorkflow::None; m_requiredState = ClipWorkflow::None;
delete m_vlcMedia; delete m_vlcMedia;
m_initFlag = false;
m_rendering = false;
} }
else else
qDebug() << "ClipWorkflow has already been stopped"; qDebug() << "ClipWorkflow has already been stopped";
...@@ -270,6 +247,12 @@ bool ClipWorkflow::isRendering() const ...@@ -270,6 +247,12 @@ bool ClipWorkflow::isRendering() const
return m_state == ClipWorkflow::Rendering; return m_state == ClipWorkflow::Rendering;
} }
bool ClipWorkflow::isSleeping() const
{
QReadLocker lock( m_stateLock );
return m_state == ClipWorkflow::Sleeping;
}
void ClipWorkflow::checkSynchronisation( State newState ) void ClipWorkflow::checkSynchronisation( State newState )
{ {
switch ( newState ) switch ( newState )
...@@ -277,9 +260,6 @@ void ClipWorkflow::checkSynchronisation( State newState ) ...@@ -277,9 +260,6 @@ void ClipWorkflow::checkSynchronisation( State newState )
case Ready: case Ready:
m_initWaitCond->wake(); m_initWaitCond->wake();
break ; break ;
case Pausing:
m_pausingStateWaitCond->wake();
break ;
default: default:
break ; break ;
} }
...@@ -289,6 +269,7 @@ void ClipWorkflow::setState( State state ) ...@@ -289,6 +269,7 @@ void ClipWorkflow::setState( State state )
{ {
{ {
QWriteLocker lock( m_stateLock ); QWriteLocker lock( m_stateLock );
// qDebug() << "Changing from state" << m_state << "to state" << state;
m_state = state; m_state = state;
} }
checkSynchronisation( state ); checkSynchronisation( state );
...@@ -320,32 +301,28 @@ void ClipWorkflow::reinitialize() ...@@ -320,32 +301,28 @@ void ClipWorkflow::reinitialize()
void ClipWorkflow::pause() void ClipWorkflow::pause()
{ {
setState( Paused ); connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ), Qt::DirectConnection );
setState( Pausing );
m_mediaPlayer->pause(); m_mediaPlayer->pause();
QMutexLocker lock( m_requiredStateLock ); QMutexLocker lock( m_requiredStateLock );
m_requiredState = ClipWorkflow::None; m_requiredState = ClipWorkflow::None;
{
QMutexLocker sync( m_condMutex );
wake();
}
} }
void ClipWorkflow::unpause( bool wakeRenderThread /*= true*/ ) void ClipWorkflow::unpause()
{ {
//Since VLC will detect that the media player is paused and unpause it, we can do this safely queryStateChange( ClipWorkflow::Rendering );
setState( ClipWorkflow::Rendering ); connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( unpausedMediaPlayer() ), Qt::DirectConnection );
m_mediaPlayer->pause(); m_mediaPlayer->pause();
// QMutexLocker lock( m_requiredStateLock );
// m_requiredState = ClipWorkflow::None;
if ( wakeRenderThread == true )
wake();
} }
//void ClipWorkflow::activateOneFrameOnly() void ClipWorkflow::waitForCompleteRender( bool dontCheckRenderStarted /*= false*/ )
//{
// qDebug() << "Activating one frame only";
// m_oneFrameOnly = 1;
//}
void ClipWorkflow::waitForCompleteRender()
{ {
if ( isRendering() == true ) if ( isRendering() == true || dontCheckRenderStarted == true )
m_renderWaitCond->wait(); m_renderWaitCond->wait();
} }
...@@ -355,12 +332,6 @@ void ClipWorkflow::waitForCompleteInit() ...@@ -355,12 +332,6 @@ void ClipWorkflow::waitForCompleteInit()
m_initWaitCond->wait(); m_initWaitCond->wait();
} }
void ClipWorkflow::waitForPausingState()
{
if ( isPausing() == false )
m_pausingStateWaitCond->wait();
}
QMutex* ClipWorkflow::getSleepMutex() QMutex* ClipWorkflow::getSleepMutex()
{ {
return m_condMutex; return m_condMutex;
...@@ -370,3 +341,16 @@ LibVLCpp::MediaPlayer* ClipWorkflow::getMediaPlayer() ...@@ -370,3 +341,16 @@ LibVLCpp::MediaPlayer* ClipWorkflow::getMediaPlayer()
{ {
return m_mediaPlayer; return m_mediaPlayer;
} }
void ClipWorkflow::pausedMediaPlayer()
{
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();
}
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <QMutex> #include <QMutex>
#include "WaitCondition.hpp" #include "WaitCondition.hpp"
#include <QObject> #include <QObject>
#include <QQueue>
#include "Clip.h" #include "Clip.h"
#include "VLCMediaPlayer.h" #include "VLCMediaPlayer.h"
...@@ -91,7 +92,7 @@ class ClipWorkflow : public QObject ...@@ -91,7 +92,7 @@ class ClipWorkflow : public QObject
*/ */
bool isRendering() const; bool isRendering() const;
bool isPausing() const; bool isSleeping() const;
/** /**
* Returns the current workflow state. * Returns the current workflow state.
...@@ -106,7 +107,7 @@ class ClipWorkflow : public QObject ...@@ -106,7 +107,7 @@ class ClipWorkflow : public QObject
* on the media player. * on the media player.
* If the media player isn't ready, this method waits. * If the media player isn't ready, this method waits.
*/ */
void startRender(); void startRender( bool startInPausedMode );
/** /**
\brief Returns the Clip this workflow instance is based \brief Returns the Clip this workflow instance is based
...@@ -147,17 +148,14 @@ class ClipWorkflow : public QObject ...@@ -147,17 +148,14 @@ class ClipWorkflow : public QObject
*/ */
void reinitialize(); void reinitialize();
void unpause( bool wakeRenderThread = true ); void unpause();
void waitForCompleteInit(); void waitForCompleteInit();
void waitForCompleteRender(); void waitForCompleteRender( bool dontCheckRenderStarted = false );
void waitForPausingState();
QMutex* getSleepMutex(); QMutex* getSleepMutex();
LibVLCpp::MediaPlayer* getMediaPlayer(); LibVLCpp::MediaPlayer* getMediaPlayer();
// void activateOneFrameOnly();
private: private:
static void lock( ClipWorkflow* clipWorkflow, void** pp_ret ); static void lock( ClipWorkflow* clipWorkflow, void** pp_ret );
static void unlock( ClipWorkflow* clipWorkflow ); static void unlock( ClipWorkflow* clipWorkflow );
...@@ -178,17 +176,7 @@ class ClipWorkflow : public QObject ...@@ -178,17 +176,7 @@ class ClipWorkflow : public QObject
LibVLCpp::Media* m_vlcMedia; LibVLCpp::Media* m_vlcMedia;
unsigned char* m_buffer; unsigned char* m_buffer;
//unsigned char* m_backBuffer; QMutex* m_renderLock;
/**
* This allow the render procedure to know in which buffer it should render.
* If true, then the render occurs in the back buffer, which means the
* returned buffer much be the "front" buffer.
* In other term :
* - When m_usingBackBuffer == false, lock() will return m_buffer, and getOutput() m_backBuffer
* - When m_usingBackBuffer == true, lock() will return m_backBuffer, and getOutput() m_buffer
*/
//bool m_usingBackBuffer;
//QReadWriteLock* m_backBufferLock;
LibVLCpp::MediaPlayer* m_mediaPlayer; LibVLCpp::MediaPlayer* m_mediaPlayer;
...@@ -200,22 +188,36 @@ class ClipWorkflow : public QObject ...@@ -200,22 +188,36 @@ class ClipWorkflow : public QObject
State m_requiredState; State m_requiredState;
QMutex* m_requiredStateLock; QMutex* m_requiredStateLock;
QAtomicInt m_oneFrameOnly;
WaitCondition* m_initWaitCond; WaitCondition* m_initWaitCond;
WaitCondition* m_renderWaitCond; WaitCondition* m_renderWaitCond;
WaitCondition* m_pausingStateWaitCond; WaitCondition* m_pausingStateWaitCond;
/**
* While this flag is set to false, we will use the same buffer, to prevent
* having X buffers with the same picture (when media player is paused mainly)
*/
bool m_rendering;
/**
* This flag is here to avoid multiple connection to the mediaPlayer* slots.
* It's essentially a nasty hack due to the multiples calls to lock/unlock when
* the render is started, and that cannot really be avoided...
*/
bool m_initFlag;
private slots: private slots:
void pauseAfterPlaybackStarted(); void pauseAfterPlaybackStarted();
void initializedMediaPlayer(); void initializedMediaPlayer();
void setPositionAfterPlayback(); void setPositionAfterPlayback();
void pausedMediaPlayer();
void unpausedMediaPlayer();
public slots: public slots:
void clipEndReached(); void clipEndReached();
signals: signals:
void renderComplete( ClipWorkflow* ); void renderComplete( ClipWorkflow* );
void paused();
void unpaused();
}; };
#endif // CLIPWORKFLOW_H #endif // CLIPWORKFLOW_H
...@@ -46,6 +46,7 @@ MainWorkflow::MainWorkflow( int trackCount ) : ...@@ -46,6 +46,7 @@ MainWorkflow::MainWorkflow( int trackCount ) :
m_tracks[i].setPtr( new TrackWorkflow( i ) ); m_tracks[i].setPtr( new TrackWorkflow( i ) );
connect( m_tracks[i], SIGNAL( trackEndReached( unsigned int ) ), this, SLOT( trackEndReached(unsigned int) ) ); connect( m_tracks[i], SIGNAL( trackEndReached( unsigned int ) ), this, SLOT( trackEndReached(unsigned int) ) );
connect( m_tracks[i], SIGNAL( trackPaused() ), this, SLOT( trackPaused() ) ); connect( m_tracks[i], SIGNAL( trackPaused() ), this, SLOT( trackPaused() ) );
connect( m_tracks[i], SIGNAL( trackUnpaused() ), this, SLOT( trackUnpaused() ) );
connect( m_tracks[i], SIGNAL( renderCompleted( unsigned int ) ), this, SLOT( tracksRenderCompleted( unsigned int ) ), Qt::QueuedConnection ); connect( m_tracks[i], SIGNAL( renderCompleted( unsigned int ) ), this, SLOT( tracksRenderCompleted( unsigned int ) ), Qt::QueuedConnection );
} }
m_renderStartedLock = new QReadWriteLock; m_renderStartedLock = new QReadWriteLock;
...@@ -105,7 +106,7 @@ void MainWorkflow::startRender() ...@@ -105,7 +106,7 @@ void MainWorkflow::startRender()
computeLength(); computeLength();
} }
unsigned char* MainWorkflow::getOutput() void MainWorkflow::getOutput()
{ {
QReadLocker lock( m_renderStartedLock ); QReadLocker lock( m_renderStartedLock );
QMutexLocker lock2( m_renderMutex ); QMutexLocker lock2( m_renderMutex );
...@@ -118,27 +119,19 @@ unsigned char* MainWorkflow::getOutput() ...@@ -118,27 +119,19 @@ unsigned char* MainWorkflow::getOutput()
m_synchroneRenderingBuffer = NULL; m_synchroneRenderingBuffer = NULL;
if ( m_renderStarted == true ) if ( m_renderStarted == true )
{ {
unsigned char* ret;
for ( unsigned int i = 0; i < m_trackCount; ++i ) for ( unsigned int i = 0; i < m_trackCount; ++i )
{ {
if ( m_tracks[i].activated() == false ) if ( m_tracks[i].activated() == false )
continue ; continue ;
if ( ( ret = m_tracks[i]->getOutput( m_currentFrame ) ) != NULL ) m_nbTracksToRender.fetchAndAddAcquire( 1 );
if ( m_tracks[i]->getOutput( m_currentFrame ) != false )
{ {
m_nbTracksToRender.fetchAndAddAcquire( 1 );
break ; break ;
} }
} }
if ( ret == NULL ) if ( m_paused == false )
ret = MainWorkflow::blackOutput; nextFrame();
nextFrame();
return ret;
}
else
{
return MainWorkflow::blackOutput;
} }
} }
...@@ -157,8 +150,24 @@ void MainWorkflow::pause() ...@@ -157,8 +150,24 @@ void MainWorkflow::pause()
} }
} }
void MainWorkflow::unpause()
{
QMutexLocker lock( m_renderMutex );
m_nbTracksToUnpause = 0;
for ( unsigned int i = 0; i < m_trackCount; ++i )
{
if ( m_tracks[i].activated() == true )
{
m_nbTracksToUnpause.fetchAndAddAcquire( 1 );
m_tracks[i]->unpause();
}
}
}
void MainWorkflow::nextFrame() void MainWorkflow::nextFrame()
{ {
// qDebug() << "Going to the next frame";
++m_currentFrame; ++m_currentFrame;
//FIXME: This is probably a bit much... //FIXME: This is probably a bit much...
emit frameChanged( m_currentFrame ); emit frameChanged( m_currentFrame );
...@@ -167,6 +176,7 @@ void MainWorkflow::nextFrame() ...@@ -167,6 +176,7 @@ void MainWorkflow::nextFrame()
void MainWorkflow::previousFrame() void MainWorkflow::previousFrame()
{ {