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
    emit clipRemoved( uuid, trackId, trackType );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
212
    return m_tracks[trackType]->removeClip( uuid, trackId );
213 214
}

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

228
    m_synchroneRenderWaitConditionMutex->unlock();
229 230

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

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

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

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

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

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

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

            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" )
                {
334
                    trackType = static_cast<MainWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
335 336 337 338 339 340 341 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();
            }

            Clip*       c = new Clip( parent, begin, end );
            addClip( c, trackId, startPos, trackType );

            clip = clip.nextSibling().toElement();
        }
        elem = elem.nextSibling().toElement();
    }
354 355
}

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

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

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
397 398
void        MainWorkflow::tracksRenderCompleted()
{
399
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
400 401 402 403 404 405 406
        if ( m_tracks[i]->allTracksRendered() == false )
            return ;
    {
        QMutexLocker    lock( m_synchroneRenderWaitConditionMutex );
    }
    m_synchroneRenderWaitCondition->wakeAll();
}
407

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

413 414 415 416
qint64      MainWorkflow::getCurrentFrame() const
{
    return m_currentFrame;
}