MainWorkflow.cpp 13.9 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
/*****************************************************************************
 * 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>

Ludovic Fauvet's avatar
Ludovic Fauvet committed
26
#include "vlmc.h"
27
28
29
30
#include "Clip.h"
#include "EffectsEngine.h"
#include "Library.h"
#include "LightVideoFrame.h"
31
#include "MainWorkflow.h"
32
33
#include "TrackWorkflow.h"
#include "TrackHandler.h"
34
#include "SettingsManager.h"
35
36

#include <QDomElement>
37

38
LightVideoFrame     *MainWorkflow::blackOutput = NULL;
39

40
MainWorkflow::MainWorkflow( int trackCount ) :
41
        m_lengthFrame( 0 ),
42
        m_renderStarted( false )
43
{
44
    m_currentFrameLock = new QReadWriteLock;
45
    m_renderStartedLock = new QReadWriteLock;
46

47
48
49
50
    const SettingValue  *width = SettingsManager::getInstance()->getValue( "project",
                                                                    "VideoProjectWidth" );
    connect( width,     SIGNAL( changed( QVariant ) ),
             this,      SLOT( widthChanged( QVariant ) ) );
51
    m_width = width->get().toUInt();
52
53
54
55
    const SettingValue  *height = SettingsManager::getInstance()->getValue( "project",
                                                                "VideoProjectHeight" );
    connect( height, SIGNAL( changed( QVariant ) ),
             this, SLOT( widthChanged( QVariant ) ) );
56
57
    m_height = height->get().toUInt();

58
59
60
    m_effectEngine = new EffectsEngine;
    m_effectEngine->disable();

61
    m_tracks = new TrackHandler*[MainWorkflow::NbTrackType];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
62
    m_currentFrame = new qint64[MainWorkflow::NbTrackType];
63
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
64
    {
65
66
        MainWorkflow::TrackType trackType =
                (i == 0 ? MainWorkflow::VideoTrack : MainWorkflow::AudioTrack );
67
        m_tracks[i] = new TrackHandler( trackCount, trackType, m_effectEngine );
68
69
        connect( m_tracks[i], SIGNAL( tracksEndReached() ),
                 this, SLOT( tracksEndReached() ) );
70
        m_currentFrame[i] = 0;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
71
72
    }
    m_outputBuffers = new OutputBuffers;
73
74
75

    blackOutput = new LightVideoFrame( m_width * m_height * Pixel::NbComposantes );
    memset( (*blackOutput)->frame.octets, 0, (*blackOutput)->nboctets );
76
77
78
79
}

MainWorkflow::~MainWorkflow()
{
80
    //FIXME: this is probably useless, since already done by the renderer
81
82
    stop();

83
    delete m_effectEngine;
84
    delete m_renderStartedLock;
85
    delete m_currentFrameLock;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86
    delete m_currentFrame;
87
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
88
        delete m_tracks[i];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
89
    delete[] m_tracks;
90
91
}

92
93
EffectsEngine*
MainWorkflow::getEffectsEngine()
94
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
95
    return m_effectEngine;
96
}
97

98
99
void
MainWorkflow::addClip( Clip *clip, unsigned int trackId,
100
                                        qint64 start, MainWorkflow::TrackType trackType )
101
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
102
    m_tracks[trackType]->addClip( clip, trackId, start );
103
    computeLength();
104
    //Inform the GUI
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
105
    emit clipAdded( clip, trackId, start, trackType );
106
}
107

108
109
void
MainWorkflow::computeLength()
110
{
111
112
    qint64      maxLength = 0;

113
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
114
115
116
117
    {
        if ( m_tracks[i]->getLength() > maxLength )
            maxLength = m_tracks[i]->getLength();
    }
118
119
120
121
122
123
    if ( m_lengthFrame != maxLength )
    {
        m_lengthFrame = maxLength;
        emit lengthChanged( m_lengthFrame );
    }

124
125
}

126
127
void
MainWorkflow::startRender()
128
129
{
    m_renderStarted = true;
130
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
131
        m_tracks[i]->startRender();
132
133
134
    computeLength();
}

135
136
MainWorkflow::OutputBuffers*
MainWorkflow::getOutput( TrackType trackType )
137
{
138
    QReadLocker         lock( m_renderStartedLock );
139

140
    if ( m_renderStarted == true )
141
    {
142
        QReadLocker         lock2( m_currentFrameLock );
143

144
145
        m_tracks[trackType]->getOutput( m_currentFrame[VideoTrack],
                                        m_currentFrame[trackType] );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
146
        if ( trackType == MainWorkflow::VideoTrack )
147
        {
148
            m_effectEngine->setCurrentFrameNumber( m_currentFrame[VideoTrack] );
149
150
            m_effectEngine->render();
            const LightVideoFrame &tmp = m_effectEngine->getVideoOutput( 1 );
151
            m_outputBuffers->video = &tmp;
152
        }
153
154
        else
        {
155
156
            m_outputBuffers->audio =
                    m_tracks[MainWorkflow::AudioTrack]->getTmpAudioBuffer();
157
        }
158
    }
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
159
    return m_outputBuffers;
160
}
161

162
163
void
MainWorkflow::pause()
164
{
165
166
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->pause();
167
    emit mainWorkflowPaused();
168
169
}

170
171
void
MainWorkflow::unpause()
172
{
173
174
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->unpause();
175
    emit mainWorkflowUnpaused();
176
177
}

178
179
void
MainWorkflow::nextFrame( MainWorkflow::TrackType trackType )
180
{
181
    QWriteLocker    lock( m_currentFrameLock );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
182

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
183
184
185
    ++m_currentFrame[trackType];
    if ( trackType == MainWorkflow::VideoTrack )
        emit frameChanged( m_currentFrame[MainWorkflow::VideoTrack], Renderer );
186
187
}

188
189
void
MainWorkflow::previousFrame( MainWorkflow::TrackType trackType )
190
{
191
    QWriteLocker    lock( m_currentFrameLock );
192

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
193
194
195
    --m_currentFrame[trackType];
    if ( trackType == MainWorkflow::VideoTrack )
        emit frameChanged( m_currentFrame[MainWorkflow::VideoTrack], Renderer );
196
197
}

198
199
qint64
MainWorkflow::getLengthFrame() const
200
{
201
    return m_lengthFrame;
202
}
203

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

211
212
void
MainWorkflow::stop()
213
214
{
    QWriteLocker    lock( m_renderStartedLock );
215
    QWriteLocker    lock2( m_currentFrameLock );
216
217

    m_renderStarted = false;
218
    for (unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
219
    {
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
220
        m_tracks[i]->stop();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
221
222
        m_currentFrame[i] = 0;
    }
223
    emit frameChanged( 0, Renderer );
224
}
225

226
227
228
229
230
void
MainWorkflow::moveClip( const QUuid &clipUuid, unsigned int oldTrack,
                        unsigned int newTrack, qint64 startingFrame,
                        MainWorkflow::TrackType trackType,
                        bool undoRedoCommand /*= false*/ )
231
{
232
    m_tracks[trackType]->moveClip( clipUuid, oldTrack, newTrack, startingFrame );
233
    computeLength();
234

235
236
237
238
    if ( undoRedoCommand == true )
    {
        emit clipMoved( clipUuid, newTrack, startingFrame, trackType );
    }
239
}
240

241
242
243
Clip*
MainWorkflow::removeClip( const QUuid &uuid, unsigned int trackId,
                          MainWorkflow::TrackType trackType )
244
{
245
    Clip *clip = m_tracks[trackType]->removeClip( uuid, trackId );
246
247
248
249
250
    if ( clip != NULL )
    {
        computeLength();
        emit clipRemoved( clip, trackId, trackType );
    }
251
    return clip;
252
253
}

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

260
261
void
MainWorkflow::unmuteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
262
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
263
    m_tracks[trackType]->unmuteTrack( trackId );
264
}
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
void
MainWorkflow::muteClip( const QUuid& uuid, unsigned int trackId,
                        MainWorkflow::TrackType trackType )
{
    qDebug() << "Mute" << uuid ;
}

void
MainWorkflow::unmuteClip( const QUuid& uuid, unsigned int trackId,
                          MainWorkflow::TrackType trackType )
{
    qDebug() << "Unmute" << uuid;
}

280
281
282
283
void toggleBreakPoint()
{
}

284
285
void
MainWorkflow::setCurrentFrame( qint64 currentFrame, MainWorkflow::FrameChangedReason reason )
286
{
287
288
    QWriteLocker    lock( m_currentFrameLock );

289
    toggleBreakPoint();
290
291
292
293
294
295
296
    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();
    }
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
297
298
299
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
        m_currentFrame[i] = currentFrame;
    emit frameChanged( currentFrame, reason );
300
}
301

302
303
304
Clip*
MainWorkflow::getClip( const QUuid &uuid, unsigned int trackId,
                       MainWorkflow::TrackType trackType )
305
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
306
    return m_tracks[trackType]->getClip( uuid, trackId );
307
}
308

309
/**
310
 *  \warning    The mainworkflow is expected to be already cleared by the ProjectManager
311
 */
312
313
void
MainWorkflow::loadProject( const QDomElement &project )
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
342
    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;
343
            MainWorkflow::TrackType     trackType = MainWorkflow::VideoTrack;
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380

            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" )
                {
381
382
                    trackType = static_cast<MainWorkflow::TrackType>(
                                                    clipProperty.text().toUInt( &ok ) );
383
384
385
386
387
388
389
390
391
392
393
394
                    if ( ok == false )
                    {
                        qWarning() << "Invalid track type starting frame";
                        return ;
                    }
                }
                else
                    qDebug() << "Unknown field" << clipProperty.tagName();

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

395
            if ( Library::getInstance()->media( parent ) != NULL )
396
            {
397
                Clip        *c = new Clip( parent, begin, end );
398
399
                addClip( c, trackId, startPos, trackType );
            }
400
401
402
403
404

            clip = clip.nextSibling().toElement();
        }
        elem = elem.nextSibling().toElement();
    }
405
406
}

407
408
void
MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
409
{
410
    QDomElement project = doc.createElement( "timeline" );
411
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
412
413
414
415
    {
        m_tracks[i]->save( doc, project );
    }
    rootNode.appendChild( project );
416
}
417

418
419
void
MainWorkflow::clear()
420
{
421
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
422
        m_tracks[i]->clear();
423
    emit cleared();
424
}
425

426
427
void
MainWorkflow::tracksEndReached()
428
429
{
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
430
    {
431
432
        if ( m_tracks[i]->endIsReached() == false )
            return ;
433
    }
434
435
436
    emit mainWorkflowEndReached();
}

437
438
int
MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
439
440
441
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
442

443
444
qint64
MainWorkflow::getCurrentFrame() const
445
{
446
447
    QReadLocker     lock( m_currentFrameLock );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
448
    return m_currentFrame[MainWorkflow::VideoTrack];
449
}
450

451
452
void
MainWorkflow::widthChanged( const QVariant &width )
453
454
455
456
{
    m_width = width.toUInt();
}

457
458
void
MainWorkflow::heightChanged( const QVariant &height )
459
460
461
462
{
    m_height = height.toUInt();
}

463
464
uint32_t
MainWorkflow::getWidth() const
465
466
467
468
{
    return m_width;
}

469
470
uint32_t
MainWorkflow::getHeight() const
471
472
473
{
    return m_height;
}
474
475
476
477
478
479
480
481
482

void
MainWorkflow::renderOneFrame()
{
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->renderOneFrame();
    nextFrame( VideoTrack );
    nextFrame( AudioTrack );
}
483
484
485
486
487
488
489

void
MainWorkflow::setFullSpeedRender( bool val )
{
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->setFullSpeedRender( val );
}