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

First refactoring step.

All the methods has been moved down to a new TrackHandler class.
Synchronisation stuff is in progress
parent 24744cda
......@@ -25,37 +25,33 @@
#include "MainWorkflow.h"
//JUST FOR THE DEFINES !
//TODO:
//FIXME: remove this !
#include "ClipWorkflow.h"
unsigned char* MainWorkflow::blackOutput = NULL;
MainWorkflow* MainWorkflow::m_instance = NULL;
MainWorkflow::MainWorkflow( int trackCount ) :
m_currentFrame( 0 ),
m_length( 0 ),
m_trackCount( trackCount ),
m_renderStarted( false )
{
Q_ASSERT_X( MainWorkflow::m_instance == NULL,
"MainWorkflow constructor", "Can't have more than one MainWorkflow instance" );
m_instance = this;
MainWorkflow::blackOutput = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 3];
memset( MainWorkflow::blackOutput, 0, VIDEOHEIGHT * VIDEOWIDTH * 3 );
m_tracks = new Toggleable<TrackWorkflow*>[trackCount];
for ( int i = 0; i < trackCount; ++i )
{
m_tracks[i].setPtr( new TrackWorkflow( i, TrackWorkflow::Video ) );
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( trackUnpaused() ), this, SLOT( trackUnpaused() ) );
connect( m_tracks[i], SIGNAL( renderCompleted( unsigned int ) ), this, SLOT( tracksRenderCompleted( unsigned int ) ), Qt::QueuedConnection );
}
m_renderStartedLock = new QReadWriteLock;
m_renderMutex = new QMutex;
m_highestTrackNumberMutex = new QMutex;
m_synchroneRenderWaitCondition = new QWaitCondition;
m_synchroneRenderWaitConditionMutex = new QMutex;
m_nbTracksToRenderMutex = new QMutex;
m_tracks = new TrackHandler*[2];
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
{
TrackWorkflow::TrackType trackType = (i == 0 ? TrackWorkflow::Video : TrackWorkflow::Audio );
m_tracks[i] = new TrackHandler( trackCount, trackType );
connect( m_tracks[i], SIGNAL( tracksPaused() ), this, SLOT( tracksPaused() ) );
}
m_outputBuffers = new OutputBuffers;
}
MainWorkflow::~MainWorkflow()
......@@ -63,41 +59,30 @@ MainWorkflow::~MainWorkflow()
//FIXME: this is probably useless, since already done by the renderer
stop();
delete m_nbTracksToRenderMutex;
delete m_synchroneRenderWaitConditionMutex;
delete m_synchroneRenderWaitCondition;
delete m_highestTrackNumberMutex;
delete m_renderMutex;
delete m_renderStartedLock;
for (unsigned int i = 0; i < m_trackCount; ++i)
delete m_tracks[i];
delete[] m_tracks;
delete[] blackOutput;
delete m_tracks[0];
delete m_tracks[1];
delete[] m_tracks;
}
void MainWorkflow::addClip( Clip* clip, unsigned int trackId, qint64 start )
void MainWorkflow::addClip( Clip* clip, unsigned int trackId,
qint64 start, TrackWorkflow::TrackType trackType )
{
Q_ASSERT_X( trackId < m_trackCount, "MainWorkflow::addClip",
"The specified trackId isn't valid, for it's higher than the number of tracks");
m_tracks[trackId]->addClip( clip, start );
//if the track is deactivated, we need to reactivate it.
if ( m_tracks[trackId].deactivated() == true )
activateTrack( trackId );
//Now check if this clip addition has changed something about the workflow's length
if ( m_tracks[trackId]->getLength() > m_length )
m_length = m_tracks[trackId]->getLength();
m_tracks[trackType]->addClip( clip, trackId, start );
//Inform the GUI
emit clipAdded( clip, trackId, start );
emit clipAdded( clip, trackId, start, trackType );
}
void MainWorkflow::computeLength()
{
qint64 maxLength = 0;
for ( unsigned int i = 0; i < m_trackCount; ++i )
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
{
if ( m_tracks[i]->getLength() > maxLength )
maxLength = m_tracks[i]->getLength();
......@@ -109,8 +94,8 @@ void MainWorkflow::startRender()
{
m_renderStarted = true;
m_paused = false;
for ( unsigned int i = 0; i < m_trackCount; ++i )
activateTrack( i );
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->startRender();
computeLength();
}
......@@ -119,23 +104,10 @@ void MainWorkflow::getOutput()
QReadLocker lock( m_renderStartedLock );
QMutexLocker lock2( m_renderMutex );
{
QMutexLocker lockHighestTrackNumber( m_highestTrackNumberMutex );
m_highestTrackNumber = 0;
}
m_nbTracksToRender = 0;
m_synchroneRenderingBuffer = NULL;
if ( m_renderStarted == true )
{
QMutexLocker lockNbTracks( m_nbTracksToRenderMutex );
for ( unsigned int i = 0; i < m_trackCount; ++i )
{
if ( m_tracks[i].activated() == false )
continue ;
++m_nbTracksToRender;
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->getOutput( m_currentFrame );
}
if ( m_paused == false )
nextFrame();
}
......@@ -145,30 +117,16 @@ void MainWorkflow::pause()
{
QMutexLocker lock( m_renderMutex );
m_nbTracksToPause = 0;
for ( unsigned int i = 0; i < m_trackCount; ++i )
{
if ( m_tracks[i].activated() == true )
{
m_nbTracksToPause.fetchAndAddAcquire( 1 );
m_tracks[i]->pause();
}
}
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->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();
}
}
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->unpause();
}
void MainWorkflow::nextFrame()
......@@ -191,8 +149,8 @@ void MainWorkflow::setPosition( float pos )
{
//Since any track can be reactivated, we reactivate all of them, and let them
//unable themself if required.
for ( unsigned int i = 0; i < m_trackCount; ++i)
activateTrack( i );
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i)
m_tracks[i]->activateAll();
}
qint64 frame = static_cast<qint64>( (float)m_length * pos );
m_currentFrame = frame;
......@@ -205,28 +163,9 @@ qint64 MainWorkflow::getLength() const
return m_length;
}
qint64 MainWorkflow::getClipPosition( const QUuid& uuid, unsigned int trackId ) const
{
Q_ASSERT( trackId < m_trackCount );
return m_tracks[trackId]->getClipPosition( uuid );
}
void MainWorkflow::trackEndReached( unsigned int trackId )
{
m_tracks[trackId].deactivate();
for ( unsigned int i = 0; i < m_trackCount; ++i)
{
if ( m_tracks[i].activated() == true )
return ;
}
emit mainWorkflowEndReached();
}
unsigned int MainWorkflow::getTrackCount() const
qint64 MainWorkflow::getClipPosition( const QUuid& uuid, unsigned int trackId, TrackWorkflow::TrackType trackType ) const
{
return m_trackCount;
return m_tracks[trackType]->getClipPosition( uuid, trackId );
}
void MainWorkflow::stop()
......@@ -234,123 +173,27 @@ void MainWorkflow::stop()
QWriteLocker lock( m_renderStartedLock );
m_renderStarted = false;
for (unsigned int i = 0; i < m_trackCount; ++i)
{
if ( m_tracks[i].activated() == true )
m_tracks[i]->stop();
}
for (unsigned int i = 0; i < TrackWorkflow::NbType; ++i)
m_tracks[i]->stop();
m_currentFrame = 0;
emit frameChanged( 0 );
emit positionChanged( 0 );
}
MainWorkflow* MainWorkflow::getInstance()
{
Q_ASSERT( m_instance != NULL );
return m_instance;
}
void MainWorkflow::deleteInstance()
{
if ( m_instance != NULL )
{
delete m_instance;
m_instance = NULL;
}
}
void MainWorkflow::moveClip( const QUuid& clipUuid, unsigned int oldTrack,
unsigned int newTrack, qint64 startingFrame, bool undoRedoCommand /*= false*/ )
{
Q_ASSERT( newTrack < m_trackCount && oldTrack < m_trackCount );
if ( oldTrack == newTrack )
{
//And now, just move the clip.
m_tracks[newTrack]->moveClip( clipUuid, startingFrame );
activateTrack( newTrack );
}
else
{
bool needRepo;
if ( m_tracks[oldTrack]->getClipPosition( clipUuid ) != startingFrame )
needRepo = true;
ClipWorkflow* cw = m_tracks[oldTrack]->removeClipWorkflow( clipUuid );
m_tracks[newTrack]->addClip( cw, startingFrame );
if ( needRepo == true )
m_tracks[newTrack]->forceRepositionning();
activateTrack( oldTrack );
activateTrack( newTrack );
}
computeLength();
if ( undoRedoCommand == true )
{
emit clipMoved( clipUuid, newTrack, startingFrame );
}
}
Clip* MainWorkflow::removeClip( const QUuid& uuid, unsigned int trackId )
unsigned int newTrack, qint64 startingFrame,
TrackWorkflow::TrackType trackType, bool undoRedoCommand /*= false*/ )
{
Q_ASSERT( trackId < m_trackCount );
Clip* clip = m_tracks[trackId]->removeClip( uuid );
m_tracks[trackType]->moveClip( clipUuid, oldTrack, newTrack, startingFrame, undoRedoCommand );
computeLength();
activateTrack( trackId );
emit clipRemoved( uuid, trackId );
return clip;
}
void MainWorkflow::trackPaused()
{
m_nbTracksToPause.fetchAndAddAcquire( -1 );
if ( m_nbTracksToPause <= 0 )
{
m_paused = true;
emit mainWorkflowPaused();
}
}
void MainWorkflow::trackUnpaused()
{
m_nbTracksToUnpause.fetchAndAddAcquire( -1 );
if ( m_nbTracksToUnpause <= 0 )
{
m_paused = false;
emit mainWorkflowUnpaused();
}
}
void MainWorkflow::tracksRenderCompleted( unsigned int trackId )
Clip* MainWorkflow::removeClip( const QUuid& uuid, unsigned int trackId, TrackWorkflow::TrackType trackType )
{
// qDebug() << "tracksRenderCompleted";
QMutexLocker lockNbTracks( m_nbTracksToRenderMutex );
--m_nbTracksToRender;
{
QMutexLocker lock( m_highestTrackNumberMutex );
unsigned char* buff = m_tracks[trackId]->getSynchroneOutput();
if ( m_highestTrackNumber <= trackId && buff != NULL )
{
m_highestTrackNumber = trackId;
m_synchroneRenderingBuffer = buff;;
}
}
//We check for minus or equal, since we can have 0 frame to compute,
//therefore, m_nbTracksToRender will be equal to -1
if ( m_nbTracksToRender <= 0 )
{
// qDebug() << "main workflow render completed";
//Just a synchronisation barriere
{
QMutexLocker lock( m_synchroneRenderWaitConditionMutex );
}
m_synchroneRenderWaitCondition->wakeAll();
}
return m_tracks[trackType]->removeClip( uuid, trackId );
}
unsigned char* MainWorkflow::getSynchroneOutput()
MainWorkflow::OutputBuffers* MainWorkflow::getSynchroneOutput()
{
m_synchroneRenderWaitConditionMutex->lock();
getOutput();
......@@ -358,9 +201,7 @@ unsigned char* MainWorkflow::getSynchroneOutput()
m_synchroneRenderWaitCondition->wait( m_synchroneRenderWaitConditionMutex );
// qDebug() << "Got it";
m_synchroneRenderWaitConditionMutex->unlock();
if ( m_synchroneRenderingBuffer == NULL )
return MainWorkflow::blackOutput;
return m_synchroneRenderingBuffer;
return m_outputBuffers;
}
void MainWorkflow::cancelSynchronisation()
......@@ -371,14 +212,14 @@ void MainWorkflow::cancelSynchronisation()
m_synchroneRenderWaitCondition->wakeAll();
}
void MainWorkflow::muteTrack( unsigned int trackId )
void MainWorkflow::muteTrack( unsigned int trackId, TrackWorkflow::TrackType trackType )
{
m_tracks[trackId].setHardDeactivation( true );
m_tracks[trackType]->muteTrack( trackId );
}
void MainWorkflow::unmuteTrack( unsigned int trackId )
void MainWorkflow::unmuteTrack( unsigned int trackId, TrackWorkflow::TrackType trackType )
{
m_tracks[trackId].setHardDeactivation( false );
m_tracks[trackType]->unmuteTrack( trackId );
}
void MainWorkflow::setCurrentFrame( qint64 currentFrame )
......@@ -387,133 +228,139 @@ void MainWorkflow::setCurrentFrame( qint64 currentFrame )
emit positionChanged( (float)m_currentFrame / (float)m_length );
}
void MainWorkflow::activateTrack( unsigned int trackId )
{
if ( m_tracks[trackId]->getLength() > 0 )
m_tracks[trackId].activate();
else
m_tracks[trackId].deactivate();
}
Clip* MainWorkflow::getClip( const QUuid& uuid, unsigned int trackId )
Clip* MainWorkflow::getClip( const QUuid& uuid, unsigned int trackId, TrackWorkflow::TrackType trackType )
{
Q_ASSERT( trackId < m_trackCount );
return m_tracks[trackId]->getClip( uuid );
return m_tracks[trackType]->getClip( uuid, trackId );
}
void MainWorkflow::loadProject( const QDomElement& project )
{
if ( project.isNull() == true || project.tagName() != "timeline" )
{
qWarning() << "Invalid timeline node (" << project.tagName() << ')';
return ;
}
clear();
QDomElement elem = project.firstChild().toElement();
while ( elem.isNull() == false )
{
bool ok;
Q_ASSERT( elem.tagName() == "track" );
unsigned int trackId = elem.attribute( "id" ).toUInt( &ok );
if ( ok == false )
{
qWarning() << "Invalid track number in project file";
return ;
}
QDomElement clip = elem.firstChild().toElement();
while ( clip.isNull() == false )
{
//Iterate over clip fields:
QDomElement clipProperty = clip.firstChild().toElement();
QUuid parent;
qint64 begin;
qint64 end;
qint64 startPos;
while ( clipProperty.isNull() == false )
{
QString tagName = clipProperty.tagName();
bool ok;
if ( tagName == "parent" )
parent = QUuid( clipProperty.text() );
else if ( tagName == "begin" )
{
begin = clipProperty.text().toLongLong( &ok );
if ( ok == false )
{
qWarning() << "Invalid clip begin";
return ;
}
}
else if ( tagName == "end" )
{
end = clipProperty.text().toLongLong( &ok );
if ( ok == false )
{
qWarning() << "Invalid clip end";
return ;
}
}
else if ( tagName == "startFrame" )
{
startPos = clipProperty.text().toLongLong( &ok );
if ( ok == false )
{
qWarning() << "Invalid clip starting frame";
return ;
}
}
else
qDebug() << "Unknown field" << clipProperty.tagName();
clipProperty = clipProperty.nextSibling().toElement();
}
Clip* c = new Clip( parent, begin, end );
addClip( c, trackId, startPos );
clip = clip.nextSibling().toElement();
}
elem = elem.nextSibling().toElement();
}
// if ( project.isNull() == true || project.tagName() != "timeline" )
// {
// qWarning() << "Invalid timeline node (" << project.tagName() << ')';
// return ;
// }
//
// clear();
//
// QDomElement elem = project.firstChild().toElement();
//
// while ( elem.isNull() == false )
// {
// bool ok;
//
// Q_ASSERT( elem.tagName() == "track" );
// unsigned int trackId = elem.attribute( "id" ).toUInt( &ok );
// if ( ok == false )
// {
// qWarning() << "Invalid track number in project file";
// return ;
// }
// QDomElement clip = elem.firstChild().toElement();
// while ( clip.isNull() == false )
// {
// //Iterate over clip fields:
// QDomElement clipProperty = clip.firstChild().toElement();
// QUuid parent;
// qint64 begin;
// qint64 end;
// qint64 startPos;
//
// while ( clipProperty.isNull() == false )
// {
// QString tagName = clipProperty.tagName();
// bool ok;
//
// if ( tagName == "parent" )
// parent = QUuid( clipProperty.text() );
// else if ( tagName == "begin" )
// {
// begin = clipProperty.text().toLongLong( &ok );
// if ( ok == false )
// {
// qWarning() << "Invalid clip begin";
// return ;
// }
// }
// else if ( tagName == "end" )
// {
// end = clipProperty.text().toLongLong( &ok );
// if ( ok == false )
// {
// qWarning() << "Invalid clip end";
// return ;
// }
// }
// else if ( tagName == "startFrame" )
// {
// startPos = clipProperty.text().toLongLong( &ok );
// if ( ok == false )
// {
// qWarning() << "Invalid clip starting frame";
// return ;
// }
// }
// else
// qDebug() << "Unknown field" << clipProperty.tagName();
//
// clipProperty = clipProperty.nextSibling().toElement();
// }
//
// Clip* c = new Clip( parent, begin, end );
// addClip( c, trackId, startPos, TrackWorkflow::Video );
//
// clip = clip.nextSibling().toElement();
// }
// elem = elem.nextSibling().toElement();
// }
}
void MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
{
QDomElement project = doc.createElement( "timeline" );
for ( unsigned int i = 0; i < m_trackCount; ++i )
{
if ( m_tracks[i]->getLength() > 0 )
{
QDomElement trackNode = doc.createElement( "track" );
trackNode.setAttribute( "id", i );
m_tracks[i]->save( doc, trackNode );
project.appendChild( trackNode );
}
}
rootNode.appendChild( project );
// QDomElement project = doc.createElement( "timeline" );
// for ( unsigned int i = 0; i < m_trackCount; ++i )
// {
// if ( m_tracks[i]->getLength() > 0 )
// {
// QDomElement trackNode = doc.createElement( "track" );
//
// trackNode.setAttribute( "id", i );
//
// m_tracks[i]->save( doc, trackNode );
// project.appendChild( trackNode );
// }
// }
// rootNode.appendChild( project );
}
void MainWorkflow::clear()
{
for ( unsigned int i = 0; i < m_trackCount; ++i )
{
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->clear();
}
m_length = 0;
emit cleared();
}
void MainWorkflow::setFullSpeedRender( bool value )
{
for ( unsigned int i = 0; i < m_trackCount; ++i )
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
m_tracks[i]->setFullSpeedRender( value );
}
void MainWorkflow::tracksPaused()
{
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
if ( m_tracks[i]->isPaused() == false )
return ;
emit mainWorkflowPaused();
}
void MainWorkflow::tracksRenderCompleted()
{
for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
if ( m_tracks[i]->allTracksRendered() == false )
return ;
{
QMutexLocker lock( m_synchroneRenderWaitConditionMutex );
}
m_synchroneRenderWaitCondition->wakeAll();
}
......@@ -28,23 +28,27 @@
#include <QReadWriteLock>
#include <QMutex>
#include <QDomElement>
#include <QWaitCondition>
#include "Toggleable.hpp"
#include "TrackWorkflow.h"
#include "Singleton.hpp"
#include "TrackWorkflow.h"
#include "TrackHandler.h"
#include "Clip.h"
class MainWorkflow : public QObject, public Singleton<MainWorkflow>
{
Q_OBJECT
public:
MainWorkflow( int trackCount );
~MainWorkflow();
void addClip( Clip* clip, unsigned int trackId, qint64 start );
struct OutputBuffers
{
unsigned char* video;
unsigned char* audio;
};
void addClip( Clip* clip, unsigned int trackId, qint64 start, TrackWorkflow::TrackType type );
void startRender();
void getOutput();
unsigned char* getSynchroneOutput();
OutputBuffers* getSynchroneOutput();
/**
* \brief Set the workflow position
......@@ -64,11 +68,6 @@ class MainWorkflow : public QObject, public Singleton<MainWorkflow>
*/
qint64 getLength() const;
/**
* Returns the number of tracks in this workflow
*/
unsigned int getTrackCount() const;
/**
* Stop the workflow (including sub track workflows and clip workflows)
*/
......@@ -83,12 +82,11 @@ class MainWorkflow : public QObject, public Singleton<MainWorkflow>
void nextFrame();
void previousFrame();
static MainWorkflow* getInstance();
static void deleteInstance();
Clip* removeClip( const QUuid& uuid, unsigned int trackId );
Clip* removeClip( const QUuid& uuid, unsigned int trackId, TrackWorkflow::TrackType trackType );
void moveClip( const QUuid& uuid, unsigned int oldTrack,
unsigned int newTrack, qint64 pos, bool undoRedoCommand = false );
qint64 getClipPosition( const QUuid& uuid, unsigned int trackId ) const;
unsigned int newTrack, qint64 pos,
TrackWorkflow::TrackType trackType, bool undoRedoCommand = false );