MainWorkflow.cpp 12.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*****************************************************************************
 * MainWorkflow.cpp : Will query all of the track workflows to render the final
 *                    image
 *****************************************************************************
 * Copyright (C) 2008-2009 the VLMC team
 *
 * Authors: Hugo Beauzee-Luyssen <hugo@vlmc.org>
 *
 * 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.
 *****************************************************************************/

#include <QtDebug>

#include "MainWorkflow.h"
27 28
#include "TrackWorkflow.h"
#include "TrackHandler.h"
29

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
30 31 32 33 34
//JUST FOR THE DEFINES !
//TODO:
//FIXME: remove this !
#include "ClipWorkflow.h"

35
MainWorkflow::MainWorkflow( int trackCount ) :
36
        m_currentFrame( 0 ),
37
        m_lengthFrame( 0 ),
38
        m_renderStarted( false )
39
{
40
    m_renderStartedLock = new QReadWriteLock;
41
    m_renderMutex = new QMutex;
42 43
    m_synchroneRenderWaitCondition = new QWaitCondition;
    m_synchroneRenderWaitConditionMutex = new QMutex;
44 45 46 47

    m_effectEngine = new EffectsEngine;
    m_effectEngine->disable();

48 49
    m_tracks = new TrackHandler*[MainWorkflow::NbTrackType];
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
50
    {
51
        MainWorkflow::TrackType trackType = (i == 0 ? MainWorkflow::VideoTrack : MainWorkflow::AudioTrack );
52
        m_tracks[i] = new TrackHandler( trackCount, trackType, m_effectEngine );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
53
        connect( m_tracks[i], SIGNAL( tracksPaused() ), this, SLOT( tracksPaused() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
54
        connect( m_tracks[i], SIGNAL( tracksUnpaused() ), this, SLOT( tracksUnpaused() ) );
55
        connect( m_tracks[i], SIGNAL( allTracksRenderCompleted() ), this, SLOT( tracksRenderCompleted() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
56 57
    }
    m_outputBuffers = new OutputBuffers;
58 59 60 61
}

MainWorkflow::~MainWorkflow()
{
62
    //FIXME: this is probably useless, since already done by the renderer
63 64
    stop();

65
    delete m_effectEngine;
66 67 68
    delete m_synchroneRenderWaitConditionMutex;
    delete m_synchroneRenderWaitCondition;
    delete m_renderMutex;
69
    delete m_renderStartedLock;
70
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
71
        delete m_tracks[i];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
72
    delete[] m_tracks;
73 74
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
75
EffectsEngine*          MainWorkflow::getEffectsEngine()
76
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
77
    return m_effectEngine;
78
}
79

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
80
void            MainWorkflow::addClip( Clip* clip, unsigned int trackId,
81
                                        qint64 start, MainWorkflow::TrackType trackType )
82
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
83
    m_tracks[trackType]->addClip( clip, trackId, start );
84
    computeLength();
85

86
    //Inform the GUI
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
87
    emit clipAdded( clip, trackId, start, trackType );
88
}
89

90
void            MainWorkflow::computeLength()
91
{
92 93
    qint64      maxLength = 0;

94
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
95 96 97 98
    {
        if ( m_tracks[i]->getLength() > maxLength )
            maxLength = m_tracks[i]->getLength();
    }
99
    m_lengthFrame = maxLength;
100 101
}

102 103 104
void    MainWorkflow::startRender()
{
    m_renderStarted = true;
105
    m_paused = false;
106
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
107
        m_tracks[i]->startRender();
108 109 110
    computeLength();
}

111
void                    MainWorkflow::getOutput()
112
{
113 114
    QReadLocker         lock( m_renderStartedLock );
    QMutexLocker        lock2( m_renderMutex );
115

116
    if ( m_renderStarted == true )
117
    {
118
        for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
119
            m_tracks[i]->getOutput( m_currentFrame );
120 121
        if ( m_paused == false )
            nextFrame();
122
    }
123
}
124

125 126
void        MainWorkflow::pause()
{
127 128
    QMutexLocker    lock( m_renderMutex );

129
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
130
        m_tracks[i]->pause();
131 132
}

133 134 135 136
void        MainWorkflow::unpause()
{
    QMutexLocker    lock( m_renderMutex );

137
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
138
        m_tracks[i]->unpause();
139 140
}

141 142 143 144
void        MainWorkflow::nextFrame()
{
    ++m_currentFrame;
    emit frameChanged( m_currentFrame );
145
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
146 147 148 149 150 151
}

void        MainWorkflow::previousFrame()
{
    --m_currentFrame;
    emit frameChanged( m_currentFrame );
152
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
153 154
}

155 156
void        MainWorkflow::setPosition( float pos )
{
157 158 159 160
    if ( m_renderStarted == true )
    {
        //Since any track can be reactivated, we reactivate all of them, and let them
        //unable themself if required.
161
        for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
162
            m_tracks[i]->activateAll();
163
    }
164
    qint64  frame = static_cast<qint64>( (float)m_lengthFrame * pos );
165 166
    m_currentFrame = frame;
    emit frameChanged( frame );
167
    //Do not emit a signal for the RenderWidget, since it's the one that triggered that call...
168 169
}

170
qint64      MainWorkflow::getLengthFrame() const
171
{
172
    return m_lengthFrame;
173
}
174

175
qint64      MainWorkflow::getClipPosition( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType ) const
176
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
177
    return m_tracks[trackType]->getClipPosition( uuid, trackId );
178
}
179 180 181 182 183 184

void            MainWorkflow::stop()
{
    QWriteLocker    lock( m_renderStartedLock );

    m_renderStarted = false;
185
    for (unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
186
        m_tracks[i]->stop();
187 188
    m_currentFrame = 0;
    emit frameChanged( 0 );
189
    emit positionChanged( 0 );
190
}
191

192
void           MainWorkflow::moveClip( const QUuid& clipUuid, unsigned int oldTrack,
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
193
                                       unsigned int newTrack, qint64 startingFrame,
194
                                       MainWorkflow::TrackType trackType, bool undoRedoCommand /*= false*/ )
195
{
196
    m_tracks[trackType]->moveClip( clipUuid, oldTrack, newTrack, startingFrame );
197
    computeLength();
198 199 200 201
    if ( undoRedoCommand == true )
    {
        emit clipMoved( clipUuid, newTrack, startingFrame, trackType );
    }
202
}
203

204
Clip*       MainWorkflow::removeClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
205
{
206
    emit clipRemoved( uuid, trackId, trackType );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
207
    return m_tracks[trackType]->removeClip( uuid, trackId );
208 209
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
210
MainWorkflow::OutputBuffers*  MainWorkflow::getSynchroneOutput()
211 212 213
{
    m_synchroneRenderWaitConditionMutex->lock();
    getOutput();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
214
//    qDebug() << "Waiting for sync output";
215
    m_synchroneRenderWaitCondition->wait( m_synchroneRenderWaitConditionMutex );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
216
//    qDebug() << "Got it";
217
    m_effectEngine->render();
218
    m_synchroneRenderWaitConditionMutex->unlock();
219 220 221
    m_outputBuffers->video = &( m_effectEngine->getOutputFrame( 0 ) );
//    m_outputBuffers->video = reinterpret_cast<LightVideoFrame*>( m_tracks[TrackWorkflow::Video]->getSynchroneOutput() );
//    m_outputBuffers->audio = reinterpret_cast<unsigned char*>( m_tracks[TrackWorkflow::Audio]->getSynchroneOutput() );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
222
    return m_outputBuffers;
223
}
224 225 226 227 228 229 230 231

void        MainWorkflow::cancelSynchronisation()
{
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
232

233
void        MainWorkflow::muteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
234
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
235
    m_tracks[trackType]->muteTrack( trackId );
236 237
}

238
void        MainWorkflow::unmuteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
239
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
240
    m_tracks[trackType]->unmuteTrack( trackId );
241
}
242 243 244 245

void        MainWorkflow::setCurrentFrame( qint64 currentFrame )
{
    m_currentFrame = currentFrame;
246
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
247
}
248

249
Clip*       MainWorkflow::getClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
250
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
251
    return m_tracks[trackType]->getClip( uuid, trackId );
252
}
253 254 255

void        MainWorkflow::loadProject( const QDomElement& project )
{
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    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;
286
            MainWorkflow::TrackType     trackType = MainWorkflow::VideoTrack;
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323

            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 if ( tagName == "trackType" )
                {
324
                    trackType = static_cast<MainWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
                    if ( ok == false )
                    {
                        qWarning() << "Invalid track type starting frame";
                        return ;
                    }
                }
                else
                    qDebug() << "Unknown field" << clipProperty.tagName();

                clipProperty = clipProperty.nextSibling().toElement();
            }

            Clip*       c = new Clip( parent, begin, end );
            addClip( c, trackId, startPos, trackType );

            clip = clip.nextSibling().toElement();
        }
        elem = elem.nextSibling().toElement();
    }
344 345
}

346
void        MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
347
{
348
    QDomElement project = doc.createElement( "timeline" );
349
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
350 351 352 353
    {
        m_tracks[i]->save( doc, project );
    }
    rootNode.appendChild( project );
354
}
355 356 357

void        MainWorkflow::clear()
{
358
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
359
        m_tracks[i]->clear();
360
    emit cleared();
361
}
362 363 364

void        MainWorkflow::setFullSpeedRender( bool value )
{
365
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
366 367
        m_tracks[i]->setFullSpeedRender( value );
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
368 369 370

void        MainWorkflow::tracksPaused()
{
371
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
372 373
        if ( m_tracks[i]->isPaused() == false )
            return ;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
374
    m_paused = true;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
375 376 377
    emit mainWorkflowPaused();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
378 379
void        MainWorkflow::tracksUnpaused()
{
380
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
381 382 383 384 385 386
        if ( m_tracks[i]->isPaused() == true )
            return ;
    m_paused = false;
    emit mainWorkflowUnpaused();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
387 388
void        MainWorkflow::tracksRenderCompleted()
{
389
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
390 391 392 393 394 395 396
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
397

398
int         MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
399 400 401
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
402

403 404 405 406
qint64      MainWorkflow::getCurrentFrame() const
{
    return m_currentFrame;
}