TrackWorkflow.cpp 21 KB
Newer Older
1
2
3
/*****************************************************************************
 * TrackWorkflow.cpp : Will query the Clip workflow for each successive clip in the track
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2008-2010 VideoLAN
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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 "TrackWorkflow.h"
25

26
#include "Clip.h"
27
#include "ClipHelper.h"
28
#include "AudioClipWorkflow.h"
29
30
#include "EffectInstance.h"
#include "EffectHelper.h"
31
#include "ImageClipWorkflow.h"
32
#include "MainWorkflow.h"
33
#include "Media.h"
34
#include "Types.h"
35
36
#include "VideoClipWorkflow.h"
#include "vlmc.h"
37

38
39
#include <QDomDocument>
#include <QDomElement>
40
41
#include <QMutex>
#include <QReadWriteLock>
42

43
44
#include <QtDebug>

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
45
TrackWorkflow::TrackWorkflow( Workflow::TrackType type, quint32 trackId  ) :
46
        m_length( 0 ),
47
        m_trackType( type ),
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
48
        m_lastFrame( 0 ),
49
        m_trackId( trackId )
50
{
51
    m_renderOneFrameMutex = new QMutex;
52
    m_clipsLock = new QReadWriteLock;
53
    m_mixerBuffer = new Workflow::Frame;
54
55
56

    connect( this, SIGNAL( effectAdded( EffectHelper*, qint64 ) ),
             this, SLOT( __effectAdded( EffectHelper*, qint64) ) );
57
58
    connect( this, SIGNAL( effectMoved( EffectHelper*, qint64 ) ),
             this, SLOT( __effectMoved( EffectHelper*, qint64 ) ) );
59
60
    connect( this, SIGNAL( effectRemoved( QUuid ) ),
             this, SLOT( __effectRemoved(QUuid ) ) );
61
62
}

63
64
TrackWorkflow::~TrackWorkflow()
{
65
66
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
67
68
69
70
71
72
73

    while ( it != end )
    {
        stopClipWorkflow( it.value() );
        delete it.value();
        it = m_clips.erase( it );
    }
74
    delete m_clipsLock;
75
    delete m_renderOneFrameMutex;
76
77
}

78
79
void
TrackWorkflow::addClip( ClipHelper* ch, qint64 start )
80
{
81
    ClipWorkflow* cw;
82
    if ( m_trackType == Workflow::VideoTrack )
83
    {
84
85
        if ( ch->clip()->getMedia()->fileType() == Media::Video )
            cw = new VideoClipWorkflow( ch );
86
        else
87
            cw = new ImageClipWorkflow( ch );
88
    }
89
    else
90
        cw = new AudioClipWorkflow( ch );
91
    ch->setClipWorkflow( cw );
92
    addClip( cw, start );
93
94
}

95
96
void
TrackWorkflow::addClip( ClipWorkflow* cw, qint64 start )
97
98
99
{
    QWriteLocker    lock( m_clipsLock );
    m_clips.insert( start, cw );
100
101
    connect( cw, SIGNAL( effectAdded( EffectHelper*, qint64 ) ),
             this, SLOT( __effectAdded( EffectHelper*, qint64 ) ) );
102
103
    connect( cw, SIGNAL( effectMoved( EffectHelper*, qint64 ) ),
             this, SLOT( __effectMoved( EffectHelper*, qint64) ) );
104
105
    connect( cw, SIGNAL( effectRemoved( QUuid ) ),
             this, SLOT( __effectRemoved( QUuid ) ) );
106
107
    connect( cw->getClipHelper(), SIGNAL( destroyed( QUuid ) ),
             this, SLOT( clipDestroyed( QUuid ) ) );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
108
    emit clipAdded( this, cw->getClipHelper(), start );
109
110
111
    computeLength();
}

112
//Must be called from a thread safe method (m_clipsLock locked)
113
114
void
TrackWorkflow::computeLength()
115
{
116
    bool    changed = false;
117
    if ( m_clips.count() == 0 )
118
    {
119
120
        if ( m_length != 0 )
            changed = true;
121
        m_length = 0;
122
    }
123
124
125
126
127
128
129
130
131
132
    else
    {
        QMap<qint64, ClipWorkflow*>::const_iterator it = m_clips.end() - 1;
        qint64  newLength = it.key() + it.value()->getClipHelper()->length();
        if ( m_length != newLength )
            changed = true;
        m_length = newLength;
    }
    if ( changed == true )
        emit lengthChanged( m_length );
133
134
}

135
136
qint64
TrackWorkflow::getLength() const
137
138
139
140
{
    return m_length;
}

141
142
qint64
TrackWorkflow::getClipPosition( const QUuid& uuid ) const
143
{
144
145
    QMap<qint64, ClipWorkflow*>::const_iterator     it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::const_iterator     end = m_clips.end();
146
147
148

    while ( it != end )
    {
149
        if ( it.value()->getClipHelper()->uuid() == uuid )
150
151
152
153
            return it.key();
        ++it;
    }
    return -1;
154
155
}

156
157
ClipHelper*
TrackWorkflow::getClipHelper( const QUuid& uuid )
158
159
160
161
162
163
{
    QMap<qint64, ClipWorkflow*>::const_iterator     it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::const_iterator     end = m_clips.end();

    while ( it != end )
    {
164
165
        if ( it.value()->getClipHelper()->uuid() == uuid )
            return it.value()->getClipHelper();
166
167
168
169
170
        ++it;
    }
    return NULL;
}

171
Workflow::OutputBuffer*
172
TrackWorkflow::renderClip( ClipWorkflow* cw, qint64 currentFrame,
173
                                        qint64 start , bool needRepositioning,
174
                                        bool renderOneFrame, bool paused )
175
{
176
    ClipWorkflow::GetMode       mode = ( paused == false || renderOneFrame == true ?
177
                                         ClipWorkflow::Pop : ClipWorkflow::Get );
178

179
    cw->getStateLock()->lockForRead();
180
181
182
183
    if ( cw->getState() == ClipWorkflow::Rendering ||
         cw->getState() == ClipWorkflow::Paused ||
         cw->getState() == ClipWorkflow::PauseRequired ||
         cw->getState() == ClipWorkflow::UnpauseRequired )
184
    {
185
        cw->getStateLock()->unlock();
186
187

        if ( cw->isResyncRequired() == true || needRepositioning == true )
188
            adjustClipTime( currentFrame, start, cw );
189
        return cw->getOutput( mode, currentFrame - start );
190
    }
191
    else if ( cw->getState() == ClipWorkflow::Stopped )
192
    {
193
        cw->getStateLock()->unlock();
194
        cw->initialize();
195
196
197
        //If the init failed, don't even try to call getOutput.
        if ( cw->waitForCompleteInit() == false )
            return NULL;
198
        //We check for a difference greater than one to avoid false positive when starting.
199
        if ( (  qAbs(start - currentFrame) > 1 ) || cw->getClipHelper()->begin() != 0 )
200
        {
201
            //Clip was not started at its real begining: adjust the position
202
            adjustClipTime( currentFrame, start, cw );
203
        }
204
        return cw->getOutput( mode, currentFrame - start );
205
    }
206
    else if ( cw->getState() == ClipWorkflow::EndReached ||
207
208
              cw->getState() == ClipWorkflow::Muted ||
              cw->getState() == ClipWorkflow::Error )
209
210
211
212
    {
        cw->getStateLock()->unlock();
        //The stopClipWorkflow() method will take care of that.
    }
213
    else
214
    {
215
        qCritical() << "Unexpected state:" << cw->getState();
216
        cw->getStateLock()->unlock();
217
    }
218
    return NULL;
219
}
220

221
222
void
TrackWorkflow::preloadClip( ClipWorkflow* cw )
223
{
224
    cw->getStateLock()->lockForRead();
225

226
    if ( cw->getState() == ClipWorkflow::Stopped )
227
    {
228
        cw->getStateLock()->unlock();
229
        cw->initialize();
230
        return ;
231
    }
232
    cw->getStateLock()->unlock();
233
234
}

235
236
void
TrackWorkflow::stopClipWorkflow( ClipWorkflow* cw )
237
{
238
//    qDebug() << "Stopping clip workflow";
239
    cw->getStateLock()->lockForRead();
240

241
    if ( cw->getState() == ClipWorkflow::Stopped ||
242
243
         cw->getState() == ClipWorkflow::Muted ||
         cw->getState() == ClipWorkflow::Error )
244
    {
245
246
        cw->getStateLock()->unlock();
        return ;
247
    }
248
249
    cw->getStateLock()->unlock();
    cw->stop();
250
251
}

252
bool
253
TrackWorkflow::hasNoMoreFrameToRender( qint64 currentFrame ) const
254
255
256
257
258
{
    if ( m_clips.size() == 0 )
        return true;
    //This is the last video by chronological order :
    QMap<qint64, ClipWorkflow*>::const_iterator   it = m_clips.end() - 1;
259
260
261
262
263
264
265
    ClipWorkflow* cw = it.value();
    //Check if the Clip is in error state. If so, don't bother checking anything else.
    {
        QReadLocker     lock( cw->getStateLock() );
        if ( cw->getState() == ClipWorkflow::Error )
            return true;
    }
266
    //If it ends before the current frame, we reached end.
267
    return ( cw->getClipHelper()->length() + it.key() < currentFrame );
268
269
}

270
271
void
TrackWorkflow::stop()
272
{
273
274
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
275
276
277
278
279
280

    while ( it != end )
    {
        stopClipWorkflow( it.value() );
        ++it;
    }
281
    m_lastFrame = 0;
282
    m_isRendering = false;
283
284
}

285
Workflow::OutputBuffer*
286
TrackWorkflow::getOutput( qint64 currentFrame, qint64 subFrame, bool paused )
287
{
288
289
    QReadLocker     lock( m_clipsLock );

290
291
292
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
    bool                                        needRepositioning;
293
    Workflow::OutputBuffer                      *ret = NULL;
294
    Workflow::Frame                             *frames[EffectsEngine::MaxFramesForMixer];
295
    quint32                                     frameId = 0;
296
    bool                                        renderOneFrame = false;
297

298
299
    if ( m_lastFrame == -1 )
        m_lastFrame = currentFrame;
300
301
302
303
304
305
306
307
    {
        QMutexLocker      lock2( m_renderOneFrameMutex );
        if ( m_renderOneFrame == true )
        {
            m_renderOneFrame = false;
            renderOneFrame = true;
        }
    }
308
    {
309
310
311
312
313
        // This is a bit hackish : when we want to pop a frame in renderOneFrame mode,
        // we also set the position to avoid the stream to be missynchronized.
        // this frame setting will most likely toggle the next condition as true
        // If this condition is true, the clipworkflow will flush all its buffer
        // as we need to resynchronize after a setTime, so this condition has to remain
Nikoli's avatar
Nikoli committed
314
        // false. Easy ain't it?
315
        if ( paused == true && subFrame != m_lastFrame && renderOneFrame == false)
316
            needRepositioning = true;
317
        else
318
            needRepositioning = ( abs( subFrame - m_lastFrame ) > 1 ) ? true : false;
319
    }
320
    memset( frames, 0, sizeof(*frames) * EffectsEngine::MaxFramesForMixer );
321
    while ( it != end )
322
    {
323
324
        qint64          start = it.key();
        ClipWorkflow*   cw = it.value();
Nikoli's avatar
Nikoli committed
325
        //Is the clip supposed to render now?
326
        if ( start <= currentFrame && currentFrame <= start + cw->getClipHelper()->length() )
327
        {
328
329
            ret = renderClip( cw, currentFrame, start, needRepositioning,
                              renderOneFrame, paused );
330
            if ( m_trackType == Workflow::VideoTrack )
331
            {
332
                frames[frameId] = static_cast<Workflow::Frame*>( ret );
333
334
                ++frameId;
            }
335
        }
Nikoli's avatar
Nikoli committed
336
        //Is it about to be rendered?
337
338
339
        else if ( start > currentFrame &&
                start - currentFrame < TrackWorkflow::nbFrameBeforePreload )
            preloadClip( cw );
Nikoli's avatar
Nikoli committed
340
        //Is it supposed to be stopped?
341
        else
342
343
            stopClipWorkflow( cw );
        ++it;
344
    }
345
    //Handle mixers:
346
    if ( m_trackType == Workflow::VideoTrack )
347
    {
348
        EffectHelper*   mixer = getMixer( currentFrame );
349
        if ( mixer != NULL && frames[0] != NULL ) //There's no point using the mixer if there's no frame rendered.
350
        {
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
351
            //FIXME: We don't handle mixer3 yet.
352
            mixer->effectInstance()->process( currentFrame * 1000.0 / m_fps,
353
                                    frames[0]->buffer(),
354
                                    frames[1] != NULL ? frames[1]->buffer() : MainWorkflow::getInstance()->blackOutput()->buffer(),
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
355
                                    NULL, m_mixerBuffer->buffer() );
356
            m_mixerBuffer->ptsDiff = frames[0]->ptsDiff;
357
            ret = m_mixerBuffer;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
358
        }
359
        else //If there's no mixer, just use the first frame, ignore the rest. It will be cleaned by the responsible ClipWorkflow.
360
            ret = frames[0];
361
        //Now handle filters :
362
363
        quint32     *newFrame = applyFilters( ret != NULL ? static_cast<const Workflow::Frame*>( ret ) : MainWorkflow::getInstance()->blackOutput(),
                                                currentFrame, currentFrame * 1000.0 / m_fps );
364
        if ( newFrame != NULL )
365
366
367
368
369
370
371
372
373
        {
            if ( ret != NULL )
                static_cast<Workflow::Frame*>( ret )->setBuffer( newFrame );
            else //Use the m_mixerBuffer as the frame to return. Ugly but avoid another attribute.
            {
                m_mixerBuffer->setBuffer( newFrame );
                ret = m_mixerBuffer;
            }
        }
374
    }
375
    m_lastFrame = subFrame;
376
    return ret;
377
378
}

379
380
void
TrackWorkflow::moveClip( const QUuid& id, qint64 startingFrame )
381
{
382
383
    QWriteLocker    lock( m_clipsLock );

384
385
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
386
387
388

    while ( it != end )
    {
389
        if ( it.value()->getClipHelper()->uuid() == id )
390
391
392
393
        {
            ClipWorkflow* cw = it.value();
            m_clips.erase( it );
            m_clips[startingFrame] = cw;
394
            cw->requireResync();
395
            computeLength();
396
            emit clipMoved( this, cw->getClipHelper()->uuid(), startingFrame );
397
398
399
400
401
            return ;
        }
        ++it;
    }
}
402

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
void
TrackWorkflow::clipDestroyed( const QUuid& id )
{
    QWriteLocker    lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();

    while ( it != end )
    {
        if ( it.value()->getClipHelper()->uuid() == id )
        {
            ClipWorkflow*   cw = it.value();
            m_clips.erase( it );
            stopClipWorkflow( cw );
            computeLength();
            cw->disconnect();
            cw->getClipHelper()->disconnect( this );
421
            emit clipRemoved( this, id );
422
423
424
425
426
427
428
            cw->deleteLater();
            return ;
        }
        ++it;
    }
}

429
430
Clip*
TrackWorkflow::removeClip( const QUuid& id )
431
432
433
{
    QWriteLocker    lock( m_clipsLock );

434
435
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
436
437
438

    while ( it != end )
    {
439
        if ( it.value()->getClipHelper()->uuid() == id )
440
441
        {
            ClipWorkflow*   cw = it.value();
442
            Clip*           clip = cw->clip();
443
            m_clips.erase( it );
444
            stopClipWorkflow( cw );
445
            computeLength();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
446
            cw->disconnect();
447
            cw->getClipHelper()->disconnect( this );
448
            emit clipRemoved( this, cw->getClipHelper()->uuid() );
449
            cw->deleteLater();
450
            return clip;
451
452
453
454
455
        }
        ++it;
    }
    return NULL;
}
456

457
458
ClipWorkflow*
TrackWorkflow::removeClipWorkflow( const QUuid& id )
459
460
461
462
463
464
465
466
{
    QWriteLocker    lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();

    while ( it != end )
    {
467
        if ( it.value()->getClipHelper()->uuid() == id )
468
469
        {
            ClipWorkflow*   cw = it.value();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
470
            cw->disconnect();
471
472
            m_clips.erase( it );
            computeLength();
473
            cw->getClipHelper()->disconnect( this );
474
            emit clipRemoved( this, cw->getClipHelper()->uuid() );
475
476
477
478
479
480
481
            return cw;
        }
        ++it;
    }
    return NULL;
}

482
483
void
TrackWorkflow::save( QXmlStreamWriter& project ) const
484
485
486
487
488
489
{
    QReadLocker     lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::const_iterator     it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::const_iterator     end = m_clips.end();

490
    project.writeStartElement( "clips" );
491
492
    for ( ; it != end ; ++it )
    {
493
494
        project.writeStartElement( "clip" );
        project.writeAttribute( "startFrame", QString::number( it.key() ) );
495
        it.value()->save( project );
496
        project.writeEndElement();
497
    }
498
    project.writeEndElement();
499
500
}

501
502
void
TrackWorkflow::clear()
503
504
505
506
507
508
509
510
{
    QWriteLocker    lock( m_clipsLock );
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();

    for ( ; it != end; ++it )
    {
        ClipWorkflow*   cw = it.value();
511
        //The clip contained in the trackworkflow will be delete by the undo stack.
512
513
514
515
516
        delete cw;
    }
    m_clips.clear();
    m_length = 0;
}
517

518
519
void
TrackWorkflow::adjustClipTime( qint64 currentFrame, qint64 start, ClipWorkflow* cw )
520
{
521
522
    qint64  nbMs = ( currentFrame - start ) / cw->clip()->getMedia()->fps() * 1000;
    qint64  beginInMs = cw->getClipHelper()->begin() / cw->clip()->getMedia()->fps() * 1000;
523
    qint64  startFrame = beginInMs + nbMs;
524
    cw->setTime( startFrame, currentFrame );
525
}
526

527
528
529
530
531
532
void
TrackWorkflow::renderOneFrame()
{
    QMutexLocker    lock( m_renderOneFrameMutex );
    m_renderOneFrame = true;
}
533
534
535
536
537
538
539
540
541

void
TrackWorkflow::setFullSpeedRender( bool val )
{
    foreach ( ClipWorkflow* cw, m_clips.values() )
    {
        cw->setFullSpeedRender( val );
    }
}
542
543
544
545
546
547
548
549
550
551
552

void
TrackWorkflow::muteClip( const QUuid &uuid )
{
    QWriteLocker    lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();

    while ( it != end )
    {
553
        if ( it.value()->getClipHelper()->uuid() == uuid )
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
        {
            it.value()->mute();
            return ;
        }
        ++it;
    }
    qWarning() << "Failed to mute clip" << uuid << "it probably doesn't exist "
            "in this track";
}

void
TrackWorkflow::unmuteClip( const QUuid &uuid )
{
    QWriteLocker    lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();

    while ( it != end )
    {
574
        if ( it.value()->getClipHelper()->uuid() == uuid )
575
576
577
578
579
580
581
582
583
        {
            it.value()->unmute();
            return ;
        }
        ++it;
    }
    qWarning() << "Failed to unmute clip" << uuid << "it probably doesn't exist "
            "in this track";
}
584
585

void
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
586
TrackWorkflow::initRender( quint32 width, quint32 height, double fps )
587
588
589
{
    QReadLocker     lock( m_clipsLock );

590
    m_mixerBuffer->resize( width, height );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
591
    m_fps = fps;
592
593
594
    m_width = width;
    m_height = height;
    m_isRendering = true;
595
596
597
598
599
600
601
602
603
604
    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
    while ( it != end )
    {
        qint64          start = it.key();
        ClipWorkflow*   cw = it.value();
        if ( start < TrackWorkflow::nbFrameBeforePreload )
            preloadClip( cw );
        ++it;
    }
605
606
    initFilters();
    initMixers();
607
}
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623

bool
TrackWorkflow::contains( const QUuid &uuid ) const
{
    QMap<qint64, ClipWorkflow*>::const_iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::const_iterator       end = m_clips.end();

    while ( it != end )
    {
        if ( it.value()->getClipHelper()->clip()->uuid() == uuid ||
             it.value()->getClipHelper()->clip()->isChild( uuid ) )
            return true;
        ++it;
    }
    return false;
}
624
625
626
627
628
629
630
631
632
633
634
635
636
637

void
TrackWorkflow::stopFrameComputing()
{
    QMap<qint64, ClipWorkflow*>::const_iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::const_iterator       end = m_clips.end();

    while ( it != end )
    {
        ClipWorkflow*   cw = it.value();

        cw->getStateLock()->lockForRead();

        if ( cw->getState() == ClipWorkflow::Stopped ||
638
639
             cw->getState() == ClipWorkflow::Muted ||
             cw->getState() == ClipWorkflow::Error )
640
641
642
643
644
645
646
647
648
        {
            cw->getStateLock()->unlock();
            return ;
        }
        cw->getStateLock()->unlock();
        cw->stopRenderer();
        ++it;
    }
}
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
649
650
651
652
653
654
655
656
657
658
659
660

quint32
TrackWorkflow::trackId() const
{
    return m_trackId;
}

Workflow::TrackType
TrackWorkflow::type() const
{
    return m_trackType;
}
661
662
663
664
665
666
667
668
669
670
671
672

EffectsEngine::EffectList*
TrackWorkflow::filters()
{
    return &m_filters;
}

EffectsEngine::EffectList*
TrackWorkflow::mixers()
{
    return &m_mixers;
}
673
674
675
676

void
TrackWorkflow::__effectAdded( EffectHelper* helper, qint64 pos )
{
677
678
679
680
681
682
    if ( helper->target()->effectType() == ClipEffectUser )
    {
        ClipWorkflow    *cw = qobject_cast<ClipWorkflow*>( helper->target() );
        Q_ASSERT( cw != NULL );
        pos += getClipPosition( cw->getClipHelper()->uuid() );
    }
683
684
685
686
687
688
689
690
691
692
    emit effectAdded( this, helper, pos );
}

void
TrackWorkflow::__effectRemoved( const QUuid& uuid )
{
    emit effectRemoved( this, uuid );
}

void
693
TrackWorkflow::__effectMoved( EffectHelper* helper, qint64 pos )
694
{
695
696
697
698
699
700
701
    if ( helper->target()->effectType() == ClipEffectUser )
    {
        ClipWorkflow    *cw = qobject_cast<ClipWorkflow*>( helper->target() );
        Q_ASSERT( cw != NULL );
        pos += getClipPosition( cw->getClipHelper()->uuid() );
    }
    emit effectMoved( this, helper->uuid(), pos );
702
}
703
704
705
706
707
708

qint64
TrackWorkflow::length() const
{
    return m_length;
}
709
710
711
712
713
714

EffectUser::Type
TrackWorkflow::effectType() const
{
    return TrackEffectUser;
}