MainWorkflow.cpp 13.2 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() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
58 59
    }
    m_outputBuffers = new OutputBuffers;
60 61 62

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

230
    m_synchroneRenderWaitConditionMutex->unlock();
231 232

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

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

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

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

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

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

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

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

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

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
390 391
void        MainWorkflow::tracksUnpaused()
{
392
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
393 394 395 396 397 398
        if ( m_tracks[i]->isPaused() == true )
            return ;
    m_paused = false;
    emit mainWorkflowUnpaused();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
399 400
void        MainWorkflow::tracksRenderCompleted()
{
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 408
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
409

410
int         MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
411 412 413
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
414

415 416 417 418
qint64      MainWorkflow::getCurrentFrame() const
{
    return m_currentFrame;
}