mirror of
https://invent.kde.org/multimedia/kdenlive
synced 2025-12-05 15:59:59 +01:00
Cleanup, use MLT::Link for avfilters
This commit is contained in:
@@ -917,9 +917,9 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
|||||||
if (qFuzzyCompare(speed, 1.0) && !timeremapInfo.enableRemap) {
|
if (qFuzzyCompare(speed, 1.0) && !timeremapInfo.enableRemap) {
|
||||||
// we are requesting a normal speed producer
|
// we are requesting a normal speed producer
|
||||||
bool byPassTrackProducer = false;
|
bool byPassTrackProducer = false;
|
||||||
if (trackId == -1 && (state != PlaylistState::AudioOnly || audioStream == m_masterProducer->get_int("audio_index"))) {
|
/*if (trackId == -1 && (state != PlaylistState::AudioOnly || audioStream == m_masterProducer->get_int("audio_index"))) {
|
||||||
byPassTrackProducer = true;
|
byPassTrackProducer = true;
|
||||||
}
|
}*/
|
||||||
int maxDuration = 0;
|
int maxDuration = 0;
|
||||||
if (m_clipType == ClipType::Timeline && m_masterProducer->parent().property_exists("kdenlive:maxduration")) {
|
if (m_clipType == ClipType::Timeline && m_masterProducer->parent().property_exists("kdenlive:maxduration")) {
|
||||||
int duration = m_masterProducer->parent().get_int("kdenlive:maxduration");
|
int duration = m_masterProducer->parent().get_int("kdenlive:maxduration");
|
||||||
@@ -947,6 +947,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
|||||||
return prod;
|
return prod;
|
||||||
}
|
}
|
||||||
if (m_usedProducers.count(clipId) > 0) {
|
if (m_usedProducers.count(clipId) > 0) {
|
||||||
|
qDebug() << ":::: REQUESTING PRODUCER FOR CLIP: " << clipId << " ALREADY EXISTS!!!";
|
||||||
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
|
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
|
||||||
return std::shared_ptr<Mlt::Producer>(m_usedProducers[clipId]->cut(-1, duration > 0 ? duration - 1 : -1));
|
return std::shared_ptr<Mlt::Producer>(m_usedProducers[clipId]->cut(-1, duration > 0 ? duration - 1 : -1));
|
||||||
m_effectStack->removeService(m_usedProducers[clipId]);
|
m_effectStack->removeService(m_usedProducers[clipId]);
|
||||||
@@ -965,22 +966,22 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
|||||||
if (secondPlaylist) {
|
if (secondPlaylist) {
|
||||||
trackId = -trackId;
|
trackId = -trackId;
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<Mlt::Producer> master;
|
||||||
if (m_clipType == ClipType::Timeline) {
|
if (m_clipType == ClipType::Timeline) {
|
||||||
std::shared_ptr<Mlt::Producer> prod(m_masterProducer->cut(0, maxDuration));
|
master.reset(m_masterProducer->cut(0, maxDuration));
|
||||||
m_usedProducers[clipId] = prod;
|
|
||||||
} else {
|
} else {
|
||||||
m_usedProducers[clipId] = cloneProducer(true, true);
|
master = cloneProducer(true, true);
|
||||||
}
|
}
|
||||||
m_usedProducers[clipId]->set("set.test_audio", 0);
|
master->set("set.test_audio", 0);
|
||||||
m_usedProducers[clipId]->set("set.test_image", 1);
|
master->set("set.test_image", 1);
|
||||||
if (m_streamEffects.contains(audioStream)) {
|
if (m_streamEffects.contains(audioStream)) {
|
||||||
QStringList effects = m_streamEffects.value(audioStream);
|
QStringList effects = m_streamEffects.value(audioStream);
|
||||||
for (const QString &effect : std::as_const(effects)) {
|
for (const QString &effect : std::as_const(effects)) {
|
||||||
Mlt::Filter filt(m_usedProducers[clipId]->get_profile(), effect.toUtf8().constData());
|
Mlt::Filter filt(master->get_profile(), effect.toUtf8().constData());
|
||||||
if (filt.is_valid()) {
|
if (filt.is_valid()) {
|
||||||
// Add stream effect markup
|
// Add stream effect markup
|
||||||
filt.set("kdenlive:stream", 1);
|
filt.set("kdenlive:stream", 1);
|
||||||
m_usedProducers[clipId]->attach(filt);
|
master->attach(filt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -989,19 +990,20 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
|||||||
if (newAudioStreamIndex > -1) {
|
if (newAudioStreamIndex > -1) {
|
||||||
/** If the audioStreamIndex is not found, for example when replacing a clip with another one using different indexes,
|
/** If the audioStreamIndex is not found, for example when replacing a clip with another one using different indexes,
|
||||||
default to first audio stream */
|
default to first audio stream */
|
||||||
m_usedProducers[clipId]->set("audio_index", audioStream);
|
master->set("audio_index", audioStream);
|
||||||
} else {
|
} else {
|
||||||
newAudioStreamIndex = 0;
|
newAudioStreamIndex = 0;
|
||||||
}
|
}
|
||||||
if (newAudioStreamIndex > audioStreamsCount() - 1) {
|
if (newAudioStreamIndex > audioStreamsCount() - 1) {
|
||||||
newAudioStreamIndex = 0;
|
newAudioStreamIndex = 0;
|
||||||
}
|
}
|
||||||
m_usedProducers[clipId]->set("astream", newAudioStreamIndex);
|
master->set("astream", newAudioStreamIndex);
|
||||||
}
|
}
|
||||||
m_effectStack->addService(m_usedProducers[clipId]);
|
m_effectStack->addService(master);
|
||||||
std::shared_ptr<Mlt::Producer> prod(m_usedProducers.at(clipId)->cut());
|
m_usedProducers[clipId] = master;
|
||||||
if (m_clipType == ClipType::Timeline && m_usedProducers.at(clipId)->parent().property_exists("kdenlive:maxduration")) {
|
std::shared_ptr<Mlt::Producer> prod(master->cut());
|
||||||
int max = m_usedProducers.at(clipId)->parent().get_int("kdenlive:maxduration");
|
if (m_clipType == ClipType::Timeline && master->parent().property_exists("kdenlive:maxduration")) {
|
||||||
|
int max = master->parent().get_int("kdenlive:maxduration");
|
||||||
prod->set("kdenlive:maxduration", max);
|
prod->set("kdenlive:maxduration", max);
|
||||||
prod->set("length", max);
|
prod->set("length", max);
|
||||||
}
|
}
|
||||||
@@ -1011,25 +1013,28 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
|||||||
// we return the video producer
|
// we return the video producer
|
||||||
// We need to get an video producer, if none exists
|
// We need to get an video producer, if none exists
|
||||||
// second playlist producers use negative trackId
|
// second playlist producers use negative trackId
|
||||||
|
qDebug() << ":::: REQUESTING NEW VIDEO PRODUICER FOR: " << clipId;
|
||||||
if (secondPlaylist) {
|
if (secondPlaylist) {
|
||||||
trackId = -trackId;
|
trackId = -trackId;
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<Mlt::Producer> prod;
|
||||||
if (m_clipType == ClipType::Timeline) {
|
if (m_clipType == ClipType::Timeline) {
|
||||||
std::shared_ptr<Mlt::Producer> prod(m_masterProducer->cut(0, maxDuration));
|
prod.reset(m_masterProducer->cut(0, maxDuration));
|
||||||
m_usedProducers[clipId] = prod;
|
|
||||||
} else {
|
} else {
|
||||||
m_usedProducers[clipId] = cloneProducer(true, true);
|
prod = cloneProducer(true, true);
|
||||||
}
|
}
|
||||||
if (m_masterProducer->property_exists("kdenlive:maxduration")) {
|
if (m_masterProducer->property_exists("kdenlive:maxduration")) {
|
||||||
m_usedProducers[clipId]->set("kdenlive:maxduration", m_masterProducer->get_int("kdenlive:maxduration"));
|
prod->set("kdenlive:maxduration", m_masterProducer->get_int("kdenlive:maxduration"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let audio enabled so that we can use audio visualization filters ?
|
// Let audio enabled so that we can use audio visualization filters ?
|
||||||
m_usedProducers[clipId]->set("set.test_audio", 1);
|
prod->set("set.test_audio", 1);
|
||||||
m_usedProducers[clipId]->set("set.test_image", 0);
|
prod->set("set.test_image", 0);
|
||||||
m_effectStack->addService(m_usedProducers.at(clipId));
|
m_effectStack->addService(prod);
|
||||||
|
m_usedProducers[clipId] = prod;
|
||||||
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
|
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
|
||||||
return std::shared_ptr<Mlt::Producer>(m_usedProducers[clipId]->cut(-1, duration > 0 ? duration - 1 : -1));
|
// return std::shared_ptr<Mlt::Producer>(m_usedProducers[clipId]->cut(-1, duration > 0 ? duration - 1 : -1));
|
||||||
|
return std::shared_ptr<Mlt::Producer>(prod->cut(-1, duration > 0 ? duration - 1 : -1));
|
||||||
}
|
}
|
||||||
Q_ASSERT(state == PlaylistState::Disabled);
|
Q_ASSERT(state == PlaylistState::Disabled);
|
||||||
createDisabledMasterProducer();
|
createDisabledMasterProducer();
|
||||||
@@ -1352,6 +1357,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
|||||||
Q_UNUSED(timelineProducer);
|
Q_UNUSED(timelineProducer);
|
||||||
QMutexLocker lk(&m_producerMutex);
|
QMutexLocker lk(&m_producerMutex);
|
||||||
QReadLocker lock(&pCore->xmlMutex);
|
QReadLocker lock(&pCore->xmlMutex);
|
||||||
|
|
||||||
Mlt::Consumer c(pCore->getProjectProfile(), "xml", "string");
|
Mlt::Consumer c(pCore->getProjectProfile(), "xml", "string");
|
||||||
Mlt::Service s(m_masterProducer->get_service());
|
Mlt::Service s(m_masterProducer->get_service());
|
||||||
m_masterProducer->lock();
|
m_masterProducer->lock();
|
||||||
@@ -1361,10 +1367,10 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
|||||||
}
|
}
|
||||||
c.connect(s);
|
c.connect(s);
|
||||||
c.set("time_format", "frames");
|
c.set("time_format", "frames");
|
||||||
c.set("no_meta", 1);
|
// c.set("no_meta", 1);
|
||||||
c.set("no_root", 1);
|
c.set("no_root", 1);
|
||||||
c.set("no_profile", 1);
|
c.set("no_profile", 1);
|
||||||
c.set("root", "/");
|
c.set("root", "");
|
||||||
c.set("store", "kdenlive");
|
c.set("store", "kdenlive");
|
||||||
c.run();
|
c.run();
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
@@ -1426,6 +1432,26 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
|||||||
delete filter;
|
delete filter;
|
||||||
filter = prod->filter(ct);
|
filter = prod->filter(ct);
|
||||||
}
|
}
|
||||||
|
if (prod->type() == mlt_service_chain_type) {
|
||||||
|
Mlt::Chain fromChain(*prod.get());
|
||||||
|
ct = 0;
|
||||||
|
Mlt::Link *filter = fromChain.link(ct);
|
||||||
|
while (filter) {
|
||||||
|
qDebug() << "// EFFECT " << ct << " : " << filter->get("mlt_service");
|
||||||
|
QString ix = QString::fromLatin1(filter->get("kdenlive_id"));
|
||||||
|
if (!ix.isEmpty()) {
|
||||||
|
qDebug() << "/ + + DELETING";
|
||||||
|
if (fromChain.detach(*filter) == 0) {
|
||||||
|
} else {
|
||||||
|
ct++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ct++;
|
||||||
|
}
|
||||||
|
delete filter;
|
||||||
|
filter = fromChain.link(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
prod->set("id", nullptr);
|
prod->set("id", nullptr);
|
||||||
return prod;
|
return prod;
|
||||||
|
|||||||
@@ -216,11 +216,6 @@ public:
|
|||||||
/** @brief Returns a list of all timeline clip ids for this bin clip */
|
/** @brief Returns a list of all timeline clip ids for this bin clip */
|
||||||
QList<int> timelineInstances(QUuid activeUuid = QUuid()) const;
|
QList<int> timelineInstances(QUuid activeUuid = QUuid()) const;
|
||||||
QMap<QUuid, QList<int>> getAllTimelineInstances() const;
|
QMap<QUuid, QList<int>> getAllTimelineInstances() const;
|
||||||
/** @brief This function returns a cut to the master producer associated to the timeline clip with given ID.
|
|
||||||
Each clip must have a different master producer (see comment of the class)
|
|
||||||
*/
|
|
||||||
std::shared_ptr<Mlt::Producer> getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState st, int audioStream = -1, double speed = 1.0,
|
|
||||||
bool secondPlaylist = false, const TimeWarpInfo timeremapInfo = {});
|
|
||||||
|
|
||||||
/** @brief This function should only be used at loading. It takes a producer that was read from mlt, and checks whether the master producer is already in
|
/** @brief This function should only be used at loading. It takes a producer that was read from mlt, and checks whether the master producer is already in
|
||||||
use. If yes, then we must create a new one, because of the mixing bug. In any case, we return a cut of the master that can be used in the timeline The
|
use. If yes, then we must create a new one, because of the mixing bug. In any case, we return a cut of the master that can be used in the timeline The
|
||||||
@@ -369,7 +364,11 @@ public Q_SLOTS:
|
|||||||
void setInvalid();
|
void setInvalid();
|
||||||
|
|
||||||
void setClipStatus(FileStatus::ClipStatus status) override;
|
void setClipStatus(FileStatus::ClipStatus status) override;
|
||||||
|
/** @brief This function returns a cut to the master producer associated to the timeline clip with given ID.
|
||||||
|
Each clip must have a different master producer (see comment of the class) *
|
||||||
|
*/
|
||||||
|
std::shared_ptr<Mlt::Producer> getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState st, int audioStream = -1, double speed = 1.0,
|
||||||
|
bool secondPlaylist = false, const TimeWarpInfo timeremapInfo = {});
|
||||||
/**
|
/**
|
||||||
* Imports effect from a given producer
|
* Imports effect from a given producer
|
||||||
* @param producer Producer containing the effects
|
* @param producer Producer containing the effects
|
||||||
|
|||||||
@@ -237,11 +237,14 @@ bool EffectsRepository::isPreferred(const QString &effectId) const
|
|||||||
return m_preferred_list.contains(effectId);
|
return m_preferred_list.contains(effectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Mlt::Filter> EffectsRepository::getEffect(const QString &effectId) const
|
std::unique_ptr<Mlt::Properties> EffectsRepository::getEffect(const QString &effectId) const
|
||||||
{
|
{
|
||||||
Q_ASSERT(exists(effectId));
|
Q_ASSERT(exists(effectId));
|
||||||
QString service_name = m_assets.at(effectId).mltId;
|
QString service_name = m_assets.at(effectId).mltId;
|
||||||
// We create the Mlt element from its name
|
// We create the Mlt element from its name
|
||||||
|
if (effectId.startsWith(QStringLiteral("avfilter."))) {
|
||||||
|
return std::make_unique<Mlt::Link>(service_name.toLatin1().constData());
|
||||||
|
}
|
||||||
auto filter = std::make_unique<Mlt::Filter>(pCore->getProjectProfile(), service_name.toLatin1().constData(), nullptr);
|
auto filter = std::make_unique<Mlt::Filter>(pCore->getProjectProfile(), service_name.toLatin1().constData(), nullptr);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public:
|
|||||||
static std::unique_ptr<EffectsRepository> &get();
|
static std::unique_ptr<EffectsRepository> &get();
|
||||||
|
|
||||||
/** @brief returns a fresh instance of the given effect */
|
/** @brief returns a fresh instance of the given effect */
|
||||||
std::unique_ptr<Mlt::Filter> getEffect(const QString &effectId) const;
|
std::unique_ptr<Mlt::Properties> getEffect(const QString &effectId) const;
|
||||||
/** @brief returns true if an effect exists in MLT (bypasses the excludelist/metadata parsing) */
|
/** @brief returns true if an effect exists in MLT (bypasses the excludelist/metadata parsing) */
|
||||||
bool hasInternalEffect(const QString &effectId) const;
|
bool hasInternalEffect(const QString &effectId) const;
|
||||||
QPair<QString, QString> reloadCustom(const QString &path);
|
QPair<QString, QString> reloadCustom(const QString &path);
|
||||||
|
|||||||
@@ -96,7 +96,16 @@ std::shared_ptr<EffectItemModel> EffectItemModel::construct(std::unique_ptr<Mlt:
|
|||||||
void EffectItemModel::plant(const std::weak_ptr<Mlt::Service> &service)
|
void EffectItemModel::plant(const std::weak_ptr<Mlt::Service> &service)
|
||||||
{
|
{
|
||||||
if (auto ptr = service.lock()) {
|
if (auto ptr = service.lock()) {
|
||||||
int ret = ptr->attach(filter());
|
int ret = 0;
|
||||||
|
if (isLink()) {
|
||||||
|
qDebug() << ":::: TRYING TO PLANT LINK...";
|
||||||
|
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
|
||||||
|
ret = fromChain.attach(getLink());
|
||||||
|
} else {
|
||||||
|
qDebug() << ":::: TRYING TO PLANT FILTER...";
|
||||||
|
ret = ptr->attach(getFilter());
|
||||||
|
}
|
||||||
|
qDebug() << ":::: TRYING TO PLANT RESULT: " << ret;
|
||||||
Q_ASSERT(ret == 0);
|
Q_ASSERT(ret == 0);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
|
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
|
||||||
@@ -120,7 +129,7 @@ void EffectItemModel::loadClone(const std::weak_ptr<Mlt::Service> &service)
|
|||||||
int out = m_asset->get_int("out");
|
int out = m_asset->get_int("out");
|
||||||
int in = m_asset->get_int("in");
|
int in = m_asset->get_int("in");
|
||||||
if (out > in) {
|
if (out > in) {
|
||||||
effect->filter().set_in_and_out(in, out);
|
effect->getFilter().set_in_and_out(in, out);
|
||||||
}
|
}
|
||||||
int childId = ptr->get_int("_childid");
|
int childId = ptr->get_int("_childid");
|
||||||
if (childId == 0) {
|
if (childId == 0) {
|
||||||
@@ -164,7 +173,7 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
|
|||||||
int out = m_asset->get_int("out");
|
int out = m_asset->get_int("out");
|
||||||
int in = m_asset->get_int("in");
|
int in = m_asset->get_int("in");
|
||||||
if (out > in) {
|
if (out > in) {
|
||||||
effect->filter().set_in_and_out(in, out);
|
effect->getFilter().set_in_and_out(in, out);
|
||||||
}
|
}
|
||||||
int childId = ptr->get_int("_childid");
|
int childId = ptr->get_int("_childid");
|
||||||
if (childId == 0) {
|
if (childId == 0) {
|
||||||
@@ -172,10 +181,16 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
|
|||||||
ptr->set("_childid", childId);
|
ptr->set("_childid", childId);
|
||||||
}
|
}
|
||||||
if (out > in) {
|
if (out > in) {
|
||||||
effect->filter().set_in_and_out(in, out);
|
effect->getFilter().set_in_and_out(in, out);
|
||||||
}
|
}
|
||||||
m_childEffects.insert(childId, effect);
|
m_childEffects.insert(childId, effect);
|
||||||
int ret = ptr->attach(effect->filter());
|
int ret = 0;
|
||||||
|
if (isLink()) {
|
||||||
|
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
|
||||||
|
ret = fromChain.attach(effect->getLink());
|
||||||
|
} else {
|
||||||
|
ret = ptr->attach(effect->getFilter());
|
||||||
|
}
|
||||||
if (ret == 0 && target > -1) {
|
if (ret == 0 && target > -1) {
|
||||||
ptr->move_filter(ptr->count() - 1, target);
|
ptr->move_filter(ptr->count() - 1, target);
|
||||||
}
|
}
|
||||||
@@ -190,7 +205,13 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
|
|||||||
void EffectItemModel::unplant(const std::weak_ptr<Mlt::Service> &service)
|
void EffectItemModel::unplant(const std::weak_ptr<Mlt::Service> &service)
|
||||||
{
|
{
|
||||||
if (auto ptr = service.lock()) {
|
if (auto ptr = service.lock()) {
|
||||||
int ret = ptr->detach(filter());
|
int ret = 0;
|
||||||
|
if (isLink()) {
|
||||||
|
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
|
||||||
|
ret = fromChain.detach(getLink());
|
||||||
|
} else {
|
||||||
|
ret = ptr->detach(getFilter());
|
||||||
|
}
|
||||||
Q_ASSERT(ret == 0);
|
Q_ASSERT(ret == 0);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
|
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
|
||||||
@@ -204,7 +225,13 @@ void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (auto ptr = service.lock()) {
|
if (auto ptr = service.lock()) {
|
||||||
int ret = ptr->detach(filter());
|
int ret = 0;
|
||||||
|
if (isLink()) {
|
||||||
|
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
|
||||||
|
ret = fromChain.detach(getLink());
|
||||||
|
} else {
|
||||||
|
ret = ptr->detach(getFilter());
|
||||||
|
}
|
||||||
Q_ASSERT(ret == 0);
|
Q_ASSERT(ret == 0);
|
||||||
if (!ptr->property_exists("_childid")) {
|
if (!ptr->property_exists("_childid")) {
|
||||||
return;
|
return;
|
||||||
@@ -212,7 +239,12 @@ void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
|
|||||||
int childId = ptr->get_int("_childid");
|
int childId = ptr->get_int("_childid");
|
||||||
auto effect = m_childEffects.take(childId);
|
auto effect = m_childEffects.take(childId);
|
||||||
if (effect && effect->isValid()) {
|
if (effect && effect->isValid()) {
|
||||||
ptr->detach(effect->filter());
|
if (effect->isLink()) {
|
||||||
|
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
|
||||||
|
ret = fromChain.detach(effect->getLink());
|
||||||
|
} else {
|
||||||
|
ret = ptr->detach(effect->getFilter());
|
||||||
|
}
|
||||||
effect.reset();
|
effect.reset();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "TRYING TO REMOVE INVALID EFFECT!!!!!!!";
|
qDebug() << "TRYING TO REMOVE INVALID EFFECT!!!!!!!";
|
||||||
@@ -223,11 +255,26 @@ void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mlt::Filter &EffectItemModel::filter() const
|
Mlt::Properties &EffectItemModel::filter() const
|
||||||
|
{
|
||||||
|
return *(m_asset.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Mlt::Filter &EffectItemModel::getFilter() const
|
||||||
{
|
{
|
||||||
return *static_cast<Mlt::Filter *>(m_asset.get());
|
return *static_cast<Mlt::Filter *>(m_asset.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mlt::Link &EffectItemModel::getLink() const
|
||||||
|
{
|
||||||
|
return *static_cast<Mlt::Link *>(m_asset.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EffectItemModel::isLink() const
|
||||||
|
{
|
||||||
|
return m_assetId.startsWith(QLatin1String("avfilter."));
|
||||||
|
}
|
||||||
|
|
||||||
bool EffectItemModel::isValid() const
|
bool EffectItemModel::isValid() const
|
||||||
{
|
{
|
||||||
return m_asset && m_asset->is_valid();
|
return m_asset && m_asset->is_valid();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "abstractmodel/treeitem.hpp"
|
#include "abstractmodel/treeitem.hpp"
|
||||||
#include "assets/model/assetparametermodel.hpp"
|
#include "assets/model/assetparametermodel.hpp"
|
||||||
#include <mlt++/MltFilter.h>
|
#include <mlt++/MltFilter.h>
|
||||||
|
#include <mlt++/MltLink.h>
|
||||||
|
|
||||||
class EffectStackModel;
|
class EffectStackModel;
|
||||||
/** @brief This represents an effect of the effectstack
|
/** @brief This represents an effect of the effectstack
|
||||||
@@ -37,7 +38,10 @@ public:
|
|||||||
void unplant(const std::weak_ptr<Mlt::Service> &service) override;
|
void unplant(const std::weak_ptr<Mlt::Service> &service) override;
|
||||||
void unplantClone(const std::weak_ptr<Mlt::Service> &service) override;
|
void unplantClone(const std::weak_ptr<Mlt::Service> &service) override;
|
||||||
|
|
||||||
Mlt::Filter &filter() const;
|
Mlt::Properties &filter() const;
|
||||||
|
Mlt::Filter &getFilter() const;
|
||||||
|
Mlt::Link &getLink() const;
|
||||||
|
bool isLink() const;
|
||||||
|
|
||||||
void setEffectStackEnabled(bool enabled) override;
|
void setEffectStackEnabled(bool enabled) override;
|
||||||
/** @brief Return true if the effect applies only to audio */
|
/** @brief Return true if the effect applies only to audio */
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ QDomElement EffectStackModel::toXml(QDomDocument &document)
|
|||||||
QStringList passProps{QStringLiteral("disable"), QStringLiteral("kdenlive:collapsed"), QStringLiteral("kdenlive:builtin"),
|
QStringList passProps{QStringLiteral("disable"), QStringLiteral("kdenlive:collapsed"), QStringLiteral("kdenlive:builtin"),
|
||||||
QStringLiteral("kdenlive:hiddenbuiltin"), QStringLiteral("kdenlive:kfrhidden")};
|
QStringLiteral("kdenlive:hiddenbuiltin"), QStringLiteral("kdenlive:kfrhidden")};
|
||||||
for (const QString ¶m : passProps) {
|
for (const QString ¶m : passProps) {
|
||||||
int paramVal = sourceEffect->filter().get_int(param.toUtf8().constData());
|
int paramVal = sourceEffect->getFilter().get_int(param.toUtf8().constData());
|
||||||
if (paramVal > 0) {
|
if (paramVal > 0) {
|
||||||
Xml::setXmlProperty(sub, param, QString::number(paramVal));
|
Xml::setXmlProperty(sub, param, QString::number(paramVal));
|
||||||
}
|
}
|
||||||
@@ -358,7 +358,7 @@ QDomElement EffectStackModel::rowToXml(int row, QDomDocument &document)
|
|||||||
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(row));
|
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(row));
|
||||||
QDomElement sub = document.createElement(QStringLiteral("effect"));
|
QDomElement sub = document.createElement(QStringLiteral("effect"));
|
||||||
sub.setAttribute(QStringLiteral("id"), sourceEffect->getAssetId());
|
sub.setAttribute(QStringLiteral("id"), sourceEffect->getAssetId());
|
||||||
int filterIn = sourceEffect->filter().get_int("in");
|
int filterIn = sourceEffect->getFilter().get_int("in");
|
||||||
int filterOut = sourceEffect->filter().get_int("out");
|
int filterOut = sourceEffect->filter().get_int("out");
|
||||||
if (filterOut > filterIn) {
|
if (filterOut > filterIn) {
|
||||||
sub.setAttribute(QStringLiteral("in"), filterIn);
|
sub.setAttribute(QStringLiteral("in"), filterIn);
|
||||||
@@ -500,7 +500,7 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
|
|||||||
connect(effect.get(), &AssetParameterModel::showEffectZone, this, &EffectStackModel::updateEffectZones);
|
connect(effect.get(), &AssetParameterModel::showEffectZone, this, &EffectStackModel::updateEffectZones);
|
||||||
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||||
m_fadeIns.insert(effect->getId());
|
m_fadeIns.insert(effect->getId());
|
||||||
int duration = effect->filter().get_length() - 1;
|
int duration = effect->getFilter().get_length() - 1;
|
||||||
effect->filter().set("in", currentIn);
|
effect->filter().set("in", currentIn);
|
||||||
effect->filter().set("out", currentIn + duration);
|
effect->filter().set("out", currentIn + duration);
|
||||||
if (effectId.startsWith(QLatin1String("fade_"))) {
|
if (effectId.startsWith(QLatin1String("fade_"))) {
|
||||||
@@ -525,7 +525,7 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
|
|||||||
}
|
}
|
||||||
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
|
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
|
||||||
m_fadeOuts.insert(effect->getId());
|
m_fadeOuts.insert(effect->getId());
|
||||||
int duration = effect->filter().get_length() - 1;
|
int duration = effect->getFilter().get_length() - 1;
|
||||||
int filterOut = pCore->getItemIn(m_ownerId) + pCore->getItemDuration(m_ownerId) - 1;
|
int filterOut = pCore->getItemIn(m_ownerId) + pCore->getItemDuration(m_ownerId) - 1;
|
||||||
effect->filter().set("in", filterOut - duration);
|
effect->filter().set("in", filterOut - duration);
|
||||||
effect->filter().set("out", filterOut);
|
effect->filter().set("out", filterOut);
|
||||||
@@ -647,14 +647,14 @@ bool EffectStackModel::copyEffectWithUndo(const std::shared_ptr<AbstractEffectIt
|
|||||||
QVector<int> roles = {TimelineModel::EffectNamesRole, TimelineModel::EffectCountRole};
|
QVector<int> roles = {TimelineModel::EffectNamesRole, TimelineModel::EffectCountRole};
|
||||||
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||||
m_fadeIns.insert(effect->getId());
|
m_fadeIns.insert(effect->getId());
|
||||||
int duration = effect->filter().get_length() - 1;
|
int duration = effect->getFilter().get_length() - 1;
|
||||||
int in = pCore->getItemIn(m_ownerId);
|
int in = pCore->getItemIn(m_ownerId);
|
||||||
effect->filter().set("in", in);
|
effect->filter().set("in", in);
|
||||||
effect->filter().set("out", in + duration);
|
effect->filter().set("out", in + duration);
|
||||||
roles << TimelineModel::FadeInRole;
|
roles << TimelineModel::FadeInRole;
|
||||||
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
|
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
|
||||||
m_fadeOuts.insert(effect->getId());
|
m_fadeOuts.insert(effect->getId());
|
||||||
int duration = effect->filter().get_length() - 1;
|
int duration = effect->getFilter().get_length() - 1;
|
||||||
int out = pCore->getItemIn(m_ownerId) + pCore->getItemDuration(m_ownerId) - 1;
|
int out = pCore->getItemIn(m_ownerId) + pCore->getItemDuration(m_ownerId) - 1;
|
||||||
effect->filter().set("in", out - duration);
|
effect->filter().set("in", out - duration);
|
||||||
effect->filter().set("out", out);
|
effect->filter().set("out", out);
|
||||||
@@ -760,7 +760,7 @@ std::pair<bool, bool> EffectStackModel::doAppendEffect(const QString &effectId,
|
|||||||
int inFades = 0;
|
int inFades = 0;
|
||||||
int outFades = 0;
|
int outFades = 0;
|
||||||
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||||
int duration = effect->filter().get_length() - 1;
|
int duration = effect->getFilter().get_length() - 1;
|
||||||
int in = pCore->getItemIn(m_ownerId);
|
int in = pCore->getItemIn(m_ownerId);
|
||||||
effect->filter().set("in", in);
|
effect->filter().set("in", in);
|
||||||
effect->filter().set("out", in + duration);
|
effect->filter().set("out", in + duration);
|
||||||
@@ -830,10 +830,10 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
|||||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(leaf);
|
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(leaf);
|
||||||
if (fadeInDuration > 0 && m_fadeIns.count(leaf->getId()) > 0) {
|
if (fadeInDuration > 0 && m_fadeIns.count(leaf->getId()) > 0) {
|
||||||
// Adjust fade in
|
// Adjust fade in
|
||||||
int oldEffectIn = qMax(0, effect->filter().get_in());
|
int oldEffectIn = qMax(0, effect->getFilter().get_in());
|
||||||
int oldEffectOut = effect->filter().get_out();
|
int oldEffectOut = effect->getFilter().get_out();
|
||||||
qDebug() << "--previous effect: " << oldEffectIn << "-" << oldEffectOut;
|
qDebug() << "--previous effect: " << oldEffectIn << "-" << oldEffectOut;
|
||||||
int effectDuration = qMin(effect->filter().get_length() - 1, duration);
|
int effectDuration = qMin(effect->getFilter().get_length() - 1, duration);
|
||||||
if (!adjustFromEnd && (oldIn != newIn || duration != oldDuration)) {
|
if (!adjustFromEnd && (oldIn != newIn || duration != oldDuration)) {
|
||||||
// Clip start was resized, adjust effect in / out
|
// Clip start was resized, adjust effect in / out
|
||||||
Fun operation = [effect, newIn, effectDuration, logUndo]() {
|
Fun operation = [effect, newIn, effectDuration, logUndo]() {
|
||||||
@@ -927,7 +927,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
|||||||
qDebug() << "// NULL Keyframes---------";
|
qDebug() << "// NULL Keyframes---------";
|
||||||
}
|
}
|
||||||
if (m_ownerId.type == KdenliveObjectType::TimelineTrack && !hasZone) {
|
if (m_ownerId.type == KdenliveObjectType::TimelineTrack && !hasZone) {
|
||||||
int oldEffectOut = effect->filter().get_out();
|
int oldEffectOut = effect->getFilter().get_out();
|
||||||
Fun operation = [effect, out, logUndo]() {
|
Fun operation = [effect, out, logUndo]() {
|
||||||
effect->setParameter(QStringLiteral("out"), out, logUndo);
|
effect->setParameter(QStringLiteral("out"), out, logUndo);
|
||||||
return true;
|
return true;
|
||||||
@@ -945,12 +945,12 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
|||||||
PUSH_LAMBDA(reverse, undo);
|
PUSH_LAMBDA(reverse, undo);
|
||||||
}
|
}
|
||||||
} else if (m_ownerId.type == KdenliveObjectType::TimelineClip && effect->data(QModelIndex(), AssetParameterModel::RequiresInOut).toBool() == true) {
|
} else if (m_ownerId.type == KdenliveObjectType::TimelineClip && effect->data(QModelIndex(), AssetParameterModel::RequiresInOut).toBool() == true) {
|
||||||
int oldEffectIn = qMax(0, effect->filter().get_in());
|
int oldEffectIn = qMax(0, effect->getFilter().get_in());
|
||||||
int oldEffectOut = effect->filter().get_out();
|
int oldEffectOut = effect->getFilter().get_out();
|
||||||
int newIn = pCore->getItemIn(m_ownerId);
|
int newIn = pCore->getItemIn(m_ownerId);
|
||||||
int newOut = newIn + pCore->getItemDuration(m_ownerId) - 1;
|
int newOut = newIn + pCore->getItemDuration(m_ownerId) - 1;
|
||||||
Fun operation = [effect, newIn, newOut]() {
|
Fun operation = [effect, newIn, newOut]() {
|
||||||
effect->filter().set_in_and_out(newIn, newOut);
|
effect->getFilter().set_in_and_out(newIn, newOut);
|
||||||
qDebug() << "--new effect: " << newIn << "-" << newOut;
|
qDebug() << "--new effect: " << newIn << "-" << newOut;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -959,7 +959,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Fun reverse = [effect, oldEffectIn, oldEffectOut]() {
|
Fun reverse = [effect, oldEffectIn, oldEffectOut]() {
|
||||||
effect->filter().set_in_and_out(oldEffectIn, oldEffectOut);
|
effect->getFilter().set_in_and_out(oldEffectIn, oldEffectOut);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
PUSH_LAMBDA(operation, redo);
|
PUSH_LAMBDA(operation, redo);
|
||||||
@@ -994,7 +994,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
|
|||||||
if (m_fadeIns.count(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) > 0) {
|
if (m_fadeIns.count(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) > 0) {
|
||||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||||
if (oldDuration == -1) {
|
if (oldDuration == -1) {
|
||||||
oldDuration = effect->filter().get_length();
|
oldDuration = effect->getFilter().get_length();
|
||||||
}
|
}
|
||||||
effect->filter().set("in", in);
|
effect->filter().set("in", in);
|
||||||
duration = qMin(pCore->getItemDuration(m_ownerId), duration);
|
duration = qMin(pCore->getItemDuration(m_ownerId), duration);
|
||||||
@@ -1058,7 +1058,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
|
|||||||
if (m_fadeOuts.count(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) > 0) {
|
if (m_fadeOuts.count(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) > 0) {
|
||||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||||
if (oldDuration == -1) {
|
if (oldDuration == -1) {
|
||||||
oldDuration = effect->filter().get_length();
|
oldDuration = effect->getFilter().get_length();
|
||||||
}
|
}
|
||||||
effect->filter().set("out", out);
|
effect->filter().set("out", out);
|
||||||
duration = qMin(itemDuration, duration);
|
duration = qMin(itemDuration, duration);
|
||||||
@@ -1191,7 +1191,7 @@ int EffectStackModel::getFadePosition(bool fromStart)
|
|||||||
for (int i = 0; i < rootItem->childCount(); ++i) {
|
for (int i = 0; i < rootItem->childCount(); ++i) {
|
||||||
if (*(m_fadeIns.begin()) == std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) {
|
if (*(m_fadeIns.begin()) == std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) {
|
||||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||||
return effect->filter().get_length() - 1;
|
return effect->getFilter().get_length() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1201,7 +1201,7 @@ int EffectStackModel::getFadePosition(bool fromStart)
|
|||||||
for (int i = 0; i < rootItem->childCount(); ++i) {
|
for (int i = 0; i < rootItem->childCount(); ++i) {
|
||||||
if (*(m_fadeOuts.begin()) == std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) {
|
if (*(m_fadeOuts.begin()) == std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId()) {
|
||||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||||
return effect->filter().get_length() - 1;
|
return effect->getFilter().get_length() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1303,7 +1303,7 @@ void EffectStackModel::registerItem(const std::shared_ptr<TreeItem> &item)
|
|||||||
if (effectItem->data(QModelIndex(), AssetParameterModel::RequiresInOut).toBool() == true) {
|
if (effectItem->data(QModelIndex(), AssetParameterModel::RequiresInOut).toBool() == true) {
|
||||||
int in = pCore->getItemIn(m_ownerId);
|
int in = pCore->getItemIn(m_ownerId);
|
||||||
int out = in + pCore->getItemDuration(m_ownerId) - 1;
|
int out = in + pCore->getItemDuration(m_ownerId) - 1;
|
||||||
effectItem->filter().set_in_and_out(in, out);
|
effectItem->getFilter().set_in_and_out(in, out);
|
||||||
}
|
}
|
||||||
if (!m_loadingExisting) {
|
if (!m_loadingExisting) {
|
||||||
effectItem->plant(m_masterService);
|
effectItem->plant(m_masterService);
|
||||||
@@ -1468,6 +1468,77 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
|||||||
int imported = 0;
|
int imported = 0;
|
||||||
int builtin = 0;
|
int builtin = 0;
|
||||||
if (auto ptr = service.lock()) {
|
if (auto ptr = service.lock()) {
|
||||||
|
// Import links if this is a chain
|
||||||
|
std::shared_ptr<Mlt::Chain> chain = nullptr;
|
||||||
|
if (ptr->type() == mlt_service_chain_type) {
|
||||||
|
Mlt::Producer prod(*ptr.get());
|
||||||
|
chain.reset(new Mlt::Chain(prod));
|
||||||
|
} else if (ptr->type() == mlt_service_producer_type) {
|
||||||
|
Mlt::Producer prod = static_cast<Mlt::Producer *>(ptr.get())->parent();
|
||||||
|
if (prod.type() == mlt_service_chain_type) {
|
||||||
|
chain.reset(new Mlt::Chain(prod));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chain) {
|
||||||
|
int maxLink = chain->link_count();
|
||||||
|
for (int i = 0; i < maxLink; i++) {
|
||||||
|
std::unique_ptr<Mlt::Link> filter(chain->link(i));
|
||||||
|
if (!filter->property_exists("kdenlive_id")) {
|
||||||
|
// don't consider internal MLT stuff
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
effectEnabled = filter->get_int("disable") == 0;
|
||||||
|
bool forcedInOut = filter->get_int("kdenlive:force_in_out") == 1 && filter->get_int("out") > 0;
|
||||||
|
if (disabledStack && filter->get_int("kdenlive:bin-disabled") == 0) {
|
||||||
|
disabledStack = false;
|
||||||
|
}
|
||||||
|
const QString effectId = qstrdup(filter->get("kdenlive_id"));
|
||||||
|
if (m_ownerId.type == KdenliveObjectType::TimelineClip && EffectsRepository::get()->isUnique(effectId) && hasFilter(effectId)) {
|
||||||
|
pCore->displayMessage(i18n("Effect %1 cannot be added twice.", EffectsRepository::get()->getName(effectId)), ErrorMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// The MLT filter already exists, use it directly to create the effect
|
||||||
|
int filterIn = filter->get_in();
|
||||||
|
int filterOut = filter->get_out();
|
||||||
|
std::shared_ptr<EffectItemModel> effect;
|
||||||
|
if (alreadyExist) {
|
||||||
|
// effect is already plugged in the service
|
||||||
|
effect = EffectItemModel::construct(std::move(filter), shared_from_this(), originalDecimalPoint);
|
||||||
|
} else {
|
||||||
|
// duplicate effect
|
||||||
|
std::unique_ptr<Mlt::Properties> asset = EffectsRepository::get()->getEffect(effectId);
|
||||||
|
asset->inherit(*(filter));
|
||||||
|
effect = EffectItemModel::construct(std::move(asset), shared_from_this(), originalDecimalPoint);
|
||||||
|
}
|
||||||
|
if (state == PlaylistState::VideoOnly) {
|
||||||
|
if (effect->isAudio()) {
|
||||||
|
// Don't import effect
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (state == PlaylistState::AudioOnly) {
|
||||||
|
if (!effect->isAudio()) {
|
||||||
|
// Don't import effect
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imported++;
|
||||||
|
connect(effect.get(), &AssetParameterModel::modelChanged, this, &EffectStackModel::modelChanged);
|
||||||
|
connect(effect.get(), &AssetParameterModel::replugEffect, this, &EffectStackModel::replugEffect, Qt::DirectConnection);
|
||||||
|
connect(effect.get(), &AssetParameterModel::showEffectZone, this, &EffectStackModel::updateEffectZones);
|
||||||
|
Fun redo = addItem_lambda(effect, rootItem->getId());
|
||||||
|
int clipIn = ptr->get_int("in");
|
||||||
|
int clipOut = ptr->get_int("out");
|
||||||
|
if (clipOut <= clipIn) {
|
||||||
|
clipOut = ptr->get_int("length") - 1;
|
||||||
|
}
|
||||||
|
effect->prepareKeyframes(clipIn, clipOut);
|
||||||
|
if (redo()) {
|
||||||
|
if (forcedInOut) {
|
||||||
|
effect->getFilter().set_in_and_out(filterIn, filterOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
int max = ptr->filter_count();
|
int max = ptr->filter_count();
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
std::unique_ptr<Mlt::Filter> filter(ptr->filter(i));
|
std::unique_ptr<Mlt::Filter> filter(ptr->filter(i));
|
||||||
@@ -1519,7 +1590,7 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
|||||||
effect = EffectItemModel::construct(std::move(filter), shared_from_this(), originalDecimalPoint);
|
effect = EffectItemModel::construct(std::move(filter), shared_from_this(), originalDecimalPoint);
|
||||||
} else {
|
} else {
|
||||||
// duplicate effect
|
// duplicate effect
|
||||||
std::unique_ptr<Mlt::Filter> asset = EffectsRepository::get()->getEffect(effectId);
|
std::unique_ptr<Mlt::Properties> asset = EffectsRepository::get()->getEffect(effectId);
|
||||||
asset->inherit(*(filter));
|
asset->inherit(*(filter));
|
||||||
effect = EffectItemModel::construct(std::move(asset), shared_from_this(), originalDecimalPoint);
|
effect = EffectItemModel::construct(std::move(asset), shared_from_this(), originalDecimalPoint);
|
||||||
}
|
}
|
||||||
@@ -1547,12 +1618,12 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
|||||||
effect->prepareKeyframes(clipIn, clipOut);
|
effect->prepareKeyframes(clipIn, clipOut);
|
||||||
if (redo()) {
|
if (redo()) {
|
||||||
if (forcedInOut) {
|
if (forcedInOut) {
|
||||||
effect->filter().set_in_and_out(filterIn, filterOut);
|
effect->getFilter().set_in_and_out(filterIn, filterOut);
|
||||||
} else if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
} else if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||||
m_fadeIns.insert(effect->getId());
|
m_fadeIns.insert(effect->getId());
|
||||||
if (effect->filter().get_int("in") != clipIn) {
|
if (effect->filter().get_int("in") != clipIn) {
|
||||||
// Broken fade, fix
|
// Broken fade, fix
|
||||||
int filterLength = effect->filter().get_length() - 1;
|
int filterLength = effect->getFilter().get_length() - 1;
|
||||||
effect->filter().set("in", clipIn);
|
effect->filter().set("in", clipIn);
|
||||||
effect->filter().set("out", clipIn + filterLength);
|
effect->filter().set("out", clipIn + filterLength);
|
||||||
}
|
}
|
||||||
@@ -1560,7 +1631,7 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
|||||||
m_fadeOuts.insert(effect->getId());
|
m_fadeOuts.insert(effect->getId());
|
||||||
if (effect->filter().get_int("out") != clipOut) {
|
if (effect->filter().get_int("out") != clipOut) {
|
||||||
// Broken fade, fix
|
// Broken fade, fix
|
||||||
int filterLength = effect->filter().get_length() - 1;
|
int filterLength = effect->getFilter().get_length() - 1;
|
||||||
effect->filter().set("in", clipOut - filterLength);
|
effect->filter().set("in", clipOut - filterLength);
|
||||||
effect->filter().set("out", clipOut);
|
effect->filter().set("out", clipOut);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ ClipStabilize::ClipStabilize(const std::vector<QString> &binIds, QString filterN
|
|||||||
if (m_filtername == QLatin1String("vidstab")) {
|
if (m_filtername == QLatin1String("vidstab")) {
|
||||||
m_view = std::make_unique<AssetParameterView>(this);
|
m_view = std::make_unique<AssetParameterView>(this);
|
||||||
qDebug() << "// Fetching effect: " << m_filtername;
|
qDebug() << "// Fetching effect: " << m_filtername;
|
||||||
std::unique_ptr<Mlt::Filter> asset = EffectsRepository::get()->getEffect(m_filtername);
|
std::unique_ptr<Mlt::Properties> asset = EffectsRepository::get()->getEffect(m_filtername);
|
||||||
auto prop = std::make_unique<Mlt::Properties>(asset->get_properties());
|
auto prop = std::make_unique<Mlt::Properties>(asset->get_properties());
|
||||||
QDomElement xml = EffectsRepository::get()->getXml(m_filtername);
|
QDomElement xml = EffectsRepository::get()->getXml(m_filtername);
|
||||||
m_assetModel.reset(new AssetParameterModel(std::move(prop), xml, m_filtername, ObjectId()));
|
m_assetModel.reset(new AssetParameterModel(std::move(prop), xml, m_filtername, ObjectId()));
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ int ClipModel::construct(const std::shared_ptr<TimelineModel> &parent, const QSt
|
|||||||
videoAudio.first = videoAudio.first && binClip->hasVideo();
|
videoAudio.first = videoAudio.first && binClip->hasVideo();
|
||||||
videoAudio.second = videoAudio.second && binClip->hasAudio();
|
videoAudio.second = videoAudio.second && binClip->hasAudio();
|
||||||
state = stateFromBool(videoAudio);
|
state = stateFromBool(videoAudio);
|
||||||
qDebug() << "// GET TIMELINE PROD FOR STREAM: " << audioStream;
|
qDebug() << "// GET TIMELINE PROD FOR STREAM: " << audioStream << ", CID: " << id;
|
||||||
std::shared_ptr<Mlt::Producer> cutProducer = binClip->getTimelineProducer(-1, id, state, audioStream, speed);
|
std::shared_ptr<Mlt::Producer> cutProducer = binClip->getTimelineProducer(-1, id, state, audioStream, speed);
|
||||||
std::shared_ptr<ClipModel> clip(new ClipModel(parent, cutProducer, binClipId, id, state, speed));
|
std::shared_ptr<ClipModel> clip(new ClipModel(parent, cutProducer, binClipId, id, state, speed));
|
||||||
if (!qFuzzyCompare(speed, 1.)) {
|
if (!qFuzzyCompare(speed, 1.)) {
|
||||||
@@ -854,6 +854,7 @@ void ClipModel::refreshProducerFromBin(int trackId, PlaylistState::ClipState sta
|
|||||||
{
|
{
|
||||||
// We require that the producer is not in the track when we refresh the producer, because otherwise the modification will not be propagated. Remove the clip
|
// We require that the producer is not in the track when we refresh the producer, because otherwise the modification will not be propagated. Remove the clip
|
||||||
// first, refresh, and then replant.
|
// first, refresh, and then replant.
|
||||||
|
// TODO Link: links seem to still be available when trying to refresh producer
|
||||||
QWriteLocker locker(&m_lock);
|
QWriteLocker locker(&m_lock);
|
||||||
int in = getIn();
|
int in = getIn();
|
||||||
int out = getOut();
|
int out = getOut();
|
||||||
@@ -1243,7 +1244,8 @@ void ClipModel::setCurrentTrackId(int tid, bool finalMove)
|
|||||||
|
|
||||||
if (finalMove && m_lastTrackId != m_currentTrackId) {
|
if (finalMove && m_lastTrackId != m_currentTrackId) {
|
||||||
if (tid != -1) {
|
if (tid != -1) {
|
||||||
refreshProducerFromBin(m_currentTrackId);
|
// TODO Link: check if this doesn't break anything
|
||||||
|
// refreshProducerFromBin(m_currentTrackId);
|
||||||
}
|
}
|
||||||
m_lastTrackId = m_currentTrackId;
|
m_lastTrackId = m_currentTrackId;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user