MainWorkflow.cpp 13.5 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 36
LightVideoFrame*     MainWorkflow::blackOutput = NULL;

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

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

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

    blackOutput = new LightVideoFrame( VIDEOHEIGHT * VIDEOWIDTH * Pixel::NbComposantes );
    memset( (*blackOutput)->frame.octets, 0, (*blackOutput)->nboctets );
64 65 66 67
}

MainWorkflow::~MainWorkflow()
{
68
    //FIXME: this is probably useless, since already done by the renderer
69 70
    stop();

71
    delete m_effectEngine;
72 73 74
    delete m_synchroneRenderWaitConditionMutex;
    delete m_synchroneRenderWaitCondition;
    delete m_renderMutex;
75
    delete m_renderStartedLock;
76
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
77
        delete m_tracks[i];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
78
    delete[] m_tracks;
79 80
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
81
EffectsEngine*          MainWorkflow::getEffectsEngine()
82
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
83
    return m_effectEngine;
84
}
85

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86
void            MainWorkflow::addClip( Clip* clip, unsigned int trackId,
87
                                        qint64 start, MainWorkflow::TrackType trackType )
88
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
89
    m_tracks[trackType]->addClip( clip, trackId, start );
90
    computeLength();
91

92
    //Inform the GUI
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
93
    emit clipAdded( clip, trackId, start, trackType );
94
}
95

96
void            MainWorkflow::computeLength()
97
{
98 99
    qint64      maxLength = 0;

100
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
101 102 103 104
    {
        if ( m_tracks[i]->getLength() > maxLength )
            maxLength = m_tracks[i]->getLength();
    }
105
    m_lengthFrame = maxLength;
106 107
}

108 109 110
void    MainWorkflow::startRender()
{
    m_renderStarted = true;
111
    m_paused = false;
112
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
113
        m_tracks[i]->startRender();
114 115 116
    computeLength();
}

117
void                    MainWorkflow::getOutput()
118
{
119 120
    QReadLocker         lock( m_renderStartedLock );
    QMutexLocker        lock2( m_renderMutex );
121

122
    if ( m_renderStarted == true )
123
    {
124
        for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
125
            m_tracks[i]->getOutput( m_currentFrame );
126 127
        if ( m_paused == false )
            nextFrame();
128
    }
129
}
130

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

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

139 140 141 142
void        MainWorkflow::unpause()
{
    QMutexLocker    lock( m_renderMutex );

143
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
144
        m_tracks[i]->unpause();
145 146
}

147 148 149 150
void        MainWorkflow::nextFrame()
{
    ++m_currentFrame;
    emit frameChanged( m_currentFrame );
151
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
152 153 154 155 156 157
}

void        MainWorkflow::previousFrame()
{
    --m_currentFrame;
    emit frameChanged( m_currentFrame );
158
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
159 160
}

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

176
qint64      MainWorkflow::getLengthFrame() const
177
{
178
    return m_lengthFrame;
179
}
180

181
qint64      MainWorkflow::getClipPosition( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType ) const
182
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
183
    return m_tracks[trackType]->getClipPosition( uuid, trackId );
184
}
185 186 187 188 189 190

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

    m_renderStarted = false;
191
    for (unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
192
        m_tracks[i]->stop();
193 194
    m_currentFrame = 0;
    emit frameChanged( 0 );
195
    emit positionChanged( 0 );
196
}
197

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

210
Clip*       MainWorkflow::removeClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
211
{
212 213
    Clip* clip = m_tracks[trackType]->removeClip( uuid, trackId );
    computeLength();
214
    emit clipRemoved( clip, trackId, trackType );
215
    return clip;
216 217
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
218
MainWorkflow::OutputBuffers*  MainWorkflow::getSynchroneOutput()
219 220 221
{
    m_synchroneRenderWaitConditionMutex->lock();
    getOutput();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
222
//    qDebug() << "Waiting for sync output";
223
    m_synchroneRenderWaitCondition->wait( m_synchroneRenderWaitConditionMutex );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
224
//    qDebug() << "Got it";
225
    m_effectEngine->render();
226 227 228 229 230
    if ( m_effectEngine->getOutputFrame( 0 )->nboctets == 0 )
        m_outputBuffers->video = MainWorkflow::blackOutput;
    else
        m_outputBuffers->video = &( m_effectEngine->getOutputFrame( 0 ) );

231
    m_synchroneRenderWaitConditionMutex->unlock();
232 233

    //    m_outputBuffers->video = reinterpret_cast<LightVideoFrame*>( m_tracks[TrackWorkflow::Video]->getSynchroneOutput() );
234
//    m_outputBuffers->audio = reinterpret_cast<unsigned char*>( m_tracks[TrackWorkflow::Audio]->getSynchroneOutput() );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
235
    return m_outputBuffers;
236
}
237 238 239 240 241 242 243 244

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

246
void        MainWorkflow::muteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
247
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
248
    m_tracks[trackType]->muteTrack( trackId );
249 250
}

251
void        MainWorkflow::unmuteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
252
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
253
    m_tracks[trackType]->unmuteTrack( trackId );
254
}
255 256 257 258

void        MainWorkflow::setCurrentFrame( qint64 currentFrame )
{
    m_currentFrame = currentFrame;
259
    emit positionChanged( (float)m_currentFrame / (float)m_lengthFrame );
260
}
261

262
Clip*       MainWorkflow::getClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
263
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
264
    return m_tracks[trackType]->getClip( uuid, trackId );
265
}
266 267 268

void        MainWorkflow::loadProject( const QDomElement& project )
{
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
    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;
299
            MainWorkflow::TrackType     trackType = MainWorkflow::VideoTrack;
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

            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" )
                {
337
                    trackType = static_cast<MainWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
                    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();
    }
357 358
}

359
void        MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
360
{
361
    QDomElement project = doc.createElement( "timeline" );
362
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
363 364 365 366
    {
        m_tracks[i]->save( doc, project );
    }
    rootNode.appendChild( project );
367
}
368 369 370

void        MainWorkflow::clear()
{
371
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
372
        m_tracks[i]->clear();
373
    emit cleared();
374
}
375 376 377

void        MainWorkflow::setFullSpeedRender( bool value )
{
378
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
379 380
        m_tracks[i]->setFullSpeedRender( value );
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
381 382 383

void        MainWorkflow::tracksPaused()
{
384
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
385 386
        if ( m_tracks[i]->isPaused() == false )
            return ;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
387
    m_paused = true;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
388 389 390
    emit mainWorkflowPaused();
}

391 392 393 394 395 396 397 398
void        MainWorkflow::tracksEndReached()
{
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        if ( m_tracks[i]->endIsReached() == false )
            return ;
    emit mainWorkflowEndReached();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
399 400
void        MainWorkflow::tracksUnpaused()
{
401
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
402 403 404 405 406 407
        if ( m_tracks[i]->isPaused() == true )
            return ;
    m_paused = false;
    emit mainWorkflowUnpaused();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
408 409
void        MainWorkflow::tracksRenderCompleted()
{
410
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
411 412 413 414 415 416 417
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
418

419
int         MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
420 421 422
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
423

424 425 426 427
qint64      MainWorkflow::getCurrentFrame() const
{
    return m_currentFrame;
}