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) {
|
||||
// we are requesting a normal speed producer
|
||||
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;
|
||||
}
|
||||
}*/
|
||||
int maxDuration = 0;
|
||||
if (m_clipType == ClipType::Timeline && m_masterProducer->parent().property_exists("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;
|
||||
}
|
||||
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"));
|
||||
return std::shared_ptr<Mlt::Producer>(m_usedProducers[clipId]->cut(-1, duration > 0 ? duration - 1 : -1));
|
||||
m_effectStack->removeService(m_usedProducers[clipId]);
|
||||
@@ -965,22 +966,22 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
||||
if (secondPlaylist) {
|
||||
trackId = -trackId;
|
||||
}
|
||||
std::shared_ptr<Mlt::Producer> master;
|
||||
if (m_clipType == ClipType::Timeline) {
|
||||
std::shared_ptr<Mlt::Producer> prod(m_masterProducer->cut(0, maxDuration));
|
||||
m_usedProducers[clipId] = prod;
|
||||
master.reset(m_masterProducer->cut(0, maxDuration));
|
||||
} else {
|
||||
m_usedProducers[clipId] = cloneProducer(true, true);
|
||||
master = cloneProducer(true, true);
|
||||
}
|
||||
m_usedProducers[clipId]->set("set.test_audio", 0);
|
||||
m_usedProducers[clipId]->set("set.test_image", 1);
|
||||
master->set("set.test_audio", 0);
|
||||
master->set("set.test_image", 1);
|
||||
if (m_streamEffects.contains(audioStream)) {
|
||||
QStringList effects = m_streamEffects.value(audioStream);
|
||||
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()) {
|
||||
// Add stream effect markup
|
||||
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 the audioStreamIndex is not found, for example when replacing a clip with another one using different indexes,
|
||||
default to first audio stream */
|
||||
m_usedProducers[clipId]->set("audio_index", audioStream);
|
||||
master->set("audio_index", audioStream);
|
||||
} else {
|
||||
newAudioStreamIndex = 0;
|
||||
}
|
||||
if (newAudioStreamIndex > audioStreamsCount() - 1) {
|
||||
newAudioStreamIndex = 0;
|
||||
}
|
||||
m_usedProducers[clipId]->set("astream", newAudioStreamIndex);
|
||||
master->set("astream", newAudioStreamIndex);
|
||||
}
|
||||
m_effectStack->addService(m_usedProducers[clipId]);
|
||||
std::shared_ptr<Mlt::Producer> prod(m_usedProducers.at(clipId)->cut());
|
||||
if (m_clipType == ClipType::Timeline && m_usedProducers.at(clipId)->parent().property_exists("kdenlive:maxduration")) {
|
||||
int max = m_usedProducers.at(clipId)->parent().get_int("kdenlive:maxduration");
|
||||
m_effectStack->addService(master);
|
||||
m_usedProducers[clipId] = master;
|
||||
std::shared_ptr<Mlt::Producer> prod(master->cut());
|
||||
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("length", max);
|
||||
}
|
||||
@@ -1011,25 +1013,28 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
|
||||
// we return the video producer
|
||||
// We need to get an video producer, if none exists
|
||||
// second playlist producers use negative trackId
|
||||
qDebug() << ":::: REQUESTING NEW VIDEO PRODUICER FOR: " << clipId;
|
||||
if (secondPlaylist) {
|
||||
trackId = -trackId;
|
||||
}
|
||||
std::shared_ptr<Mlt::Producer> prod;
|
||||
if (m_clipType == ClipType::Timeline) {
|
||||
std::shared_ptr<Mlt::Producer> prod(m_masterProducer->cut(0, maxDuration));
|
||||
m_usedProducers[clipId] = prod;
|
||||
prod.reset(m_masterProducer->cut(0, maxDuration));
|
||||
|
||||
} else {
|
||||
m_usedProducers[clipId] = cloneProducer(true, true);
|
||||
prod = cloneProducer(true, true);
|
||||
}
|
||||
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 ?
|
||||
m_usedProducers[clipId]->set("set.test_audio", 1);
|
||||
m_usedProducers[clipId]->set("set.test_image", 0);
|
||||
m_effectStack->addService(m_usedProducers.at(clipId));
|
||||
prod->set("set.test_audio", 1);
|
||||
prod->set("set.test_image", 0);
|
||||
m_effectStack->addService(prod);
|
||||
m_usedProducers[clipId] = prod;
|
||||
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);
|
||||
createDisabledMasterProducer();
|
||||
@@ -1352,6 +1357,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
||||
Q_UNUSED(timelineProducer);
|
||||
QMutexLocker lk(&m_producerMutex);
|
||||
QReadLocker lock(&pCore->xmlMutex);
|
||||
|
||||
Mlt::Consumer c(pCore->getProjectProfile(), "xml", "string");
|
||||
Mlt::Service s(m_masterProducer->get_service());
|
||||
m_masterProducer->lock();
|
||||
@@ -1361,10 +1367,10 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
||||
}
|
||||
c.connect(s);
|
||||
c.set("time_format", "frames");
|
||||
c.set("no_meta", 1);
|
||||
// c.set("no_meta", 1);
|
||||
c.set("no_root", 1);
|
||||
c.set("no_profile", 1);
|
||||
c.set("root", "/");
|
||||
c.set("root", "");
|
||||
c.set("store", "kdenlive");
|
||||
c.run();
|
||||
if (ignore) {
|
||||
@@ -1426,6 +1432,26 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(bool removeEffects, bo
|
||||
delete filter;
|
||||
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);
|
||||
return prod;
|
||||
|
||||
@@ -216,11 +216,6 @@ public:
|
||||
/** @brief Returns a list of all timeline clip ids for this bin clip */
|
||||
QList<int> timelineInstances(QUuid activeUuid = QUuid()) 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
|
||||
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 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
|
||||
* @param producer Producer containing the effects
|
||||
|
||||
@@ -237,11 +237,14 @@ bool EffectsRepository::isPreferred(const QString &effectId) const
|
||||
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));
|
||||
QString service_name = m_assets.at(effectId).mltId;
|
||||
// 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);
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
static std::unique_ptr<EffectsRepository> &get();
|
||||
|
||||
/** @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) */
|
||||
bool hasInternalEffect(const QString &effectId) const;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
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 in = m_asset->get_int("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");
|
||||
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 in = m_asset->get_int("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");
|
||||
if (childId == 0) {
|
||||
@@ -172,10 +181,16 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
|
||||
ptr->set("_childid", childId);
|
||||
}
|
||||
if (out > in) {
|
||||
effect->filter().set_in_and_out(in, out);
|
||||
effect->getFilter().set_in_and_out(in, out);
|
||||
}
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (!ptr->property_exists("_childid")) {
|
||||
return;
|
||||
@@ -212,7 +239,12 @@ void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
|
||||
int childId = ptr->get_int("_childid");
|
||||
auto effect = m_childEffects.take(childId);
|
||||
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();
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return m_asset && m_asset->is_valid();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "abstractmodel/treeitem.hpp"
|
||||
#include "assets/model/assetparametermodel.hpp"
|
||||
#include <mlt++/MltFilter.h>
|
||||
#include <mlt++/MltLink.h>
|
||||
|
||||
class EffectStackModel;
|
||||
/** @brief This represents an effect of the effectstack
|
||||
@@ -37,7 +38,10 @@ public:
|
||||
void unplant(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;
|
||||
/** @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"),
|
||||
QStringLiteral("kdenlive:hiddenbuiltin"), QStringLiteral("kdenlive:kfrhidden")};
|
||||
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) {
|
||||
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));
|
||||
QDomElement sub = document.createElement(QStringLiteral("effect"));
|
||||
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");
|
||||
if (filterOut > 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);
|
||||
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||
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("out", currentIn + duration);
|
||||
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_"))) {
|
||||
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;
|
||||
effect->filter().set("in", filterOut - duration);
|
||||
effect->filter().set("out", filterOut);
|
||||
@@ -647,14 +647,14 @@ bool EffectStackModel::copyEffectWithUndo(const std::shared_ptr<AbstractEffectIt
|
||||
QVector<int> roles = {TimelineModel::EffectNamesRole, TimelineModel::EffectCountRole};
|
||||
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
|
||||
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);
|
||||
effect->filter().set("in", in);
|
||||
effect->filter().set("out", in + duration);
|
||||
roles << TimelineModel::FadeInRole;
|
||||
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
|
||||
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;
|
||||
effect->filter().set("in", out - duration);
|
||||
effect->filter().set("out", out);
|
||||
@@ -760,7 +760,7 @@ std::pair<bool, bool> EffectStackModel::doAppendEffect(const QString &effectId,
|
||||
int inFades = 0;
|
||||
int outFades = 0;
|
||||
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);
|
||||
effect->filter().set("in", in);
|
||||
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);
|
||||
if (fadeInDuration > 0 && m_fadeIns.count(leaf->getId()) > 0) {
|
||||
// Adjust fade in
|
||||
int oldEffectIn = qMax(0, effect->filter().get_in());
|
||||
int oldEffectOut = effect->filter().get_out();
|
||||
int oldEffectIn = qMax(0, effect->getFilter().get_in());
|
||||
int oldEffectOut = effect->getFilter().get_out();
|
||||
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)) {
|
||||
// Clip start was resized, adjust effect in / out
|
||||
Fun operation = [effect, newIn, effectDuration, logUndo]() {
|
||||
@@ -927,7 +927,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
||||
qDebug() << "// NULL Keyframes---------";
|
||||
}
|
||||
if (m_ownerId.type == KdenliveObjectType::TimelineTrack && !hasZone) {
|
||||
int oldEffectOut = effect->filter().get_out();
|
||||
int oldEffectOut = effect->getFilter().get_out();
|
||||
Fun operation = [effect, out, logUndo]() {
|
||||
effect->setParameter(QStringLiteral("out"), out, logUndo);
|
||||
return true;
|
||||
@@ -945,12 +945,12 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
||||
PUSH_LAMBDA(reverse, undo);
|
||||
}
|
||||
} else if (m_ownerId.type == KdenliveObjectType::TimelineClip && effect->data(QModelIndex(), AssetParameterModel::RequiresInOut).toBool() == true) {
|
||||
int oldEffectIn = qMax(0, effect->filter().get_in());
|
||||
int oldEffectOut = effect->filter().get_out();
|
||||
int oldEffectIn = qMax(0, effect->getFilter().get_in());
|
||||
int oldEffectOut = effect->getFilter().get_out();
|
||||
int newIn = pCore->getItemIn(m_ownerId);
|
||||
int newOut = newIn + pCore->getItemDuration(m_ownerId) - 1;
|
||||
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;
|
||||
return true;
|
||||
};
|
||||
@@ -959,7 +959,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
|
||||
return false;
|
||||
}
|
||||
Fun reverse = [effect, oldEffectIn, oldEffectOut]() {
|
||||
effect->filter().set_in_and_out(oldEffectIn, oldEffectOut);
|
||||
effect->getFilter().set_in_and_out(oldEffectIn, oldEffectOut);
|
||||
return true;
|
||||
};
|
||||
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) {
|
||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||
if (oldDuration == -1) {
|
||||
oldDuration = effect->filter().get_length();
|
||||
oldDuration = effect->getFilter().get_length();
|
||||
}
|
||||
effect->filter().set("in", in);
|
||||
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) {
|
||||
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
|
||||
if (oldDuration == -1) {
|
||||
oldDuration = effect->filter().get_length();
|
||||
oldDuration = effect->getFilter().get_length();
|
||||
}
|
||||
effect->filter().set("out", out);
|
||||
duration = qMin(itemDuration, duration);
|
||||
@@ -1191,7 +1191,7 @@ int EffectStackModel::getFadePosition(bool fromStart)
|
||||
for (int i = 0; i < rootItem->childCount(); ++i) {
|
||||
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));
|
||||
return effect->filter().get_length() - 1;
|
||||
return effect->getFilter().get_length() - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1201,7 +1201,7 @@ int EffectStackModel::getFadePosition(bool fromStart)
|
||||
for (int i = 0; i < rootItem->childCount(); ++i) {
|
||||
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));
|
||||
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) {
|
||||
int in = pCore->getItemIn(m_ownerId);
|
||||
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) {
|
||||
effectItem->plant(m_masterService);
|
||||
@@ -1468,6 +1468,77 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
||||
int imported = 0;
|
||||
int builtin = 0;
|
||||
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();
|
||||
for (int i = 0; i < max; 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);
|
||||
} else {
|
||||
// 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));
|
||||
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);
|
||||
if (redo()) {
|
||||
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_"))) {
|
||||
m_fadeIns.insert(effect->getId());
|
||||
if (effect->filter().get_int("in") != clipIn) {
|
||||
// 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("out", clipIn + filterLength);
|
||||
}
|
||||
@@ -1560,7 +1631,7 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
|
||||
m_fadeOuts.insert(effect->getId());
|
||||
if (effect->filter().get_int("out") != clipOut) {
|
||||
// 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("out", clipOut);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ ClipStabilize::ClipStabilize(const std::vector<QString> &binIds, QString filterN
|
||||
if (m_filtername == QLatin1String("vidstab")) {
|
||||
m_view = std::make_unique<AssetParameterView>(this);
|
||||
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());
|
||||
QDomElement xml = EffectsRepository::get()->getXml(m_filtername);
|
||||
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.second = videoAudio.second && binClip->hasAudio();
|
||||
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<ClipModel> clip(new ClipModel(parent, cutProducer, binClipId, id, state, speed));
|
||||
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
|
||||
// first, refresh, and then replant.
|
||||
// TODO Link: links seem to still be available when trying to refresh producer
|
||||
QWriteLocker locker(&m_lock);
|
||||
int in = getIn();
|
||||
int out = getOut();
|
||||
@@ -1243,7 +1244,8 @@ void ClipModel::setCurrentTrackId(int tid, bool finalMove)
|
||||
|
||||
if (finalMove && m_lastTrackId != m_currentTrackId) {
|
||||
if (tid != -1) {
|
||||
refreshProducerFromBin(m_currentTrackId);
|
||||
// TODO Link: check if this doesn't break anything
|
||||
// refreshProducerFromBin(m_currentTrackId);
|
||||
}
|
||||
m_lastTrackId = m_currentTrackId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user