MainWorkflow.cpp 13.8 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 27
/*****************************************************************************
 * 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"

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

33
unsigned char* MainWorkflow::blackOutput = NULL;
34

35
MainWorkflow::MainWorkflow( int trackCount ) :
36
        m_currentFrame( 0 ),
37
        m_length( 0 ),
38
        m_renderStarted( false )
39
{
40 41
    MainWorkflow::blackOutput = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 3];
    memset( MainWorkflow::blackOutput, 0, VIDEOHEIGHT * VIDEOWIDTH * 3 );
42

43
    m_renderStartedLock = new QReadWriteLock;
44
    m_renderMutex = new QMutex;
45 46
    m_synchroneRenderWaitCondition = new QWaitCondition;
    m_synchroneRenderWaitConditionMutex = new QMutex;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
47 48 49
    m_tracks = new TrackHandler*[2];
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
    {
50
        TrackWorkflow::TrackType trackType = (i == 0 ? TrackWorkflow::Video : TrackWorkflow::Audio );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
51 52
        m_tracks[i] = new TrackHandler( trackCount, trackType );
        connect( m_tracks[i], SIGNAL( tracksPaused() ), this, SLOT( tracksPaused() ) );
53
        connect( m_tracks[i], SIGNAL( allTracksRenderCompleted() ), this, SLOT( tracksRenderCompleted() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
54 55
    }
    m_outputBuffers = new OutputBuffers;
56
    m_effectEngine = new EffectsEngine;
57 58 59

    m_effectEngine->disable();

60
    m_nbTracksToRenderMutex = new QMutex;
61 62 63 64
}

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
81 82
void            MainWorkflow::addClip( Clip* clip, unsigned int trackId,
                                        qint64 start, TrackWorkflow::TrackType trackType )
83
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
84
    m_tracks[trackType]->addClip( clip, trackId, start );
85

86
    //Inform the GUI
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
87
    emit clipAdded( clip, trackId, start, trackType );
88
}
89

90
void            MainWorkflow::computeLength()
91
{
92 93
    qint64      maxLength = 0;

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
94
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
95 96 97 98 99
    {
        if ( m_tracks[i]->getLength() > maxLength )
            maxLength = m_tracks[i]->getLength();
    }
    m_length = maxLength;
100 101
}

102 103 104
void    MainWorkflow::startRender()
{
    m_renderStarted = true;
105
    m_paused = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
106 107
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        m_tracks[i]->startRender();
108 109 110
    computeLength();
}

111
void                    MainWorkflow::getOutput()
112
{
113 114
    QReadLocker         lock( m_renderStartedLock );
    QMutexLocker        lock2( m_renderMutex );
115

116
    if ( m_renderStarted == true )
117
    {
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
118
        for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
119
            m_tracks[i]->getOutput( m_currentFrame );
120 121
        if ( m_paused == false )
            nextFrame();
122
    }
123
}
124

125 126
void        MainWorkflow::pause()
{
127 128
    QMutexLocker    lock( m_renderMutex );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
129 130
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        m_tracks[i]->pause();
131 132
}

133 134 135 136
void        MainWorkflow::unpause()
{
    QMutexLocker    lock( m_renderMutex );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
137 138
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        m_tracks[i]->unpause();
139 140
}

141 142 143 144 145 146 147 148 149 150 151 152 153 154
void        MainWorkflow::nextFrame()
{
    ++m_currentFrame;
    emit frameChanged( m_currentFrame );
    emit positionChanged( (float)m_currentFrame / (float)m_length );
}

void        MainWorkflow::previousFrame()
{
    --m_currentFrame;
    emit frameChanged( m_currentFrame );
    emit positionChanged( (float)m_currentFrame / (float)m_length );
}

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

qint64      MainWorkflow::getLength() const
{
    return m_length;
}
174

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

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

    m_renderStarted = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
185 186
    for (unsigned int i = 0; i < TrackWorkflow::NbType; ++i)
        m_tracks[i]->stop();
187 188
    m_currentFrame = 0;
    emit frameChanged( 0 );
189
    emit positionChanged( 0 );
190
}
191

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

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

210
<<<<<<< HEAD:src/Workflow/MainWorkflow.cpp
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
211
MainWorkflow::OutputBuffers*  MainWorkflow::getSynchroneOutput()
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
=======
void        MainWorkflow::trackUnpaused()
{
    m_nbTracksToUnpause.fetchAndAddAcquire( -1 );
    if ( m_nbTracksToUnpause <= 0 )
    {
        m_paused = false;
        emit mainWorkflowUnpaused();
    }
}

void        MainWorkflow::tracksRenderCompleted( unsigned int trackId )
{
//    qDebug() << "tracksRenderCompleted";
    QMutexLocker    lockNbTracks( m_nbTracksToRenderMutex );
    --m_nbTracksToRender;

    {
        LightVideoFrame*     buff = m_tracks[trackId]->getSynchroneOutput();
        if ( buff == NULL )
            m_effectEngine->setInputFrame( *MainWorkflow::nullOutput, trackId );
        else
            m_effectEngine->setInputFrame( *buff, trackId );
    }
    //We check for minus or equal, since we can have 0 frame to compute,
    //therefore, m_nbTracksToRender will be equal to -1
    if ( m_nbTracksToRender <= 0 )
    {
//        qDebug() << "main workflow render completed";
        //Just a synchronisation barriere
        {
            QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
        }
        //FIXME: This is uggly.... god probably just killed a kitten :(
        m_synchroneRenderWaitCondition->wakeAll();
    }
}

const LightVideoFrame*  MainWorkflow::getSynchroneOutput()
>>>>>>> Merge new version with Workflow:src/Workflow/MainWorkflow.cpp
252 253 254
{
    m_synchroneRenderWaitConditionMutex->lock();
    getOutput();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
255
//    qDebug() << "Waiting for sync output";
256
    m_synchroneRenderWaitCondition->wait( m_synchroneRenderWaitConditionMutex );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
257
//    qDebug() << "Got it";
258 259
    m_effectEngine->render();
    m_synchroneRenderingBuffer = &( m_effectEngine->getOutputFrame( 0 ) );
260
    m_synchroneRenderWaitConditionMutex->unlock();
261
<<<<<<< HEAD:src/Workflow/MainWorkflow.cpp
262
    m_outputBuffers->video = m_tracks[TrackWorkflow::Video]->getSynchroneOutput();
263
    m_outputBuffers->audio = m_tracks[TrackWorkflow::Audio]->getSynchroneOutput();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
264
    return m_outputBuffers;
265 266 267 268 269 270 271
=======

    if ( (*m_synchroneRenderingBuffer)->frame.octets == NULL )
        return MainWorkflow::blackOutput;

    return m_synchroneRenderingBuffer;
>>>>>>> Merge new version with Workflow:src/Workflow/MainWorkflow.cpp
272
}
273 274 275 276 277 278 279 280

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
282
void        MainWorkflow::muteTrack( unsigned int trackId, TrackWorkflow::TrackType trackType )
283
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
284
    m_tracks[trackType]->muteTrack( trackId );
285 286
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
287
void        MainWorkflow::unmuteTrack( unsigned int trackId, TrackWorkflow::TrackType trackType )
288
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
289
    m_tracks[trackType]->unmuteTrack( trackId );
290
}
291 292 293 294 295 296

void        MainWorkflow::setCurrentFrame( qint64 currentFrame )
{
    m_currentFrame = currentFrame;
    emit positionChanged( (float)m_currentFrame / (float)m_length );
}
297

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

void        MainWorkflow::loadProject( const QDomElement& project )
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
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 341 342 343 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 381 382
//    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;
//
//            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
//                    qDebug() << "Unknown field" << clipProperty.tagName();
//
//                clipProperty = clipProperty.nextSibling().toElement();
//            }
//
//            Clip*       c = new Clip( parent, begin, end );
//            addClip( c, trackId, startPos, TrackWorkflow::Video );
//
//            clip = clip.nextSibling().toElement();
//        }
//        elem = elem.nextSibling().toElement();
//    }
383 384
}

385
void        MainWorkflow::saveProject( QDomDocument& doc, QDomElement& rootNode )
386
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400
//    QDomElement project = doc.createElement( "timeline" );
//    for ( unsigned int i = 0; i < m_trackCount; ++i )
//    {
//        if ( m_tracks[i]->getLength() > 0 )
//        {
//            QDomElement     trackNode = doc.createElement( "track" );
//
//            trackNode.setAttribute( "id", i );
//
//            m_tracks[i]->save( doc, trackNode );
//            project.appendChild( trackNode );
//        }
//    }
//    rootNode.appendChild( project );
401
}
402 403 404

void        MainWorkflow::clear()
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
405
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
406
        m_tracks[i]->clear();
407
    emit cleared();
408
}
409 410 411

void        MainWorkflow::setFullSpeedRender( bool value )
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
412
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
413 414
        m_tracks[i]->setFullSpeedRender( value );
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

void        MainWorkflow::tracksPaused()
{
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        if ( m_tracks[i]->isPaused() == false )
            return ;
    emit mainWorkflowPaused();
}

void        MainWorkflow::tracksRenderCompleted()
{
    for ( unsigned int i = 0; i < TrackWorkflow::NbType; ++i )
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
434 435 436 437 438

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