Commit feb939d9 authored by Hugo Beauzee-Luyssen's avatar Hugo Beauzee-Luyssen

Adding doc to MainWorkflow.h

Removed useless mutex, useless method, reordered inludes as defined in HACKING
parent 741b5378
......@@ -39,7 +39,6 @@ MainWorkflow::MainWorkflow( int trackCount ) :
{
m_currentFrameLock = new QReadWriteLock;
m_renderStartedLock = new QReadWriteLock;
m_renderMutex = new QMutex;
const SettingValue* width = SettingsManager::getInstance()->getValue( "project", "VideoProjectWidth" );
connect( width, SIGNAL( changed( QVariant ) ), this, SLOT( widthChanged( QVariant ) ) );
......@@ -72,7 +71,6 @@ MainWorkflow::~MainWorkflow()
stop();
delete m_effectEngine;
delete m_renderMutex;
delete m_renderStartedLock;
delete m_currentFrameLock;
delete m_currentFrame;
......@@ -119,11 +117,10 @@ void MainWorkflow::startRender()
MainWorkflow::OutputBuffers* MainWorkflow::getOutput( TrackType trackType )
{
QReadLocker lock( m_renderStartedLock );
QMutexLocker lock2( m_renderMutex );
if ( m_renderStarted == true )
{
QReadLocker lock3( m_currentFrameLock );
QReadLocker lock2( m_currentFrameLock );
m_tracks[trackType]->getOutput( m_currentFrame[VideoTrack], m_currentFrame[trackType] );
if ( trackType == MainWorkflow::VideoTrack )
......@@ -145,26 +142,15 @@ MainWorkflow::OutputBuffers* MainWorkflow::getOutput( TrackType trackType )
void MainWorkflow::pause()
{
{
//Just wait for the current render to finish
//TODO:
//FIXME: check if this is not alreay handled by the stacked actions system.
QMutexLocker lock( m_renderMutex );
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
m_tracks[i]->pause();
}
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
m_tracks[i]->pause();
emit mainWorkflowPaused();
}
void MainWorkflow::unpause()
{
{
QMutexLocker lock( m_renderMutex );
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
m_tracks[i]->unpause();
}
for ( unsigned int i = 0; i < MainWorkflow::NbTrackType; ++i )
m_tracks[i]->unpause();
emit mainWorkflowUnpaused();
}
......
......@@ -27,100 +27,263 @@
#include "Singleton.hpp"
#include "AudioClipWorkflow.h"
class QDomDocument;
class QDomElement;
class QMutex;
class QReadWriteLock;
class QDomElement;
class QDomDocument;
class Clip;
class LightVideoFrame;
class EffectsEngine;
class TrackWorkflow;
class LightVideoFrame;
class TrackHandler;
class TrackWorkflow;
#include <QObject>
#include <QUuid>
/**
* \class Represent the Timeline backend.
*/
class MainWorkflow : public QObject, public Singleton<MainWorkflow>
{
Q_OBJECT
public:
/**
* \struct Represents an output, with both audio and video buffers.
* Note that an OutputBuffers will not necessarly have its both
* fields filed out.
*/
struct OutputBuffers
{
const LightVideoFrame* video;
AudioClipWorkflow::AudioSample* audio;
};
/**
* \enum Represents the potential Track types.
*/
enum TrackType
{
VideoTrack,
AudioTrack,
NbTrackType,
VideoTrack, ///< Represents a video track
AudioTrack, ///< Represents an audio track
NbTrackType, ///< Used to know how many types we have
};
/**
* \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.
*/
enum FrameChangedReason
{
Renderer,
Renderer, ///< Used by the WorkflowRenderer
/**
* \brief Used by the timeline cursor.
* \warning The timeline cursor is not the timeline ruler
*/
TimelineCursor,
PreviewCursor,
RulerCursor,
PreviewCursor, ///< Used by the preview widget, when using the time cursor.
RulerCursor, ///< Used by the timeline's ruler.
};
void addClip( Clip* clip, unsigned int trackId, qint64 start, TrackType type );
/**
* \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 );
/**
* \brief Initialize the workflow for the render.
*
* This will basically activate all the tracks, so they can render.
*/
void startRender();
/**
* \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.
*/
OutputBuffers* getOutput( TrackType trackType );
/**
* \brief Returns the effect engine instance used by the workflow
*
* \return The effect engine instance used by the workflow
*/
EffectsEngine* getEffectsEngine();
/**
* \brief This method is meant to make the workflow go to the next frame, only in rendering mode.
* The nextFrame() method will always go for the next frame, whereas this one only does when
* rendering isn't paused.
* \brief This method is meant to make the workflow go to the next
* frame, only in rendering mode.
*
* The nextFrame() method will always go for the next frame, whereas this one
* only does when rendering isn't paused.
* \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 nextFrame( MainWorkflow::TrackType )
* \todo check if this is still usefull.
*/
void goToNextFrame( MainWorkflow::TrackType trackype );
/**
* \brief Set the workflow position by the desired frame
* \param currentFrame: The desired frame to render from
* \paragraph reason: The program part which required this frame change
* \param reason: The program part which required this frame change
(to avoid cyclic events)
*/
void setCurrentFrame( qint64 currentFrame,
MainWorkflow::FrameChangedReason reason );
MainWorkflow::FrameChangedReason reason );
/**
* \brief Get the workflow length in frames.
* \return Returns the global length of the workflow
* in frames.
*/
qint64 getLengthFrame() const;
/**
* \brief Get the currently rendered frame.
* \return Returns the current frame.
*/
qint64 getCurrentFrame() const;
/**
* Stop the workflow (including sub track workflows and clip workflows)
* \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
*/
void stop();
/**
* Pause the main workflow and all its sub-workflows
* \brief Pause the workflow.
*
* This will cause the mainworkflow to render the same frame over and over again
* if calling getOutput().
*
* \sa unpause()
*/
void pause();
/**
* \brief Unpause the workflow.
*
* \sa pause()
*/
void unpause();
/**
* \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 goToNextFrame( MainWorkflow::TrackType )
* \sa previousFrame( MainWorkflow::TrackType );
*/
void nextFrame( TrackType trackType );
/**
* \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 );
*/
void previousFrame( TrackType trackType );
Clip* removeClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType );
/**
* \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 );
/**
* \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 )
*/
void moveClip( const QUuid& uuid, unsigned int oldTrack,
unsigned int newTrack, qint64 pos,
MainWorkflow::TrackType trackType, bool undoRedoCommand = false );
qint64 getClipPosition( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType ) const;
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;
void muteTrack( unsigned int trackId, MainWorkflow::TrackType );
void unmuteTrack( unsigned int trackId, MainWorkflow::TrackType );
/**
* \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 );
/**
* \param uuid : The clip's uuid.
......@@ -130,66 +293,208 @@ class MainWorkflow : public QObject, public Singleton<MainWorkflow>
* \param trackType : the track type (audio or video)
* \returns The clip that matches the given UUID.
*/
Clip* getClip( const QUuid& uuid, unsigned int trackId, MainWorkflow::TrackType trackType );
Clip* getClip( const QUuid& uuid, unsigned int trackId,
MainWorkflow::TrackType trackType );
/**
* \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
*/
int getTrackCount( MainWorkflow::TrackType trackType ) const;
/**
* \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()
*/
uint32_t getWidth() const;
/**
* \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()
*/
uint32_t getHeight() const;
private:
MainWorkflow( int trackCount = 64 );
~MainWorkflow();
/**
* \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
*/
void computeLength();
void activateTrack( unsigned int trackId );
private:
/// Lock for the m_currentFrame atribute.
QReadWriteLock* m_currentFrameLock;
/**
* \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.
*/
qint64* m_currentFrame;
/// The workflow length, in frame.
qint64 m_lengthFrame;
/**
* This boolean describe is a render has been started
*/
/// This boolean describe is a render has been started
bool m_renderStarted;
QReadWriteLock* m_renderStartedLock;
QMutex* m_renderMutex;
/// True if the workflow is paused
bool m_paused;
/// Contains the trackhandler, indexed by MainWorkflow::TrackType
TrackHandler** m_tracks;
/// Pre-allocated buffer, that will contain every computed outputs.
OutputBuffers* m_outputBuffers;
/// Effect engine instance.
EffectsEngine* m_effectEngine;
/// Width used for the render
uint32_t m_width;
/// Height used the render
uint32_t m_height;
/// Pre-filled buffer used when there's nothing to render
static LightVideoFrame* blackOutput;
friend class Singleton<MainWorkflow>;
friend class Singleton<MainWorkflow>;
private slots:
/**
* \brief Called when a track end is reached
*
* If all track has reached end, the mainWorkflowEndReached() signal will be
* emitted;
* \sa mainWorkflowEndReached()
*/
void tracksEndReached();
/**
* \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
*/
void widthChanged( const QVariant& );
/**
* \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
*/
void heightChanged( const QVariant& );
public slots:
/**
* \brief load a project based on a QDomElement
*
* \param project The project node to load.
*/
void loadProject( const QDomElement& project );
/**
* \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.
*/
void saveProject( QDomDocument& doc, QDomElement& rootNode );
/**
* \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()
*/
void clear();
signals:
/**
* \brief Used to notify a change to the timeline and preview widget cursor
* \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"
*/
void frameChanged( qint64,
MainWorkflow::FrameChangedReason );
void frameChanged( qint64 newFrame,
MainWorkflow::FrameChangedReason reason );
/**
* \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)
*/
void mainWorkflowEndReached();
void clipAdded( Clip*, unsigned int, qint64, MainWorkflow::TrackType );
void clipRemoved( Clip*, unsigned int, MainWorkflow::TrackType );
void clipMoved( QUuid, unsigned int, qint64, MainWorkflow::TrackType );
/**
* \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();
*/
void cleared();
/**
* \brief Emitted when the workflow is paused.
*
* \sa pause();
* \sa unpause();
*/
void mainWorkflowPaused();
/**
* \brief Emitted when the workflow is unpaused.
*
* \sa pause();
* \sa unpause();
*/
void mainWorkflowUnpaused();
};
......
......@@ -433,6 +433,7 @@ void TrackWorkflow::clear()
{
//The clip contained in the trackworkflow will be delete by the undo stack.
ClipWorkflow* cw = it.value();
delete cw->getClip();
delete cw;
}
m_clips.clear();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment