MainWorkflow.cpp 12.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
#include "MainWorkflow.h"
28 29
#include "TrackWorkflow.h"
#include "TrackHandler.h"
30
#include "Library.h"
31
#include "SettingsManager.h"
32
#include "Clip.h"
33

34
LightVideoFrame*    MainWorkflow::blackOutput = NULL;
35

36
MainWorkflow::MainWorkflow( int trackCount ) :
37
        m_lengthFrame( 0 ),
38
        m_renderStarted( false )
39
{
40
    m_currentFrameLock = new QReadWriteLock;
41
    m_renderStartedLock = new QReadWriteLock;
42

43 44 45 46 47 48 49
    const SettingValue* width = SettingsManager::getInstance()->getValue( "project", "VideoProjectWidth" );
    connect( width, SIGNAL( changed( QVariant ) ), this, SLOT( widthChanged( QVariant ) ) );
    m_width = width->get().toUInt();
    const SettingValue* height = SettingsManager::getInstance()->getValue( "project", "VideoProjectHeight" );
    connect( height, SIGNAL( changed( QVariant ) ), this, SLOT( widthChanged( QVariant ) ) );
    m_height = height->get().toUInt();

50 51 52
    m_effectEngine = new EffectsEngine;
    m_effectEngine->disable();

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

    blackOutput = new LightVideoFrame( m_width * m_height * 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
    delete m_renderStartedLock;
75
    delete m_currentFrameLock;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
76
    delete m_currentFrame;
77
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
78
        delete m_tracks[i];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
79
    delete[] m_tracks;
80 81
}

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

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

96
void            MainWorkflow::computeLength()
97
{
98 99
    qint64      maxLength = 0;

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
117
MainWorkflow::OutputBuffers*    MainWorkflow::getOutput( TrackType trackType )
118
{
119
    QReadLocker         lock( m_renderStartedLock );
120

121
    if ( m_renderStarted == true )
122
    {
123
        QReadLocker         lock2( m_currentFrameLock );
124

125
        m_tracks[trackType]->getOutput( m_currentFrame[VideoTrack], m_currentFrame[trackType] );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
126
        if ( trackType == MainWorkflow::VideoTrack )
127
        {
128 129 130
            (*m_effectEngine)->render();
            LightVideoFrame const & tmp = (*((*m_effectEngine)->getInternalStaticVideoInput( 1 )) );
            if (tmp->nboctets == 0 )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
131 132
                m_outputBuffers->video = MainWorkflow::blackOutput;
            else
133
                m_outputBuffers->video = &tmp;
134
        }
135 136
        else
        {
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
137
            m_outputBuffers->audio = m_tracks[MainWorkflow::AudioTrack]->getTmpAudioBuffer();
138
        }
139
    }
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
140
    return m_outputBuffers;
141
}
142

143 144
void        MainWorkflow::pause()
{
145 146
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->pause();
147
    emit mainWorkflowPaused();
148 149
}

150 151
void        MainWorkflow::unpause()
{
152 153
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        m_tracks[i]->unpause();
154
    emit mainWorkflowUnpaused();
155 156
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
157
void        MainWorkflow::goToNextFrame( MainWorkflow::TrackType trackType )
158 159
{
    if ( m_paused == false )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
160
        nextFrame( trackType );
161 162
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
163
void        MainWorkflow::nextFrame( MainWorkflow::TrackType trackType )
164
{
165
    QWriteLocker    lock( m_currentFrameLock );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
166

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
167 168 169
    ++m_currentFrame[trackType];
    if ( trackType == MainWorkflow::VideoTrack )
        emit frameChanged( m_currentFrame[MainWorkflow::VideoTrack], Renderer );
170 171
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
172
void        MainWorkflow::previousFrame( MainWorkflow::TrackType trackType )
173
{
174
    QWriteLocker    lock( m_currentFrameLock );
175

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
176 177 178
    --m_currentFrame[trackType];
    if ( trackType == MainWorkflow::VideoTrack )
        emit frameChanged( m_currentFrame[MainWorkflow::VideoTrack], Renderer );
179 180
}

181
qint64      MainWorkflow::getLengthFrame() const
182
{
183
    return m_lengthFrame;
184
}
185

186
qint64      MainWorkflow::getClipPosition( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType ) const
187
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
188
    return m_tracks[trackType]->getClipPosition( uuid, trackId );
189
}
190 191 192 193

void            MainWorkflow::stop()
{
    QWriteLocker    lock( m_renderStartedLock );
194
    QWriteLocker    lock2( m_currentFrameLock );
195 196

    m_renderStarted = false;
197
    for (unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
198
    {
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
199
        m_tracks[i]->stop();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
200 201
        m_currentFrame[i] = 0;
    }
202
    emit frameChanged( 0, Renderer );
203
}
204

205
void           MainWorkflow::moveClip( const QUuid& clipUuid, unsigned int oldTrack,
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
206
                                       unsigned int newTrack, qint64 startingFrame,
207
                                       MainWorkflow::TrackType trackType, bool undoRedoCommand /*= false*/ )
208
{
209
    m_tracks[trackType]->moveClip( clipUuid, oldTrack, newTrack, startingFrame );
210
    computeLength();
211

212 213 214 215
    if ( undoRedoCommand == true )
    {
        emit clipMoved( clipUuid, newTrack, startingFrame, trackType );
    }
216
}
217

218
Clip*       MainWorkflow::removeClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
219
{
220 221
    Clip* clip = m_tracks[trackType]->removeClip( uuid, trackId );
    computeLength();
222
    emit clipRemoved( clip, trackId, trackType );
223
    return clip;
224 225
}

226
void        MainWorkflow::muteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
227
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
228
    m_tracks[trackType]->muteTrack( trackId );
229 230
}

231
void        MainWorkflow::unmuteTrack( unsigned int trackId, MainWorkflow::TrackType trackType )
232
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
233
    m_tracks[trackType]->unmuteTrack( trackId );
234
}
235

236
void        MainWorkflow::setCurrentFrame( qint64 currentFrame, MainWorkflow::FrameChangedReason reason )
237
{
238 239
    QWriteLocker    lock( m_currentFrameLock );

240 241 242 243 244 245 246
    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
247 248 249
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i)
        m_currentFrame[i] = currentFrame;
    emit frameChanged( currentFrame, reason );
250
}
251

252
Clip*       MainWorkflow::getClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType )
253
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
254
    return m_tracks[trackType]->getClip( uuid, trackId );
255
}
256

257 258 259
/**
 *  \warning    The mainworkflow is expected to be cleared already by the ProjectManager
 */
260 261
void        MainWorkflow::loadProject( const QDomElement& project )
{
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    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;
290
            MainWorkflow::TrackType     trackType = MainWorkflow::VideoTrack;
291 292 293 294 295 296 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

            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" )
                {
328
                    trackType = static_cast<MainWorkflow::TrackType>( clipProperty.text().toUInt( &ok ) );
329 330 331 332 333 334 335 336 337 338 339 340
                    if ( ok == false )
                    {
                        qWarning() << "Invalid track type starting frame";
                        return ;
                    }
                }
                else
                    qDebug() << "Unknown field" << clipProperty.tagName();

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

341 342 343 344 345
            if ( Library::getInstance()->getMedia( parent ) != NULL )
            {
                Clip*       c = new Clip( parent, begin, end );
                addClip( c, trackId, startPos, trackType );
            }
346 347 348 349 350

            clip = clip.nextSibling().toElement();
        }
        elem = elem.nextSibling().toElement();
    }
351 352
}

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

void        MainWorkflow::clear()
{
365
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
366
        m_tracks[i]->clear();
367
    emit cleared();
368
}
369

370 371 372 373 374 375 376 377
void        MainWorkflow::tracksEndReached()
{
    for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
        if ( m_tracks[i]->endIsReached() == false )
            return ;
    emit mainWorkflowEndReached();
}

378
int         MainWorkflow::getTrackCount( MainWorkflow::TrackType trackType ) const
379 380 381
{
    return m_tracks[trackType]->getTrackCount();
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
382

383 384
qint64      MainWorkflow::getCurrentFrame() const
{
385 386
    QReadLocker     lock( m_currentFrameLock );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
387
    return m_currentFrame[MainWorkflow::VideoTrack];
388
}
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408

void        MainWorkflow::widthChanged( const QVariant& width )
{
    m_width = width.toUInt();
}

void        MainWorkflow::heightChanged( const QVariant& height )
{
    m_height = height.toUInt();
}

uint32_t    MainWorkflow::getWidth() const
{
    return m_width;
}

uint32_t    MainWorkflow::getHeight() const
{
    return m_height;
}