Commit 24aac434 authored by luyikei's avatar luyikei

Workflow: Commands: Implement transition API

parent d5cf70b5
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "AbstractUndoStack.h" #include "AbstractUndoStack.h"
#include "Backend/IFilter.h" #include "Backend/IFilter.h"
#include "Library/Library.h" #include "Library/Library.h"
#include "Transition/Transition.h"
#ifdef HAVE_GUI #ifdef HAVE_GUI
# include "Gui/timeline/MarkerManager.h" # include "Gui/timeline/MarkerManager.h"
...@@ -570,6 +571,172 @@ Commands::Effect::Remove::internalUndo() ...@@ -570,6 +571,172 @@ Commands::Effect::Remove::internalUndo()
m_helper->setTarget( m_target.get() ); m_helper->setTarget( m_target.get() );
} }
Commands::Transition::Add::Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type )
: m_identifier( identifier )
, m_begin( begin )
, m_end( end )
, m_trackId( trackId )
, m_trackAId( 0 )
, m_trackBId( 0 )
, m_type( type )
, m_workflow( workflow )
{
retranslate();
}
Commands::Transition::Add::Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId,
Workflow::TrackType type )
: m_identifier( identifier )
, m_begin( begin )
, m_end( end )
, m_trackAId( trackAId )
, m_trackBId( trackBId )
, m_type( type )
, m_workflow( workflow )
{
retranslate();
}
void
Commands::Transition::Add::internalRedo()
{
if ( m_uuid.isNull() == true )
{
if ( m_trackBId > 0 )
m_uuid = m_workflow->addTransitionBetweenTracks( m_identifier, m_begin, m_end, m_trackAId, m_trackBId, m_type );
else
m_uuid = m_workflow->addTransition( m_identifier, m_begin, m_end, m_trackId, m_type );
}
else
m_workflow->addTransition( m_transitionInstance );
}
void
Commands::Transition::Add::internalUndo()
{
m_transitionInstance = m_workflow->removeTransition( m_uuid );
}
void
Commands::Transition::Add::retranslate()
{
setText( tr( "Adding transition" ) );
}
const QUuid&
Commands::Transition::Add::uuid()
{
return m_uuid;
}
Commands::Transition::Move::Move( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, qint64 begin, qint64 end )
: m_uuid( uuid )
, m_begin( begin )
, m_end( end )
, m_workflow( workflow )
{
auto transitionInstance = m_workflow->transition( uuid );
if ( transitionInstance == nullptr )
invalidate();
else
{
m_oldBegin = transitionInstance->transition->begin();
m_oldEnd = transitionInstance->transition->end();
}
retranslate();
}
void
Commands::Transition::Move::internalRedo()
{
bool ret = m_workflow->moveTransition( m_uuid, m_begin, m_end );
if ( ret == false )
invalidate();
}
void
Commands::Transition::Move::internalUndo()
{
bool ret = m_workflow->moveTransition( m_uuid, m_oldBegin, m_oldEnd );
if ( ret == false )
invalidate();
}
void
Commands::Transition::Move::retranslate()
{
setText( tr( "Moving transition" ) );
}
Commands::Transition::MoveBetweenTracks::MoveBetweenTracks( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, quint32 trackAId, quint32 trackBId )
: m_uuid( uuid )
, m_trackAId( trackAId )
, m_trackBId( trackBId )
, m_workflow( workflow )
{
auto transitionInstance = m_workflow->transition( uuid );
if ( transitionInstance == nullptr )
invalidate();
else
{
m_oldTrackAId = transitionInstance->trackAId;
m_oldTrackBId = transitionInstance->trackBId;
}
retranslate();
}
void
Commands::Transition::MoveBetweenTracks::internalRedo()
{
bool ret = m_workflow->moveTransitionBetweenTracks( m_uuid, m_trackAId, m_trackBId );
if ( ret == false )
invalidate();
}
void
Commands::Transition::MoveBetweenTracks::internalUndo()
{
bool ret = m_workflow->moveTransitionBetweenTracks( m_uuid, m_oldTrackAId, m_oldTrackBId );
if ( ret == false )
invalidate();
}
void
Commands::Transition::MoveBetweenTracks::retranslate()
{
setText( tr( "Moving transition" ) );
}
Commands::Transition::Remove::Remove( std::shared_ptr<SequenceWorkflow> const& workflow, const QUuid& uuid )
: m_uuid( uuid )
, m_workflow( workflow )
{
retranslate();
}
void
Commands::Transition::Remove::internalRedo()
{
m_transitionInstance = m_workflow->removeTransition( m_uuid );
}
void
Commands::Transition::Remove::internalUndo()
{
m_workflow->addTransition( m_transitionInstance );
}
void Commands::Transition::Remove::retranslate()
{
setText( tr( "Removing transition" ) );
}
#ifdef HAVE_GUI #ifdef HAVE_GUI
Commands::Marker::Add::Add( QSharedPointer<MarkerManager> markerManager, quint64 pos ) Commands::Marker::Add::Add( QSharedPointer<MarkerManager> markerManager, quint64 pos )
: m_markerManager( markerManager ) : m_markerManager( markerManager )
......
...@@ -37,13 +37,14 @@ ...@@ -37,13 +37,14 @@
#include <memory> #include <memory>
class Clip; class Clip;
class EffectHelper;
class Transition;
class MarkerManager;
namespace Backend namespace Backend
{ {
class IInput; class IInput;
} }
class EffectHelper;
class MarkerManager;
namespace Commands namespace Commands
{ {
...@@ -281,6 +282,84 @@ namespace Commands ...@@ -281,6 +282,84 @@ namespace Commands
}; };
} }
namespace Transition
{
class Add : public Generic
{
public:
Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type );
Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId, Workflow::TrackType type );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
const QUuid& uuid();
private:
QString m_identifier;
qint64 m_begin;
qint64 m_end;
quint32 m_trackId;
quint32 m_trackAId;
quint32 m_trackBId;
Workflow::TrackType m_type;
QUuid m_uuid;
QSharedPointer<SequenceWorkflow::TransitionInstance> m_transitionInstance;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class Move : public Generic
{
public:
Move( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, qint64 begin, qint64 end );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
qint64 m_begin;
qint64 m_end;
qint64 m_oldBegin;
qint64 m_oldEnd;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class MoveBetweenTracks : public Generic
{
public:
MoveBetweenTracks( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, quint32 trackAId, quint32 trackBId );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
quint32 m_trackAId;
quint32 m_trackBId;
quint32 m_oldTrackAId;
quint32 m_oldTrackBId;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class Remove : public Generic
{
public:
Remove( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
QSharedPointer<SequenceWorkflow::TransitionInstance> m_transitionInstance;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
}
#ifdef HAVE_GUI #ifdef HAVE_GUI
// Gui commands // Gui commands
namespace Marker namespace Marker
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "Tools/VlmcDebug.h" #include "Tools/VlmcDebug.h"
#include "Tools/RendererEventWatcher.h" #include "Tools/RendererEventWatcher.h"
#include "Tools/OutputEventWatcher.h" #include "Tools/OutputEventWatcher.h"
#include "Transition/Transition.h"
#include "Workflow/Types.h" #include "Workflow/Types.h"
#include <QJsonArray> #include <QJsonArray>
...@@ -67,6 +68,9 @@ MainWorkflow::MainWorkflow( Settings* projectSettings, int trackCount ) : ...@@ -67,6 +68,9 @@ MainWorkflow::MainWorkflow( Settings* projectSettings, int trackCount ) :
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipUnlinked, this, &MainWorkflow::clipUnlinked ); connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipUnlinked, this, &MainWorkflow::clipUnlinked );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipMoved, this, &MainWorkflow::clipMoved ); connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipMoved, this, &MainWorkflow::clipMoved );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipResized, this, &MainWorkflow::clipResized ); connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipResized, this, &MainWorkflow::clipResized );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionAdded, this, &MainWorkflow::transitionAdded );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionMoved, this, &MainWorkflow::transitionMoved );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionRemoved, this, &MainWorkflow::transitionRemoved );
m_renderer->setInput( m_sequenceWorkflow->input() ); m_renderer->setInput( m_sequenceWorkflow->input() );
connect( m_renderer->eventWatcher().data(), &RendererEventWatcher::lengthChanged, this, &MainWorkflow::lengthChanged ); connect( m_renderer->eventWatcher().data(), &RendererEventWatcher::lengthChanged, this, &MainWorkflow::lengthChanged );
...@@ -244,6 +248,15 @@ MainWorkflow::libraryClipInfo( const QString& uuid ) ...@@ -244,6 +248,15 @@ MainWorkflow::libraryClipInfo( const QString& uuid )
return QJsonObject::fromVariantHash( h ); return QJsonObject::fromVariantHash( h );
} }
QJsonObject
MainWorkflow::transitionInfo( const QString& uuid )
{
auto t = m_sequenceWorkflow->transition( uuid );
if ( !t )
return {};
return QJsonObject::fromVariantHash( t->toVariant().toHash() );
}
void void
MainWorkflow::moveClip( const QString& uuid, quint32 trackId, qint64 startFrame ) MainWorkflow::moveClip( const QString& uuid, quint32 trackId, qint64 startFrame )
{ {
...@@ -305,6 +318,43 @@ MainWorkflow::addEffect( const QString &clipUuid, const QString &effectId ) ...@@ -305,6 +318,43 @@ MainWorkflow::addEffect( const QString &clipUuid, const QString &effectId )
return QStringLiteral( "" ); return QStringLiteral( "" );
} }
QString
MainWorkflow::addTransition( const QString& identifier, qint64 begin, qint64 end, quint32 trackId, const QString& type )
{
auto trackType = type == QStringLiteral( "Video" ) ? Workflow::VideoTrack : Workflow::AudioTrack;
auto command = new Commands::Transition::Add( m_sequenceWorkflow, identifier, begin, end, trackId, trackType );
trigger( command );
return command->uuid().toString();
}
QString
MainWorkflow::addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end, quint32 trackAId, quint32 trackBId,
const QString& type )
{
auto trackType = type == QStringLiteral( "Video" ) ? Workflow::VideoTrack : Workflow::AudioTrack;
auto command = new Commands::Transition::Add( m_sequenceWorkflow, identifier, begin, end, trackAId, trackBId, trackType );
trigger( command );
return command->uuid().toString();
}
void
MainWorkflow::moveTransition( const QUuid& uuid, qint64 begin, qint64 end )
{
trigger( new Commands::Transition::Move( m_sequenceWorkflow, uuid, begin, end ) );
}
void
MainWorkflow::moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId )
{
trigger( new Commands::Transition::MoveBetweenTracks( m_sequenceWorkflow, uuid, trackAId, trackBId ) );
}
void
MainWorkflow::removeTransition( const QUuid& uuid )
{
trigger( new Commands::Transition::Remove( m_sequenceWorkflow, uuid ) );
}
bool bool
MainWorkflow::startRenderToFile( const QString &outputFileName, quint32 width, quint32 height, MainWorkflow::startRenderToFile( const QString &outputFileName, quint32 width, quint32 height,
double fps, const QString &ar, quint32 vbitrate, quint32 abitrate, double fps, const QString &ar, quint32 vbitrate, quint32 abitrate,
......
...@@ -128,6 +128,9 @@ class MainWorkflow : public QObject ...@@ -128,6 +128,9 @@ class MainWorkflow : public QObject
Q_INVOKABLE Q_INVOKABLE
QJsonObject libraryClipInfo( const QString& uuid ); QJsonObject libraryClipInfo( const QString& uuid );
Q_INVOKABLE
QJsonObject transitionInfo( const QString& uuid );
Q_INVOKABLE Q_INVOKABLE
void moveClip( const QString& uuid, quint32 trackId, qint64 startFrame ); void moveClip( const QString& uuid, quint32 trackId, qint64 startFrame );
...@@ -150,6 +153,23 @@ class MainWorkflow : public QObject ...@@ -150,6 +153,23 @@ class MainWorkflow : public QObject
Q_INVOKABLE Q_INVOKABLE
QString addEffect( const QString& clipUuid, const QString& effectId ); QString addEffect( const QString& clipUuid, const QString& effectId );
Q_INVOKABLE
QString addTransition( const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, const QString& type );
Q_INVOKABLE
QString addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId, const QString& type );
Q_INVOKABLE
void moveTransition( const QUuid& uuid, qint64 begin, qint64 end );
Q_INVOKABLE
void moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId );
Q_INVOKABLE
void removeTransition( const QUuid& uuid );
bool startRenderToFile( const QString& outputFileName, quint32 width, quint32 height, bool startRenderToFile( const QString& outputFileName, quint32 width, quint32 height,
double fps, const QString& ar, quint32 vbitrate, quint32 abitrate, double fps, const QString& ar, quint32 vbitrate, quint32 abitrate,
quint32 nbChannels, quint32 sampleRate ); quint32 nbChannels, quint32 sampleRate );
...@@ -247,6 +267,10 @@ class MainWorkflow : public QObject ...@@ -247,6 +267,10 @@ class MainWorkflow : public QObject
void clipLinked( const QString& uuidA, const QString& uuidB ); void clipLinked( const QString& uuidA, const QString& uuidB );
void clipUnlinked( const QString& uuidA, const QString& uuidB ); void clipUnlinked( const QString& uuidA, const QString& uuidB );
void transitionAdded( const QString& uuid );
void transitionMoved( const QString& uuid );
void transitionRemoved( const QString& uuid );
void effectsUpdated( const QString& clipUuid ); void effectsUpdated( const QString& clipUuid );
}; };
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "Library/Library.h" #include "Library/Library.h"
#include "Tools/VlmcDebug.h" #include "Tools/VlmcDebug.h"
#include "Media/Media.h" #include "Media/Media.h"
#include "Transition/Transition.h"
SequenceWorkflow::SequenceWorkflow( size_t trackCount ) SequenceWorkflow::SequenceWorkflow( size_t trackCount )
: m_multitrack( new Backend::MLT::MLTMultiTrack ) : m_multitrack( new Backend::MLT::MLTMultiTrack )
...@@ -216,9 +217,108 @@ SequenceWorkflow::unlinkClips( const QUuid& uuidA, const QUuid& uuidB ) ...@@ -216,9 +217,108 @@ SequenceWorkflow::unlinkClips( const QUuid& uuidA, const QUuid& uuidB )
return ret; return ret;
} }
QUuid
SequenceWorkflow::addTransition( const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type )
{
auto t = track( trackId, type == Workflow::AudioTrack );
auto transition = QSharedPointer<Transition>::create( identifier, begin, end, type );
t->addTransition( transition );
m_transitions.insert( transition->uuid(), QSharedPointer<TransitionInstance>::create( transition, trackId, 0, true ) );
emit transitionAdded( transition->uuid().toString() );
return transition->uuid();
}
QUuid
SequenceWorkflow::addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId,
Workflow::TrackType type )
{
auto transition = QSharedPointer<Transition>::create( identifier, begin, end, type );
m_transitions.insert( transition->uuid(), QSharedPointer<TransitionInstance>::create( transition, trackAId, trackBId, false ) );
transition->apply( *m_multitrack, trackAId, trackBId );
emit transitionAdded( transition->uuid().toString() );
return transition->uuid();
}
bool
SequenceWorkflow::addTransition( QSharedPointer<TransitionInstance> transitionInstance )
{
auto transition = transitionInstance->transition;
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
m_transitions.insert( transition->uuid(), transitionInstance );
emit transitionAdded( transition->uuid().toString() );
return t->addTransition( transition );
}
bool
SequenceWorkflow::moveTransition( const QUuid& uuid, qint64 begin, qint64 end )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return false;
auto transitionInstance = it.value();
auto transition = transitionInstance->transition;
if ( transition->begin() == begin && transition->end() == end )
return true;
if ( transitionInstance->isInTrack == true )
{
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
emit transitionMoved( uuid.toString() );
return t->moveTransition( uuid, begin, end );
}
else
{
transition->setBoundaries( begin, end );
emit transitionMoved( uuid.toString() );
return true;
}
}
bool
SequenceWorkflow::moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return false;
auto transitionInstance = it.value();
if ( transitionInstance->isInTrack == true )
return false; // Not allowed
auto transition = transitionInstance->transition;
if ( transitionInstance->trackAId == trackAId && transitionInstance->trackBId == trackBId )
return true;
transition->setTracks( trackAId, trackBId );
transitionInstance->trackAId = trackAId;
transitionInstance->trackBId = trackBId;
emit transitionMoved( uuid.toString() );
return true;
}
QSharedPointer<SequenceWorkflow::TransitionInstance>
SequenceWorkflow::removeTransition( const QUuid& uuid )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return {};
auto transitionInstance = it.value();
if ( transitionInstance->isInTrack == true )
{
auto transition = transitionInstance->transition;
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
t->removeTransition( uuid );
}
m_transitions.erase( it );
emit transitionRemoved( uuid.toString() );
return transitionInstance;
}
QVariant QVariant
SequenceWorkflow::toVariant() const SequenceWorkflow::toVariant() const
{ {
QVariantList transitions;
for ( const auto& t : m_transitions )
transitions << t->toVariant();
QVariantList l; QVariantList l;
for ( auto it = m_clips.begin(); it != m_clips.end(); ++it ) for ( auto it = m_clips.begin(); it != m_clips.end(); ++it )
{ {
...@@ -237,13 +337,26 @@ SequenceWorkflow::toVariant() const ...@@ -237,13 +337,26 @@ SequenceWorkflow::toVariant() const
h["linkedClips"] = linkedClipList; h["linkedClips"] = linkedClipList;
l << h; l << h;
} }
QVariantHash h{ { "clips", l }, { "filters", EffectHelper::toVariant( m_multitrack ) } }; QVariantHash h{ { "transitions", transitions }, { "clips", l },
{ "filters", EffectHelper::toVariant( m_multitrack.get() ) } };
return h; return h;
} }
void void
SequenceWorkflow::loadFromVariant( const QVariant& variant ) SequenceWorkflow::loadFromVariant( const QVariant& variant )
{ {
for ( auto& var : variant.toMap()["transitions"].toList() )
{
auto m = var.toMap();
bool inTrack = m["isInTrack"].toBool();
if ( inTrack == true )
addTransition( m["identifier"].toString(), m["begin"].toLongLong(), m["end"].toLongLong(),
m["trackId"].toUInt(), m["audio"].toBool() ? Workflow::AudioTrack : Workflow::VideoTrack );
else
addTransitionBetweenTracks( m["identifier"].toString(), m["begin"].toLongLong(), m["end"].toLongLong(),
m["trackAId"].toUInt(), m["trackBId"].toUInt(), m["audio"].toBool() ? Workflow::AudioTrack : Workflow::VideoTrack );
}
for ( auto& var : variant.toMap()["clips"].toList() ) for ( auto& var : variant.toMap()["clips"].toList() )
{ {
auto m = var.toMap(); auto m = var.toMap();
...@@ -294,6 +407,15 @@ SequenceWorkflow::clip( const QUuid& uuid ) ...@@ -294,6 +407,15 @@ SequenceWorkflow::clip( const QUuid& uuid )
return it.value(); return it.value();
} }
QSharedPointer<SequenceWorkflow::TransitionInstance>
SequenceWorkflow::transition( const QUuid& uuid )
{
auto it = m_transitions.find( uuid );