MainWorkflow.h 22.6 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * MainWorkflow.h : Will query all of the track workflows to render the final
 *                  image
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
5
 * Copyright (C) 2008-2010 VideoLAN
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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.
 *****************************************************************************/

#ifndef MAINWORKFLOW_H
#define MAINWORKFLOW_H

27
#include "Singleton.hpp"
28
#include "AudioClipWorkflow.h"
29

30 31
class   QDomDocument;
class   QDomElement;
32 33 34 35 36
class   QMutex;
class   QReadWriteLock;

class   Clip;
class   EffectsEngine;
37
class   LightVideoFrame;
38
class   TrackHandler;
39
class   TrackWorkflow;
40

41 42 43
#include <QObject>
#include <QUuid>

44 45 46
/**
 *  \class  Represent the Timeline backend.
 */
47
class   MainWorkflow : public QObject, public Singleton<MainWorkflow>
48 49 50 51
{
    Q_OBJECT

    public:
52 53 54 55 56
        /**
         *  \struct     Represents an output, with both audio and video buffers.
         *              Note that an OutputBuffers will not necessarly have its both
         *              fields filed out.
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
57 58
        struct      OutputBuffers
        {
59 60
            const LightVideoFrame*              video;
            AudioClipWorkflow::AudioSample*     audio;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
61
        };
62 63 64
        /**
         *  \enum   Represents the potential Track types.
         */
65 66
        enum    TrackType
        {
67 68 69
            VideoTrack, ///< Represents a video track
            AudioTrack, ///< Represents an audio track
            NbTrackType, ///< Used to know how many types we have
70
        };
71 72 73 74 75 76 77
        /**
         *  \enum   Used to know which part required a change of rendered frame.
         *          The main use of this enum is to avoid infinite information propagation
         *          such as the timeline informing itself that the frame as changed, which
         *          would cause a signal to be emmited to inform every other part that the
         *          rendered frame has changed, and so on.
         */
78 79
        enum    FrameChangedReason
        {
80 81 82 83 84
            Renderer, ///< Used by the WorkflowRenderer
            /**
             *  \brief      Used by the timeline cursor.
             *  \warning    The timeline cursor is not the timeline ruler
             */
85
            TimelineCursor,
86 87
            PreviewCursor, ///< Used by the preview widget, when using the time cursor.
            RulerCursor, ///< Used by the timeline's ruler.
88
        };
89

90 91 92 93 94 95 96 97 98 99 100 101 102 103
        /**
         *  \brief      Add a clip to the workflow
         *
         *  When called, this method will emit
         *  clipAdded( Clip*, unsigned int, qint64, MainWorkflow::TrackType ) SIGNAL.
         *  \param      clip    The clip to add
         *  \param      trackId The number of the track (starting at 0)
         *  \param      start   The clip's starting position
         *  \param      type    The track type (audio or video)
         *  \sa         removeClip( const QUuid&, unsigned int, MainWorkflow::TrackType )
         *  \sa         clipAdded( Clip*, unsigned int, qint64, MainWorkflow::TrackType )
         */
        void                    addClip( Clip* clip, unsigned int trackId, qint64 start,
                                         TrackType type );
104

105 106 107 108 109
        /**
         *  \brief      Initialize the workflow for the render.
         *
         *  This will basically activate all the tracks, so they can render.
         */
110
        void                    startRender();
111 112 113 114 115 116 117 118 119
        /**
         *  \brief      Gets a frame from the workflow
         *
         *  \return A pointer to an output buffer. This pointer must NOT be released.
         *          Both types of this output buffer are not guarantied to be filled.
         *          However, if VideoTrack was passed as trackType, the video member of
         *          the output buffer is guarantied to be filled. The same applies for
         *          AudioTrack
         *  \param  trackType   The type of track you wish to get the render from.
120
         *  \param  paused      The paused state of the renderer
121
         */
122
        OutputBuffers*          getOutput( TrackType trackType, bool paused );
123 124 125 126 127
        /**
         *  \brief  Returns the effect engine instance used by the workflow
         *
         *  \return The effect engine instance used by the workflow
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
128
        EffectsEngine*          getEffectsEngine();
129

130 131 132
        /**
         *  \brief              Set the workflow position by the desired frame
         *  \param              currentFrame: The desired frame to render from
133
         *  \param              reason: The program part which required this frame change
134
                                        (to avoid cyclic events)
135
        */
136
        void                    setCurrentFrame( qint64 currentFrame,
137
                                                MainWorkflow::FrameChangedReason reason );
138

139
        /**
140
         *  \brief              Get the workflow length in frames.
141 142
         *  \return             Returns the global length of the workflow
         *                      in frames.
143
        */
144
        qint64                  getLengthFrame() const;
145

146
        /**
147
         *  \brief              Get the currently rendered frame.
148 149 150 151
         *  \return             Returns the current frame.
         */
        qint64                  getCurrentFrame() const;

152
        /**
153 154 155 156 157
         *  \brief      Stops the rendering.
         *
         *  This will stop every ClipWorkflow that are currently rendering.
         *  Calling this methid will cause the workflow to return to frame 0, and emit
         *  the signal frameChanged(), with the reason: Renderer
158 159 160
         */
        void                    stop();

161 162 163 164 165 166 167 168 169
        /**
         *  \brief              Unconditionnaly switch to the next frame.
         *
         *  \param  trackType   The type of the frame counter to increment.
         *                      Though it seems odd to speak about frame for AudioTrack,
         *                      it's mainly a render position used for
         *                      synchronisation purpose.
         *  \sa         previousFrame( MainWorkflow::TrackType );
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
170
        void                    nextFrame( TrackType trackType );
171 172 173 174 175 176 177 178 179
        /**
         *  \brief      Unconditionnaly switch to the previous frame.
         *
         *  \param      trackType   The type of the frame counter to decrement.
         *                          Though it seems odd to speak about frame for
         *                          AudioTrack, it's mainly a render position used for
         *                          synchronisation purpose.
         *  \sa         nextFrame( MainWorkflow::TrackType );
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
180
        void                    previousFrame( TrackType trackType );
181

182 183 184 185 186 187 188 189 190 191 192 193 194 195
        /**
         *  \brief              Remove a clip from the workflow
         *
         *  The created ClipWorkflow is deleted, and the added clip is returned.
         *  Calling this method will cause
         *  clipRemoved( Clip*, unsigned int, MainWorkflow::TrackType ) to be emitted.
         *  \param  uuid        The uuid of the clip to remove.
         *  \param  trackId     The id of the track containing the clip to remove
         *  \param  trackType   The type of the track containing the clip to remove
         *  \sa                 addClip( Clip*, unsigned int, qint64, TrackType )
         *  \sa                 clipRemoved(Clip*, unsigned int, MainWorkflow::TrackType)
         */
        Clip*                   removeClip( const QUuid& uuid, unsigned int trackId,
                                            MainWorkflow::TrackType trackType );
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        /**
         *  \brief              Move a clip in the workflow
         *
         *  This will move a clip, potentially from a track to anoher, to a new
         *  starting position.
         *  if undoRedoCommand is true, the
         *  clipMoved( QUuid, unsigned int, qint64, MainWorkflow::TrackType ) will be
         *  emitted.
         *  This (bad) behaviour is caused by the fact that this move is mostly required
         *  by the timeline, which has already move its graphic item.
         *  When caused by an undo redo command, the timeline isn't aware of the change,
         *  and needs to be.
         *  \param      uuid        The uuid of the clip to move
         *  \param      oldTrack    The origin track of the clip
         *  \param      newTrack    The destination track for the clip
         *  \param      pos         The new starting position for the clip
         *  \param      trackType   The type of the track containing the clip to move
         *  \param      undoRedoCommand Must be true if the method is called from an
         *                              undo/redo action. If any doubt, false seems like
         *                              a good choice.
         *  \todo       Fix the last parameter. Such a nasty hack shouldn't even exist.
         *  \sa         clipMoved( QUuid, unsigned int, qint64, MainWorkflow::TrackType )
         */
220
        void                    moveClip( const QUuid& uuid, unsigned int oldTrack,
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
221
                                          unsigned int newTrack, qint64 pos,
222 223 224 225 226 227 228 229 230 231 232 233 234
                                          MainWorkflow::TrackType trackType,
                                          bool undoRedoCommand = false );
        /**
         *  \brief              Return the given clip position.
         *
         *  \param      uuid        The clip uuid
         *  \param      trackId     The track containing the clip
         *  \param      trackType   The type of the track containing the clip
         *  \return                 The given clip position, in frame. If not found, -1
         *                          is returned.
         */
        qint64                  getClipPosition( const QUuid& uuid, unsigned int trackId,
                                                MainWorkflow::TrackType trackType ) const;
235

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
        /**
         *  \brief      Mute a track.
         *
         *  A muted track will not be asked for render. It won't even emit endReached
         *  signal. To summerize, a mutted track is an hard deactivated track.
         *  \param  trackId     The id of the track to mute
         *  \param  trackType   The type of the track to mute.
         *  \sa     unmuteTrack( unsigned int, MainWorkflow::TrackType );
         */
        void                    muteTrack( unsigned int trackId,
                                           MainWorkflow::TrackType trackType );
        /**
         *  \brief      Unmute a track.
         *
         *  \param  trackId     The id of the track to unmute
         *  \param  trackType   The type of the track to unmute.
         *  \sa     muteTrack( unsigned int, MainWorkflow::TrackType );
         */
        void                    unmuteTrack( unsigned int trackId,
                                             MainWorkflow::TrackType trackType );
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        /**
         *  \brief      Mute a clip.
         *
         *  \param  uuid        The clip's uuid.
         *  \param  trackId     The id of the track containing the clip.
         *  \param  trackType   The type of the track containing the clip.
         */
        void                    muteClip( const QUuid& uuid, unsigned int trackId,
                                          MainWorkflow::TrackType trackType );

        /**
         *  \brief      Unmute a clip.
         *
         *  \param  uuid        The clip's uuid.
         *  \param  trackId     The id of the track containing the clip.
         *  \param  trackType   The type of the track containing the clip.
         */
        void                    unmuteClip( const QUuid& uuid, unsigned int trackId,
                                          MainWorkflow::TrackType trackType );

277 278 279 280 281
        /**
         * \param   uuid : The clip's uuid.
         *              Please note that the UUID must be the "timeline uuid"
         *              and note the clip's uuid, or else nothing would match.
         *  \param  trackId : the track id
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
282
         *  \param  trackType : the track type (audio or video)
283 284
         *  \returns    The clip that matches the given UUID.
         */
285 286
        Clip*                   getClip( const QUuid& uuid, unsigned int trackId,
                                         MainWorkflow::TrackType trackType );
287

288 289 290 291 292 293
        /**
         *  \brief              Get the number of track for a specific type
         *
         *  \param  trackType   The type of the tracks to count
         *  \return             The number of track for the type trackType
         */
294
        int                     getTrackCount( MainWorkflow::TrackType trackType ) const;
295

296 297 298 299 300 301 302 303 304
        /**
         *  \brief      Get the width used for rendering.
         *
         *  This value is used by the ClipWorkflow that generates the frames.
         *  If this value is edited in the preferences, it will only change after the
         *  current render has been stopped.
         *  \return     The width (in pixels) of the currently rendered frames
         *  \sa         getHeight()
         */
305
        quint32                getWidth() const;
306 307 308 309 310 311 312 313 314
        /**
         *  \brief      Get the height used for rendering.
         *
         *  This value is used by the ClipWorkflow that generates the frames.
         *  If this value is edited in the preferences, it will only change after the
         *  current render has been stopped.
         *  \return     The height (in pixels) of the currently rendered frames
         *  \sa         getWidth()
         */
315
        quint32                getHeight() const;
316

317 318 319 320 321 322 323 324
        /**
         *  \brief          Will render one frame only
         *
         *  It will change the ClipWorkflow frame getting mode from Get to Pop, just for
         *  one frame
         */
        void                    renderOneFrame();

325 326 327 328 329 330 331 332 333
        /**
         *  \brief              Set the render speed.
         *
         *  This will activate or deactivate vlc's pace-control
         *  \param  val         If true, ClipWorkflow will use no-pace-control
         *                      else, pace-control.
         */
        void                    setFullSpeedRender( bool val );

334 335 336 337 338 339 340
        Clip*                   split( Clip* toSplit, Clip* newClip, quint32 trackId,
                                       qint64 newClipPos, qint64 newClipBegin,
                                       MainWorkflow::TrackType trackType );

        void                    resizeClip( Clip* clip, qint64 newBegin, qint64 newEnd,
                                          qint64 newPos, quint32 trackId,
                                          MainWorkflow::TrackType trackType,
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
341
                                          bool undoRedoAction = false );
342 343 344 345

        void                    unsplit( Clip* origin, Clip* splitted, quint32 trackId,
                                         MainWorkflow::TrackType trackType );

346 347 348
        /// Pre-filled buffer used when there's nothing to render
        static LightVideoFrame*         blackOutput;

349
    private:
350
        MainWorkflow( int trackCount = 64 );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
351
        ~MainWorkflow();
352 353 354 355 356 357 358
        /**
         *  \brief  Compute the length of the workflow.
         *
         *  This is meant to be used internally, after an operation occurs on the workflow
         *  such as adding a clip, removing it...
         *  This method will update the attribute m_lengthFrame
         */
359 360
        void                    computeLength();

361
    private:
362
        /// Lock for the m_currentFrame atribute.
363
        QReadWriteLock*                 m_currentFrameLock;
364 365 366 367 368 369 370 371 372 373
        /**
         *  \brief  An array of currently rendered frame.
         *
         *  This must be indexed with MainWorkflow::TrackType.
         *  The Audio array entry is designed to synchronize the renders internally, as it
         *  is not actually a frame.
         *  If you wish to know which frame is really rendered, you must use
         *  m_currentFrame[MainWorkflow::VideoTrack], which is the value that will be used
         *  when setCurrentFrame() is called.
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
374
        qint64*                         m_currentFrame;
375
        /// The workflow length, in frame.
376
        qint64                          m_lengthFrame;
377
        /// This boolean describe is a render has been started
378
        bool                            m_renderStarted;
379
        QMutex*                         m_renderStartedMutex;
380

381
        /// Contains the trackhandler, indexed by MainWorkflow::TrackType
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
382
        TrackHandler**                  m_tracks;
383
        /// Pre-allocated buffer, that will contain every computed outputs.
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
384 385
        OutputBuffers*                  m_outputBuffers;

386
        /// Effect engine instance.
387
        EffectsEngine*                  m_effectEngine;
388
        /// Width used for the render
389
        quint32                         m_width;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
390
        /// Height used for the render
391
        quint32                         m_height;
392

393
        friend class                    Singleton<MainWorkflow>;
394

395
    private slots:
396 397 398 399 400 401 402
        /**
         *  \brief  Called when a track end is reached
         *
         *  If all track has reached end, the mainWorkflowEndReached() signal will be
         *  emitted;
         *  \sa     mainWorkflowEndReached()
         */
403
        void                            tracksEndReached();
404 405 406 407 408
        /**
         *  \brief  Called when the width is changed in the preferences
         *  \todo   The value is immediatly changed, which is wrong.
         *          See issue : http://vlmc.org/issues/show/118
         */
409
        void                            widthChanged( const QVariant& );
410 411 412 413 414
        /**
         *  \brief  Called when the height is changed in the preferences
         *  \todo   The value is immediatly changed, which is wrong.
         *          See issue : http://vlmc.org/issues/show/118
         */
415 416
        void                            heightChanged( const QVariant& );

417

418
    public slots:
419 420 421 422 423
        /**
         *  \brief  load a project based on a QDomElement
         *
         *  \param  project             The project node to load.
         */
424
        void                            loadProject( const QDomElement& project );
425 426 427 428 429 430
        /**
         *  \brief          Save the project on a given node, for a given document.
         *
         *  \param  doc         A reference to the document.
         *  \param  rootNode    A reference on the node that will contain the timeline.
         */
431
        void                            saveProject( QDomDocument& doc, QDomElement& rootNode );
432 433 434 435 436 437 438 439 440
        /**
         *  \brief      Clear the workflow.
         *
         *  Calling this method will cause every clip workflow to be deleted, along with
         *  the associated Clip.
         *  This method will emit cleared() signal once finished.
         *  \sa     removeClip( const QUuid&, unsigned int, MainWorkflow::TrackType )
         *  \sa     cleared()
         */
441
        void                            clear();
442

443
    signals:
444
        /**
445 446 447 448 449
         *  \brief      Used to notify a change to the timeline and preview widget cursor
         *
         *  \param      newFrame    The new rendered frame
         *  \param      reason      The reason for changing frame. Usually, if emitted
         *                          from the MainWorkflow, this should be "Renderer"
450
         */
451 452
        void                    frameChanged( qint64 newFrame,
                                              MainWorkflow::FrameChangedReason reason );
453

454 455 456 457 458 459
        /**
         *  \brief  Emitted when workflow end is reached
         *
         *  Workflow end is reached when tracksEndReached() is called, and no more tracks
         *  are activated (ie. they all reached end)
         */
460
        void                    mainWorkflowEndReached();
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
        /**
         *  \brief  Emitted when a clip is added
         *
         *  \param  clip        The clip that has been added
         *  \param  trackId     The id of the track in which the clip has been added
         *  \param  pos         The position of the new Clip
         *  \param  trackType   The type of the clip that has been added
         *  \sa                 addClip( Clip*, unsigned int, qint64, TrackType )
         */
        void                    clipAdded( Clip* clip, unsigned int trackId, qint64 pos,
                                           MainWorkflow::TrackType trackType );
        /**
         *  \brief              Emitted when a clip is removed
         *  \param  clip        The clip that has been removed.
         *  \param  trackId     The track that was containing the clip
         *  \param  trackType   The type of the track that was containing the clip
         *  \sa     removeClip( const QUuid&, unsigned int, MainWorkflow::TrackType )
         */
        void                    clipRemoved( Clip* clip, unsigned int trackId,
                                             MainWorkflow::TrackType trackType );
        /**
         *  \brief              Emitted when a clip has been moved
         *
         *  \param  uuid        The uuid of the moved clip
         *  \param  trackid     The destination track of the moved media
         *  \param  pos         The clip new position
         *  \param  trackType   The moved clip type.
         *  \sa                 moveClip( const QUuid&, unsigned int, unsigned int,
         *                                  qint64, MainWorkflow::TrackType, bool );
         *  \warning            This is not always emitted. Check removeClip for more
         *                      details
         */
        void                    clipMoved( const QUuid& uuid, unsigned int trackId,
                                          qint64 pos, MainWorkflow::TrackType trackType );
        /**
         *  \brief  Emitted when the workflow is cleared.
         *
         *  \sa     clear();
         */
500
        void                    cleared();
501 502 503 504 505 506 507

        /**
         *  \brief  Emitted when the global length of the workflow changes.
         *
         *  \param  newLength   The new length, in frames
         */
        void                    lengthChanged( qint64 );
508 509 510
};

#endif // MAINWORKFLOW_H