MainWorkflow.h 22.7 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.h : 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.
 *****************************************************************************/

#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
120
        /**
         *  \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.
         */
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
121
        OutputBuffers*          getOutput( TrackType trackType );
122
123
124
125
126
        /**
         *  \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
127
        EffectsEngine*          getEffectsEngine();
128

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

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

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

151
        /**
152
153
154
155
156
         *  \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
157
158
159
         */
        void                    stop();

160
        /**
161
162
163
164
165
166
         *  \brief              Pause the workflow.
         *
         *  This will cause the mainworkflow to render the same frame over and over again
         *  if calling getOutput().
         *
         *  \sa                 unpause()
167
168
         */
        void                    pause();
169
170
171
172
173
        /**
         *  \brief              Unpause the workflow.
         *
         *  \sa                 pause()
         */
174
        void                    unpause();
175

176
177
178
179
180
181
182
183
184
        /**
         *  \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
185
        void                    nextFrame( TrackType trackType );
186
187
188
189
190
191
192
193
194
        /**
         *  \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
195
        void                    previousFrame( TrackType trackType );
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
        /**
         *  \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 );
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
        /**
         *  \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 )
         */
235
        void                    moveClip( const QUuid& uuid, unsigned int oldTrack,
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
236
                                          unsigned int newTrack, qint64 pos,
237
238
239
240
241
242
243
244
245
246
247
248
249
                                          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;
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
        /**
         *  \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 );
271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        /**
         *  \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 );

292
293
294
295
296
        /**
         * \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
297
         *  \param  trackType : the track type (audio or video)
298
299
         *  \returns    The clip that matches the given UUID.
         */
300
301
        Clip*                   getClip( const QUuid& uuid, unsigned int trackId,
                                         MainWorkflow::TrackType trackType );
302

303
304
305
306
307
308
        /**
         *  \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
         */
309
        int                     getTrackCount( MainWorkflow::TrackType trackType ) const;
310

311
312
313
314
315
316
317
318
319
        /**
         *  \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()
         */
320
        quint32                getWidth() const;
321
322
323
324
325
326
327
328
329
        /**
         *  \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()
         */
330
        quint32                getHeight() const;
331

332
333
334
335
336
337
338
339
        /**
         *  \brief          Will render one frame only
         *
         *  It will change the ClipWorkflow frame getting mode from Get to Pop, just for
         *  one frame
         */
        void                    renderOneFrame();

340
341
342
343
344
345
346
347
348
        /**
         *  \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 );

349
350
351
        /// Pre-filled buffer used when there's nothing to render
        static LightVideoFrame*         blackOutput;

352
    private:
353
        MainWorkflow( int trackCount = 64 );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
354
        ~MainWorkflow();
355
356
357
358
359
360
361
        /**
         *  \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
         */
362
363
        void                    computeLength();

364
    private:
365
        /// Lock for the m_currentFrame atribute.
366
        QReadWriteLock*                 m_currentFrameLock;
367
368
369
370
371
372
373
374
375
376
        /**
         *  \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
377
        qint64*                         m_currentFrame;
378
        /// The workflow length, in frame.
379
        qint64                          m_lengthFrame;
380
        /// This boolean describe is a render has been started
381
        bool                            m_renderStarted;
382
        QReadWriteLock*                 m_renderStartedLock;
383

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

389
        /// Effect engine instance.
390
        EffectsEngine*                  m_effectEngine;
391
        /// Width used for the render
392
        quint32                         m_width;
393
        /// Height used the render
394
        quint32                         m_height;
395

396
        friend class                    Singleton<MainWorkflow>;
397

398
    private slots:
399
400
401
402
403
404
405
        /**
         *  \brief  Called when a track end is reached
         *
         *  If all track has reached end, the mainWorkflowEndReached() signal will be
         *  emitted;
         *  \sa     mainWorkflowEndReached()
         */
406
        void                            tracksEndReached();
407
408
409
410
411
        /**
         *  \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
         */
412
        void                            widthChanged( const QVariant& );
413
414
415
416
417
        /**
         *  \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
         */
418
419
        void                            heightChanged( const QVariant& );

420

421
    public slots:
422
423
424
425
426
        /**
         *  \brief  load a project based on a QDomElement
         *
         *  \param  project             The project node to load.
         */
427
        void                            loadProject( const QDomElement& project );
428
429
430
431
432
433
        /**
         *  \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.
         */
434
        void                            saveProject( QDomDocument& doc, QDomElement& rootNode );
435
436
437
438
439
440
441
442
443
        /**
         *  \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()
         */
444
        void                            clear();
445

446
    signals:
447
        /**
448
449
450
451
452
         *  \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"
453
         */
454
455
        void                    frameChanged( qint64 newFrame,
                                              MainWorkflow::FrameChangedReason reason );
456

457
458
459
460
461
462
        /**
         *  \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)
         */
463
        void                    mainWorkflowEndReached();
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
500
501
502
        /**
         *  \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();
         */
503
        void                    cleared();
504
505
506
507
508
509
        /**
         *  \brief  Emitted when the workflow is paused.
         *
         *  \sa     pause();
         *  \sa     unpause();
         */
510
        void                    mainWorkflowPaused();
511
512
513
514
515
516
        /**
         *  \brief  Emitted when the workflow is unpaused.
         *
         *  \sa     pause();
         *  \sa     unpause();
         */
517
        void                    mainWorkflowUnpaused();
518
519
520
521
522
523
524

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

#endif // MAINWORKFLOW_H