MainWorkflow.cpp 12.7 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 27
/*****************************************************************************
 * 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"

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

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

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

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

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

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

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

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

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

88
void            MainWorkflow::computeLength()
89
{
90 91
    qint64      maxLength = 0;

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
92
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
93 94 95 96
    {
        if ( m_tracks[i]->getLength() > maxLength )
            maxLength = m_tracks[i]->getLength();
    }
97
    m_lengthFrame = maxLength;
98 99
}

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

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

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

123 124
void        MainWorkflow::pause()
{
125 126
    QMutexLocker    lock( m_renderMutex );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
127 128
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        m_tracks[i]->pause();
129 130
}

131 132 133 134
void        MainWorkflow::unpause()
{
    QMutexLocker    lock( m_renderMutex );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
135 136
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        m_tracks[i]->unpause();
137 138
}

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

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

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

168
qint64      MainWorkflow::getLengthFrame() const
169
{
170
    return m_lengthFrame;
171
}
172

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

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

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
208
MainWorkflow::OutputBuffers*  MainWorkflow::getSynchroneOutput()
209 210 211
{
    m_synchroneRenderWaitConditionMutex->lock();
    getOutput();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
212
//    qDebug() << "Waiting for sync output";
213
    m_synchroneRenderWaitCondition->wait( m_synchroneRenderWaitConditionMutex );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
214
//    qDebug() << "Got it";
215
    m_effectEngine->render();
216
    m_synchroneRenderWaitConditionMutex->unlock();
217 218 219
    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
220
    return m_outputBuffers;
221
}
222 223 224 225 226 227 228 229

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

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

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

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

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

void        MainWorkflow::loadProject( const QDomElement& project )
{
254 255 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 286 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 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    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;
            TrackWorkflow::TrackType    trackType = TrackWorkflow::Video;

            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" )
                {
                    trackType = static_cast<TrackWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
                    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();
    }
342 343
}

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

void        MainWorkflow::clear()
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
356
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
357
        m_tracks[i]->clear();
358
    emit cleared();
359
}
360 361 362

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
385 386 387 388 389 390 391 392 393 394
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();
}
395 396 397 398 399

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

401 402 403 404
qint64      MainWorkflow::getCurrentFrame() const
{
    return m_currentFrame;
}