MainWorkflow.cpp 13.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
/*****************************************************************************
 * 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
#include "Library.h"
30

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

36
37
LightVideoFrame*     MainWorkflow::blackOutput = NULL;

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

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

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

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
84
EffectsEngine*          MainWorkflow::getEffectsEngine()
85
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86
    return m_effectEngine;
87
}
88

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
89
void            MainWorkflow::addClip( Clip* clip, unsigned int trackId,
90
                                        qint64 start, MainWorkflow::TrackType trackType )
91
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
92
    m_tracks[trackType]->addClip( clip, trackId, start );
93
    computeLength();
94
    //Inform the GUI
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
95
    emit clipAdded( clip, trackId, start, trackType );
96
}
97

98
void            MainWorkflow::computeLength()
99
{
100
101
    qint64      maxLength = 0;

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

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

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

124
    if ( m_renderStarted == true )
125
    {
126
127
128
129
130
131
        {
            QReadLocker         lock3( m_currentFrameLock );

            for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
                m_tracks[i]->getOutput( m_currentFrame );
        }
132
133
        if ( m_paused == false )
            nextFrame();
134
    }
135
}
136

137
138
void        MainWorkflow::pause()
{
139
140
    QMutexLocker    lock( m_renderMutex );

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

145
146
147
148
void        MainWorkflow::unpause()
{
    QMutexLocker    lock( m_renderMutex );

149
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
150
        m_tracks[i]->unpause();
151
152
}

153
154
void        MainWorkflow::nextFrame()
{
155
    QWriteLocker    lock( m_currentFrameLock );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
156

157
    ++m_currentFrame;
158
    emit frameChanged( m_currentFrame, Renderer );
159
160
161
162
}

void        MainWorkflow::previousFrame()
{
163
164
    QWriteLocker    lock( m_currentFrameLock );

165
    --m_currentFrame;
166
    emit frameChanged( m_currentFrame, Renderer );
167
168
}

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

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

void            MainWorkflow::stop()
{
    QWriteLocker    lock( m_renderStartedLock );
182
    QWriteLocker    lock2( m_currentFrameLock );
183
184

    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
    m_currentFrame = 0;
188
    emit frameChanged( 0, Renderer );
189
}
190

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

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
207
    Clip* clip = m_tracks[trackType]->removeClip( uuid, trackId );
    computeLength();
208
    emit clipRemoved( clip, trackId, trackType );
209
    return clip;
210
211
}

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

225
    m_synchroneRenderWaitConditionMutex->unlock();
226
227

    //    m_outputBuffers->video = reinterpret_cast<LightVideoFrame*>( m_tracks[TrackWorkflow::Video]->getSynchroneOutput() );
228
//    m_outputBuffers->audio = reinterpret_cast<unsigned char*>( m_tracks[TrackWorkflow::Audio]->getSynchroneOutput() );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
229
    return m_outputBuffers;
230
}
231
232
233
234
235
236
237
238

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

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

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

250
void        MainWorkflow::setCurrentFrame( qint64 currentFrame, MainWorkflow::FrameChangedReason reason )
251
{
252
253
    QWriteLocker    lock( m_currentFrameLock );

254
255
256
257
258
259
260
    if ( m_renderStarted == true )
    {
        //Since any track can be reactivated, we reactivate all of them, and let them
        //unable themself if required.
        for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
            m_tracks[i]->activateAll();
    }
261
    m_currentFrame = currentFrame;
262
    emit frameChanged( m_currentFrame, reason );
263
}
264

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

270
271
272
/**
 *  \warning    The mainworkflow is expected to be cleared already by the ProjectManager
 */
273
274
void        MainWorkflow::loadProject( const QDomElement& project )
{
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
    if ( project.isNull() == true || project.tagName() != "timeline" )
    {
        qWarning() << "Invalid timeline node (" << project.tagName() << ')';
        return ;
    }

    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;
303
            MainWorkflow::TrackType     trackType = MainWorkflow::VideoTrack;
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

            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" )
                {
341
                    trackType = static_cast<MainWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
342
343
344
345
346
347
348
349
350
351
352
353
                    if ( ok == false )
                    {
                        qWarning() << "Invalid track type starting frame";
                        return ;
                    }
                }
                else
                    qDebug() << "Unknown field" << clipProperty.tagName();

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

354
355
356
357
358
            if ( Library::getInstance()->getMedia( parent ) != NULL )
            {
                Clip*       c = new Clip( parent, begin, end );
                addClip( c, trackId, startPos, trackType );
            }
359
360
361
362
363

            clip = clip.nextSibling().toElement();
        }
        elem = elem.nextSibling().toElement();
    }
364
365
}

366
void        MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
367
{
368
    QDomElement project = doc.createElement( "timeline" );
369
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
370
371
372
373
    {
        m_tracks[i]->save( doc, project );
    }
    rootNode.appendChild( project );
374
}
375
376
377

void        MainWorkflow::clear()
{
378
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
379
        m_tracks[i]->clear();
380
    emit cleared();
381
}
382
383
384

void        MainWorkflow::setFullSpeedRender( bool value )
{
385
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
386
387
        m_tracks[i]->setFullSpeedRender( value );
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
388
389
390

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

398
399
400
401
402
403
404
405
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
406
407
void        MainWorkflow::tracksUnpaused()
{
408
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
409
410
411
412
413
414
        if ( m_tracks[i]->isPaused() == true )
            return ;
    m_paused = false;
    emit mainWorkflowUnpaused();
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
415
416
void        MainWorkflow::tracksRenderCompleted()
{
417
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
418
419
420
421
422
423
424
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
425

426
int         MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
427
428
429
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
430

431
432
qint64      MainWorkflow::getCurrentFrame() const
{
433
434
    QReadLocker     lock( m_currentFrameLock );

435
436
    return m_currentFrame;
}