Compare commits

...

1 Commits

Author SHA1 Message Date
Jean-Baptiste Mardelle
54742999ae Preliminary support for Link filters (mostly for the WIP MLT Freeze Link). 2025-02-07 16:23:41 +01:00
11 changed files with 226 additions and 141 deletions

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE kpartgui>
<effect tag="freeze" id="freeze">
<effect tag="freeze" id="freeze" mlt_type="link">
<name context="Freeze Effect Name">Freeze</name>
<description>Freeze video on a chosen frame</description>
<author>Jean-Baptiste Mardelle</author>

View File

@@ -53,6 +53,7 @@ protected:
{
QString id; // identifier of the asset
QString mltId; //"tag" of the asset, that is the name of the mlt service
bool isLink{false}; // If this effect is a mlt link instead of a mlt filter
QString name, description, author, version_str;
int version{};
bool included{false};

View File

@@ -1643,7 +1643,7 @@ void AssetParameterModel::setProgress(int progress)
Q_EMIT dataChanged(index(0, 0), index(m_rows.count() - 1, 0), {AssetParameterModel::FilterProgressRole});
}
Mlt::Properties *AssetParameterModel::getAsset()
Mlt::Properties *AssetParameterModel::getAsset() const
{
return m_asset.get();
}

View File

@@ -198,7 +198,7 @@ public:
/** @brief Returns the current value of an effect parameter */
const QString getParam(const QString &paramName);
/** @brief Returns the current asset */
Mlt::Properties *getAsset();
Mlt::Properties *getAsset() const;
/** @brief Returns a frame time as click time (00:00:00.000) */
const QString framesToTime(int t) const;
/** @brief Given an animation keyframe string, find out the keyframe type */

View File

@@ -142,6 +142,8 @@ enum AssetType {
Preferred,
Video,
Audio,
VideoLink,
AudioLink,
Custom,
CustomAudio,
Template,

View File

@@ -108,6 +108,11 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
result.type = AssetListType::AssetType::Custom;
}
}
QString mlt_type = base.attribute(QStringLiteral("mlt_type"), QString());
if (mlt_type == QLatin1String("link")) {
result.isLink = true;
}
result.id = base.attribute(QStringLiteral("id"), QString());
if (result.id.isEmpty()) {
result.id = QFileInfo(file_name).baseName();
@@ -156,7 +161,7 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
// Parse type information.
// Video effect by default
result.type = AssetListType::AssetType::Video;
QString type = currentEffect.attribute(QStringLiteral("type"), QString());
const QString type = currentEffect.attribute(QStringLiteral("type"), QString());
if (type == QLatin1String("audio")) {
result.type = AssetListType::AssetType::Audio;
} else if (type == QLatin1String("customVideo")) {
@@ -186,6 +191,10 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
if (m_includedList.contains(result.mltId)) {
result.included = true;
}
const QString mlt_type = currentEffect.attribute(QStringLiteral("mlt_type"), QString());
if (mlt_type == QLatin1String("link")) {
result.isLink = true;
}
customAssets[result.id] = result;
}
}
@@ -237,11 +246,16 @@ 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::Service> 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
qDebug() << "::: QUERYING EFFECT: " << effectId << " IS A LINK: " << m_assets.at(effectId).isLink;
if (m_assets.at(effectId).isLink) {
auto link = std::make_unique<Mlt::Link>(service_name.toLatin1().constData(), nullptr);
return link;
}
auto filter = std::make_unique<Mlt::Filter>(pCore->getProjectProfile(), service_name.toLatin1().constData(), nullptr);
return filter;
}

View File

@@ -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::Service> 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);

View File

@@ -10,7 +10,7 @@
#include "effectstackmodel.hpp"
#include <utility>
EffectItemModel::EffectItemModel(const QList<QVariant> &effectData, std::unique_ptr<Mlt::Properties> effect, const QDomElement &xml, const QString &effectId,
EffectItemModel::EffectItemModel(const QList<QVariant> &effectData, std::unique_ptr<Mlt::Service> effect, const QDomElement &xml, const QString &effectId,
const std::shared_ptr<AbstractTreeModel> &stack, bool isEnabled, QString originalDecimalPoint)
: AbstractEffectItem(EffectItemType::Effect, effectData, stack, false, isEnabled)
, AssetParameterModel(std::move(effect), xml, effectId, std::static_pointer_cast<EffectStackModel>(stack)->getOwnerId(), originalDecimalPoint)
@@ -30,7 +30,7 @@ EffectItemModel::EffectItemModel(const QList<QVariant> &effectData, std::unique_
while (i.hasNext()) {
i.next();
for (const QString &name : names) {
i.value()->filter().set(name.toUtf8().constData(), m_asset->get(name.toUtf8().constData()));
i.value()->getAsset()->set(name.toUtf8().constData(), m_asset->get(name.toUtf8().constData()));
}
}
});
@@ -42,19 +42,21 @@ std::shared_ptr<EffectItemModel> EffectItemModel::construct(const QString &effec
Q_ASSERT(EffectsRepository::get()->exists(effectId));
QDomElement xml = EffectsRepository::get()->getXml(effectId);
std::unique_ptr<Mlt::Properties> effect = EffectsRepository::get()->getEffect(effectId);
std::unique_ptr<Mlt::Service> effect = EffectsRepository::get()->getEffect(effectId);
effect->set("kdenlive_id", effectId.toUtf8().constData());
QList<QVariant> data;
data << EffectsRepository::get()->getName(effectId) << effectId;
bool isLink = effect->type() == mlt_service_link_type;
std::shared_ptr<EffectItemModel> self(new EffectItemModel(data, std::move(effect), xml, effectId, stack, effectEnabled));
self->m_isLink = isLink;
baseFinishConstruct(self);
return self;
}
std::shared_ptr<EffectItemModel> EffectItemModel::construct(std::unique_ptr<Mlt::Properties> effect, std::shared_ptr<AbstractTreeModel> stack,
std::shared_ptr<EffectItemModel> EffectItemModel::construct(std::unique_ptr<Mlt::Service> effect, std::shared_ptr<AbstractTreeModel> stack,
const QString &originalDecimalPoint)
{
QString effectId = effect->get("kdenlive_id");
@@ -97,7 +99,13 @@ 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;
if (m_isLink) {
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
ret = fromChain.attach(link());
} else {
ret = ptr->attach(filter());
}
Q_ASSERT(ret == 0);
} else {
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
@@ -115,8 +123,8 @@ void EffectItemModel::loadClone(const std::weak_ptr<Mlt::Service> &service)
if (effName == m_assetId && filt->get_int("_kdenlive_processed") == 0) {
if (auto ptr2 = m_model.lock()) {
effect = EffectItemModel::construct(std::move(filt), ptr2, QString());
if (filter().get_int("disable") == 1) {
effect->filter().set("disable", 1);
if (getAsset()->get_int("disable") == 1) {
effect->getAsset()->set("disable", 1);
}
int childId = ptr->get_int("_childid");
if (childId == 0) {
@@ -155,7 +163,7 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
effect->setParameters(getAllParameters(), false);
// ensure duplicated assets gets disabled if the original is
if (disable || m_asset->get_int("disable") == 1) {
effect->filter().set("disable", 1);
effect->getAsset()->set("disable", 1);
}
int childId = ptr->get_int("_childid");
if (childId == 0) {
@@ -163,7 +171,13 @@ void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service, int
ptr->set("_childid", childId);
}
m_childEffects.insert(childId, effect);
int ret = ptr->attach(effect->filter());
int ret;
if (m_isLink) {
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
ret = fromChain.attach(effect->link());
} else {
ret = ptr->attach(effect->filter());
}
if (ret == 0 && target > -1) {
ptr->move_filter(ptr->count() - 1, target);
}
@@ -178,7 +192,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 (m_isLink) {
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
ret = fromChain.detach(link());
} else {
ret = ptr->detach(filter());
}
Q_ASSERT(ret == 0);
} else {
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
@@ -192,7 +212,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 (m_isLink) {
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
ret = fromChain.detach(link());
} else {
ret = ptr->detach(filter());
}
Q_ASSERT(ret == 0);
if (!ptr->property_exists("_childid")) {
return;
@@ -200,7 +226,13 @@ 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());
int ret;
if (effect->m_isLink) {
Mlt::Chain fromChain(static_cast<Mlt::Producer *>(ptr.get())->parent());
ret = fromChain.detach(effect->link());
} else {
ret = ptr->detach(effect->filter());
}
effect.reset();
} else {
qDebug() << "TRYING TO REMOVE INVALID EFFECT!!!!!!!";
@@ -211,11 +243,40 @@ void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
}
}
int EffectItemModel::get_in() const
{
return m_isLink ? link().get_in() : filter().get_in();
}
int EffectItemModel::get_out() const
{
return m_isLink ? link().get_out() : filter().get_out();
}
int EffectItemModel::get_length() const
{
return m_isLink ? link().get_length() : filter().get_length();
}
void EffectItemModel::set_in_and_out(int in, int out)
{
if (m_isLink) {
link().set_in_and_out(in, out);
} else {
filter().set_in_and_out(in, out);
}
}
Mlt::Filter &EffectItemModel::filter() const
{
return *static_cast<Mlt::Filter *>(m_asset.get());
}
Mlt::Link &EffectItemModel::link() const
{
return *static_cast<Mlt::Link *>(m_asset.get());
}
bool EffectItemModel::isValid() const
{
return m_asset && m_asset->is_valid();
@@ -224,16 +285,16 @@ bool EffectItemModel::isValid() const
void EffectItemModel::setBuiltIn()
{
m_builtIn = true;
filter().set("kdenlive:builtin", 1);
getAsset()->set("kdenlive:builtin", 1);
}
void EffectItemModel::updateEnable(bool updateTimeline)
{
bool enabled = isAssetEnabled();
if (enabled) {
filter().clear("disable");
getAsset()->clear("disable");
} else {
filter().set("disable", 1);
getAsset()->set("disable", 1);
}
if (updateTimeline && !isAudio()) {
pCore->refreshProjectItem(m_ownerId);
@@ -249,23 +310,23 @@ void EffectItemModel::updateEnable(bool updateTimeline)
void EffectItemModel::setCollapsed(bool collapsed)
{
filter().set("kdenlive:collapsed", collapsed ? 1 : 0);
getAsset()->set("kdenlive:collapsed", collapsed ? 1 : 0);
}
bool EffectItemModel::isCollapsed() const
{
return filter().get_int("kdenlive:collapsed") == 1;
return getAsset()->get_int("kdenlive:collapsed") == 1;
}
void EffectItemModel::setKeyframesHidden(bool hidden)
{
Fun undo = [this, hidden]() {
filter().set("kdenlive:kfrhidden", hidden ? 0 : 1);
getAsset()->set("kdenlive:kfrhidden", hidden ? 0 : 1);
Q_EMIT hideKeyframesChange(hidden ? false : true);
return true;
};
Fun redo = [this, hidden]() {
filter().set("kdenlive:kfrhidden", hidden ? 1 : 0);
getAsset()->set("kdenlive:kfrhidden", hidden ? 1 : 0);
Q_EMIT hideKeyframesChange(hidden ? true : false);
return true;
};
@@ -275,17 +336,17 @@ void EffectItemModel::setKeyframesHidden(bool hidden)
bool EffectItemModel::isKeyframesHidden() const
{
return filter().get_int("kdenlive:kfrhidden") == 1;
return getAsset()->get_int("kdenlive:kfrhidden") == 1;
}
bool EffectItemModel::keyframesHiddenUnset() const
{
return filter().property_exists("kdenlive:kfrhidden") == false;
return getAsset()->property_exists("kdenlive:kfrhidden") == false;
}
bool EffectItemModel::hasForcedInOut() const
{
return filter().get_int("kdenlive:force_in_out") == 1 && filter().get_int("out") > 0;
return getAsset()->get_int("kdenlive:force_in_out") == 1 && getAsset()->get_int("out") > 0;
}
bool EffectItemModel::isAudio() const

View File

@@ -24,7 +24,7 @@ public:
/** @brief This construct an effect with an already existing filter
Only used when loading an existing clip
*/
static std::shared_ptr<EffectItemModel> construct(std::unique_ptr<Mlt::Properties> effect, std::shared_ptr<AbstractTreeModel> stack,
static std::shared_ptr<EffectItemModel> construct(std::unique_ptr<Mlt::Service> effect, std::shared_ptr<AbstractTreeModel> stack,
const QString &originalDecimalPoint);
/** @brief This function plants the effect into the given service in last position
@@ -38,6 +38,12 @@ public:
void unplantClone(const std::weak_ptr<Mlt::Service> &service) override;
Mlt::Filter &filter() const;
Mlt::Link &link() const;
int get_in() const;
int get_out() const;
int get_length() const;
void set_in_and_out(int in, int out);
void setEffectStackEnabled(bool enabled) override;
/** @brief Return true if the effect applies only to audio */
@@ -59,9 +65,10 @@ public:
void setBuiltIn();
protected:
EffectItemModel(const QList<QVariant> &effectData, std::unique_ptr<Mlt::Properties> effect, const QDomElement &xml, const QString &effectId,
EffectItemModel(const QList<QVariant> &effectData, std::unique_ptr<Mlt::Service> effect, const QDomElement &xml, const QString &effectId,
const std::shared_ptr<AbstractTreeModel> &stack, bool isEnabled = true, QString originalDecimalPoint = QString());
QMap<int, std::shared_ptr<EffectItemModel>> m_childEffects;
void updateEnable(bool updateTimeline = true) override;
int m_childId;
bool m_isLink{false};
};

View File

@@ -312,8 +312,8 @@ QDomElement EffectStackModel::toXml(QDomDocument &document)
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
QDomElement sub = document.createElement(QStringLiteral("effect"));
sub.setAttribute(QStringLiteral("id"), sourceEffect->getAssetId());
int filterIn = sourceEffect->filter().get_int("in");
int filterOut = sourceEffect->filter().get_int("out");
int filterIn = sourceEffect->getAsset()->get_int("in");
int filterOut = sourceEffect->getAsset()->get_int("out");
if (filterOut > filterIn) {
sub.setAttribute(QStringLiteral("in"), filterIn);
sub.setAttribute(QStringLiteral("out"), filterOut);
@@ -321,7 +321,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 &param : passProps) {
int paramVal = sourceEffect->filter().get_int(param.toUtf8().constData());
int paramVal = sourceEffect->getAsset()->get_int(param.toUtf8().constData());
if (paramVal > 0) {
Xml::setXmlProperty(sub, param, QString::number(paramVal));
}
@@ -346,15 +346,15 @@ 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 filterOut = sourceEffect->filter().get_int("out");
int filterIn = sourceEffect->getAsset()->get_int("in");
int filterOut = sourceEffect->getAsset()->get_int("out");
if (filterOut > filterIn) {
sub.setAttribute(QStringLiteral("in"), filterIn);
sub.setAttribute(QStringLiteral("out"), filterOut);
}
QStringList passProps{QStringLiteral("disable"), QStringLiteral("kdenlive:collapsed"), QStringLiteral("kdenlive:builtin")};
for (const QString &param : passProps) {
int paramVal = sourceEffect->filter().get_int(param.toUtf8().constData());
int paramVal = sourceEffect->getAsset()->get_int(param.toUtf8().constData());
if (paramVal > 0) {
Xml::setXmlProperty(sub, param, QString::number(paramVal));
}
@@ -436,8 +436,8 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
const QString in = node.attribute(QStringLiteral("in"));
const QString out = node.attribute(QStringLiteral("out"));
if (!out.isEmpty()) {
effect->filter().set("in", in.toUtf8().constData());
effect->filter().set("out", out.toUtf8().constData());
effect->getAsset()->set("in", in.toUtf8().constData());
effect->getAsset()->set("out", out.toUtf8().constData());
}
QMap<QString, std::pair<ParamType, bool>> keyframeParams = effect->getKeyframableParameters();
QVector<QPair<QString, QVariant>> parameters;
@@ -465,7 +465,7 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
if (Xml::hasXmlProperty(node, QLatin1String("kdenlive:builtin"))) {
effect->setBuiltIn();
if (Xml::hasXmlProperty(node, QLatin1String("kdenlive:hiddenbuiltin"))) {
effect->filter().set("kdenlive:hiddenbuiltin", Xml::getXmlProperty(node, QLatin1String("kdenlive:hiddenbuiltin")).toInt());
effect->getAsset()->set("kdenlive:hiddenbuiltin", Xml::getXmlProperty(node, QLatin1String("kdenlive:hiddenbuiltin")).toInt());
}
}
effect->setParameters(parameters);
@@ -479,25 +479,25 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
m_fadeIns.insert(effect->getId());
int duration = effect->filter().get_length() - 1;
effect->filter().set("in", currentIn);
effect->filter().set("out", currentIn + duration);
effect->getAsset()->set("in", currentIn);
effect->getAsset()->set("out", currentIn + duration);
if (effectId.startsWith(QLatin1String("fade_"))) {
const QString keyframeString = Xml::getXmlProperty(node, QLatin1String("level\nalpha"));
const QChar mod = AssetParameterModel::getKeyframeType(keyframeString);
if (effect->filter().get("alpha") == QLatin1String("1")) {
if (effect->getAsset()->get("alpha") == QLatin1String("1")) {
// Adjust level value to match filter end
if (!mod.isNull()) {
QString val = QStringLiteral("0%1=0;-1%1=1").arg(mod);
effect->filter().set("level", val.toUtf8().constData());
effect->getAsset()->set("level", val.toUtf8().constData());
} else {
effect->filter().set("level", "0=0;-1=1");
effect->getAsset()->set("level", "0=0;-1=1");
}
} else if (effect->filter().get("level") == QLatin1String("1")) {
} else if (effect->getAsset()->get("level") == QLatin1String("1")) {
if (!mod.isNull()) {
QString val = QStringLiteral("0%1=0;-1%1=1").arg(mod);
effect->filter().set("alpha", val.toUtf8().constData());
effect->getAsset()->set("alpha", val.toUtf8().constData());
} else {
effect->filter().set("alpha", "0=0;-1=1");
effect->getAsset()->set("alpha", "0=0;-1=1");
}
}
}
@@ -505,25 +505,25 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
m_fadeOuts.insert(effect->getId());
int duration = effect->filter().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);
effect->getAsset()->set("in", filterOut - duration);
effect->getAsset()->set("out", filterOut);
if (effectId.startsWith(QLatin1String("fade_"))) {
const QString keyframeString = Xml::getXmlProperty(node, QLatin1String("level\nalpha"));
const QChar mod = AssetParameterModel::getKeyframeType(keyframeString);
if (effect->filter().get("alpha") == QLatin1String("1")) {
if (effect->getAsset()->get("alpha") == QLatin1String("1")) {
// Adjust level value to match filter end
if (!mod.isNull()) {
QString val = QStringLiteral("0%1=1;-1%1=0").arg(mod);
effect->filter().set("level", val.toUtf8().constData());
effect->getAsset()->set("level", val.toUtf8().constData());
} else {
effect->filter().set("level", "0=1;-1=0");
effect->getAsset()->set("level", "0=1;-1=0");
}
} else if (effect->filter().get("level") == QLatin1String("1")) {
} else if (effect->getAsset()->get("level") == QLatin1String("1")) {
if (!mod.isNull()) {
QString val = QStringLiteral("0%1=1;-1%1=0").arg(mod);
effect->filter().set("alpha", val.toUtf8().constData());
effect->getAsset()->set("alpha", val.toUtf8().constData());
} else {
effect->filter().set("alpha", "0=1;-1=0");
effect->getAsset()->set("alpha", "0=1;-1=0");
}
}
}
@@ -574,32 +574,32 @@ bool EffectStackModel::copyEffectWithUndo(const std::shared_ptr<AbstractEffectIt
if (sourceEffect->isBuiltIn()) {
effect->setBuiltIn();
}
if (sourceEffect->filter().property_exists("kdenlive:kfrhidden")) {
effect->filter().set("kdenlive:kfrhidden", sourceEffect->filter().get_int("kdenlive:kfrhidden"));
if (sourceEffect->getAsset()->property_exists("kdenlive:kfrhidden")) {
effect->getAsset()->set("kdenlive:kfrhidden", sourceEffect->getAsset()->get_int("kdenlive:kfrhidden"));
}
if (sourceEffect->filter().property_exists("kdenlive:collapsed")) {
effect->filter().set("kdenlive:collapsed", sourceEffect->filter().get_int("kdenlive:collapsed"));
if (sourceEffect->getAsset()->property_exists("kdenlive:collapsed")) {
effect->getAsset()->set("kdenlive:collapsed", sourceEffect->getAsset()->get_int("kdenlive:collapsed"));
}
if (sourceEffect->filter().property_exists("kdenlive:builtin")) {
int builtin = sourceEffect->filter().get_int("kdenlive:builtin");
if (sourceEffect->getAsset()->property_exists("kdenlive:builtin")) {
int builtin = sourceEffect->getAsset()->get_int("kdenlive:builtin");
if (builtin == 1 && !enabled && !KdenliveSettings::enableBuiltInEffects()) {
// Ignore disabled builtin effects
return false;
}
effect->setBuiltIn();
if (sourceEffect->filter().property_exists("kdenlive:hiddenbuiltin")) {
effect->filter().set("kdenlive:hiddenbuiltin", sourceEffect->filter().get_int("kdenlive:hiddenbuiltin"));
if (sourceEffect->getAsset()->property_exists("kdenlive:hiddenbuiltin")) {
effect->getAsset()->set("kdenlive:hiddenbuiltin", sourceEffect->getAsset()->get_int("kdenlive:hiddenbuiltin"));
}
}
if (!enabled) {
effect->filter().set("disable", 1);
effect->getAsset()->set("disable", 1);
}
if (m_ownerId.type == KdenliveObjectType::TimelineTrack || m_ownerId.type == KdenliveObjectType::Master) {
effect->filter().set("in", 0);
effect->filter().set("out", pCore->getItemDuration(m_ownerId) - 1);
effect->getAsset()->set("in", 0);
effect->getAsset()->set("out", pCore->getItemDuration(m_ownerId) - 1);
} else {
effect->filter().set("in", sourceEffect->filter().get_int("in"));
effect->filter().set("out", sourceEffect->filter().get_int("out"));
effect->getAsset()->set("in", sourceEffect->getAsset()->get_int("in"));
effect->getAsset()->set("out", sourceEffect->getAsset()->get_int("out"));
}
Fun local_undo = removeItem_lambda(effect->getId());
// TODO the parent should probably not always be the root
@@ -613,15 +613,15 @@ bool EffectStackModel::copyEffectWithUndo(const std::shared_ptr<AbstractEffectIt
m_fadeIns.insert(effect->getId());
int duration = effect->filter().get_length() - 1;
int in = pCore->getItemIn(m_ownerId);
effect->filter().set("in", in);
effect->filter().set("out", in + duration);
effect->getAsset()->set("in", in);
effect->getAsset()->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 out = pCore->getItemIn(m_ownerId) + pCore->getItemDuration(m_ownerId) - 1;
effect->filter().set("in", out - duration);
effect->filter().set("out", out);
effect->getAsset()->set("in", out - duration);
effect->getAsset()->set("out", out);
roles << TimelineModel::FadeOutRole;
}
bool res = local_redo();
@@ -702,7 +702,7 @@ std::pair<bool, bool> EffectStackModel::doAppendEffect(const QString &effectId,
QMapIterator<QString, QString> i(params);
while (i.hasNext()) {
i.next();
effect->filter().set(i.key().toUtf8().constData(), i.value().toUtf8().constData());
effect->getAsset()->set(i.key().toUtf8().constData(), i.value().toUtf8().constData());
}
if (params.contains(QLatin1String("kdenlive:builtin"))) {
effect->setBuiltIn();
@@ -725,17 +725,17 @@ std::pair<bool, bool> EffectStackModel::doAppendEffect(const QString &effectId,
if (effectId.startsWith(QLatin1String("fadein")) || effectId.startsWith(QLatin1String("fade_from_"))) {
int duration = effect->filter().get_length() - 1;
int in = pCore->getItemIn(m_ownerId);
effect->filter().set("in", in);
effect->filter().set("out", in + duration);
effect->getAsset()->set("in", in);
effect->getAsset()->set("out", in + duration);
inFades++;
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
/*int duration = effect->filter().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);*/
effect->getAsset()->set("in", out - duration);
effect->getAsset()->set("out", out);*/
outFades++;
} else if (m_ownerId.type == KdenliveObjectType::TimelineTrack) {
effect->filter().set("out", pCore->getItemDuration(m_ownerId));
effect->getAsset()->set("out", pCore->getItemDuration(m_ownerId));
}
Fun update = [this, inFades, outFades]() {
// TODO: only update if effect is fade or keyframe
@@ -815,12 +815,12 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
};
PUSH_LAMBDA(operation, redo);
PUSH_LAMBDA(reverse, undo);
} else if (effectDuration < oldEffectOut - oldEffectIn || (logUndo && effect->filter().get_int("_refout") > 0)) {
} else if (effectDuration < oldEffectOut - oldEffectIn || (logUndo && effect->getAsset()->get_int("_refout") > 0)) {
// Clip length changed, shorter than effect length so resize
int referenceEffectOut = effect->filter().get_int("_refout");
int referenceEffectOut = effect->getAsset()->get_int("_refout");
if (referenceEffectOut <= 0) {
referenceEffectOut = oldEffectOut;
effect->filter().set("_refout", referenceEffectOut);
effect->getAsset()->set("_refout", referenceEffectOut);
}
Fun operation = [effect, oldEffectIn, effectDuration, logUndo]() {
effect->setParameter(QStringLiteral("out"), oldEffectIn + effectDuration, logUndo);
@@ -833,7 +833,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
if (logUndo) {
Fun reverse = [effect, referenceEffectOut]() {
effect->setParameter(QStringLiteral("out"), referenceEffectOut, true);
effect->filter().set("_refout", nullptr);
effect->getAsset()->set("_refout", nullptr);
return true;
};
PUSH_LAMBDA(operation, redo);
@@ -844,12 +844,12 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
// Adjust fade out
int effectDuration = qMin(fadeOutDuration, duration);
int newFadeIn = out - effectDuration;
int oldFadeIn = effect->filter().get_int("in");
int oldOut = effect->filter().get_int("out");
int referenceEffectIn = effect->filter().get_int("_refin");
int oldFadeIn = effect->getAsset()->get_int("in");
int oldOut = effect->getAsset()->get_int("out");
int referenceEffectIn = effect->getAsset()->get_int("_refin");
if (referenceEffectIn <= 0) {
referenceEffectIn = oldFadeIn;
effect->filter().set("_refin", referenceEffectIn);
effect->getAsset()->set("_refin", referenceEffectIn);
}
Fun operation = [effect, newFadeIn, out, logUndo]() {
effect->setParameter(QStringLiteral("in"), newFadeIn, false);
@@ -864,7 +864,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
Fun reverse = [effect, referenceEffectIn, oldOut]() {
effect->setParameter(QStringLiteral("in"), referenceEffectIn, false);
effect->setParameter(QStringLiteral("out"), oldOut, true);
effect->filter().set("_refin", nullptr);
effect->getAsset()->set("_refin", nullptr);
return true;
};
PUSH_LAMBDA(operation, redo);
@@ -872,7 +872,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
}
} else {
// Not a fade effect, check for keyframes
bool hasZone = effect->filter().get_int("kdenlive:force_in_out") == 1 && effect->filter().get_int("out");
bool hasZone = effect->getAsset()->get_int("kdenlive:force_in_out") == 1 && effect->getAsset()->get_int("out");
std::shared_ptr<KeyframeModelList> keyframes = effect->getKeyframeModel();
if (keyframes != nullptr) {
// Effect has keyframes, update these
@@ -889,7 +889,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->get_out();
Fun operation = [effect, out, logUndo]() {
effect->setParameter(QStringLiteral("out"), out, logUndo);
return true;
@@ -907,12 +907,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->get_in());
int oldEffectOut = effect->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->set_in_and_out(newIn, newOut);
qDebug() << "--new effect: " << newIn << "-" << newOut;
return true;
};
@@ -921,7 +921,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->set_in_and_out(oldEffectIn, oldEffectOut);
return true;
};
PUSH_LAMBDA(operation, redo);
@@ -956,31 +956,31 @@ 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->get_length();
}
effect->filter().set("in", in);
effect->getAsset()->set("in", in);
duration = qMin(pCore->getItemDuration(m_ownerId), duration);
effect->filter().set("out", in + duration);
effect->getAsset()->set("out", in + duration);
indexes << getIndexFromItem(effect);
if (effect->filter().get("alpha") == QLatin1String("1")) {
if (effect->getAsset()->get("alpha") == QLatin1String("1")) {
// Adjust level value to match filter end
const QString current = effect->filter().get("level");
const QString current = effect->getAsset()->get("level");
const QChar mod = AssetParameterModel::getKeyframeType(current);
if (!mod.isNull()) {
const QString val = QStringLiteral("0%1=0;-1%1=1").arg(mod);
effect->filter().set("level", val.toUtf8().constData());
effect->getAsset()->set("level", val.toUtf8().constData());
} else {
effect->filter().set("level", "0=0;-1=1");
effect->getAsset()->set("level", "0=0;-1=1");
}
} else if (effect->filter().get("level") == QLatin1String("1")) {
} else if (effect->getAsset()->get("level") == QLatin1String("1")) {
// Adjust level value to match filter end
const QString current = effect->filter().get("alpha");
const QString current = effect->getAsset()->get("alpha");
const QChar mod = AssetParameterModel::getKeyframeType(current);
if (!mod.isNull()) {
const QString val = QStringLiteral("0%1=0;-1%1=1").arg(mod);
effect->filter().set("alpha", val.toUtf8().constData());
effect->getAsset()->set("alpha", val.toUtf8().constData());
} else {
effect->filter().set("alpha", "0=0;-1=1");
effect->getAsset()->set("alpha", "0=0;-1=1");
}
}
}
@@ -1020,30 +1020,30 @@ 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->get_length();
}
effect->filter().set("out", out);
effect->getAsset()->set("out", out);
duration = qMin(itemDuration, duration);
effect->filter().set("in", out - duration);
effect->getAsset()->set("in", out - duration);
indexes << getIndexFromItem(effect);
if (effect->filter().get("alpha") == QLatin1String("1")) {
if (effect->getAsset()->get("alpha") == QLatin1String("1")) {
// Adjust level value to match filter end
const QString current = effect->filter().get("level");
const QString current = effect->getAsset()->get("level");
const QChar mod = AssetParameterModel::getKeyframeType(current);
if (!mod.isNull()) {
const QString val = QStringLiteral("0%1=1;-1%1=0").arg(mod);
effect->filter().set("level", val.toUtf8().constData());
effect->getAsset()->set("level", val.toUtf8().constData());
} else {
effect->filter().set("level", "0=1;-1=0");
effect->getAsset()->set("level", "0=1;-1=0");
}
} else if (effect->filter().get("level") == QLatin1String("1")) {
const QString current = effect->filter().get("alpha");
} else if (effect->getAsset()->get("level") == QLatin1String("1")) {
const QString current = effect->getAsset()->get("alpha");
const QChar mod = AssetParameterModel::getKeyframeType(current);
if (!mod.isNull()) {
const QString val = QStringLiteral("0%1=1;-1%1=0").arg(mod);
effect->filter().set("alpha", val.toUtf8().constData());
effect->getAsset()->set("alpha", val.toUtf8().constData());
} else {
effect->filter().set("alpha", "0=1;-1=0");
effect->getAsset()->set("alpha", "0=1;-1=0");
}
}
}
@@ -1103,9 +1103,9 @@ int EffectStackModel::getFadeMethod(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));
QString fadeData = effect->filter().get("alpha");
QString fadeData = effect->getAsset()->get("alpha");
if (!fadeData.contains(QLatin1Char('='))) {
fadeData = effect->filter().get("level");
fadeData = effect->getAsset()->get("level");
if (!fadeData.contains(QLatin1Char('='))) {
return 0;
}
@@ -1125,9 +1125,9 @@ int EffectStackModel::getFadeMethod(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));
QString fadeData = effect->filter().get("alpha");
QString fadeData = effect->getAsset()->get("alpha");
if (!fadeData.contains(QLatin1Char('='))) {
fadeData = effect->filter().get("level");
fadeData = effect->getAsset()->get("level");
if (!fadeData.contains(QLatin1Char('='))) {
return 0;
}
@@ -1153,7 +1153,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->get_length() - 1;
}
}
} else {
@@ -1163,7 +1163,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->get_length() - 1;
}
}
}
@@ -1267,7 +1267,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->set_in_and_out(in, out);
}
if (!m_loadingExisting) {
// qDebug() << "$$$$$$$$$$$$$$$$$$$$$ Planting effect in " << m_childServices.size();
@@ -1482,7 +1482,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::Service> asset = EffectsRepository::get()->getEffect(effectId);
asset->inherit(*(filter));
effect = EffectItemModel::construct(std::move(asset), shared_from_this(), originalDecimalPoint);
}
@@ -1510,22 +1510,22 @@ 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->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) {
if (effect->getAsset()->get_int("in") != clipIn) {
// Broken fade, fix
int filterLength = effect->filter().get_length() - 1;
effect->filter().set("in", clipIn);
effect->filter().set("out", clipIn + filterLength);
int filterLength = effect->get_length() - 1;
effect->getAsset()->set("in", clipIn);
effect->getAsset()->set("out", clipIn + filterLength);
}
} else if (effectId.startsWith(QLatin1String("fadeout")) || effectId.startsWith(QLatin1String("fade_to_"))) {
m_fadeOuts.insert(effect->getId());
if (effect->filter().get_int("out") != clipOut) {
if (effect->getAsset()->get_int("out") != clipOut) {
// Broken fade, fix
int filterLength = effect->filter().get_length() - 1;
effect->filter().set("in", clipOut - filterLength);
effect->filter().set("out", clipOut);
int filterLength = effect->get_length() - 1;
effect->getAsset()->set("in", clipOut - filterLength);
effect->getAsset()->set("out", clipOut);
}
}
}
@@ -1727,7 +1727,7 @@ double EffectStackModel::getFilterParam(const QString &effectId, const QString &
for (int i = 0; i < rootItem->childCount(); ++i) {
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
if (effectId == sourceEffect->getAssetId()) {
return sourceEffect->filter().get_double(paramName.toUtf8().constData());
return sourceEffect->getAsset()->get_double(paramName.toUtf8().constData());
}
}
return 0.0;
@@ -1885,7 +1885,7 @@ bool EffectStackModel::addEffectKeyFrame(int frame, double normalisedVal)
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(ix));
std::shared_ptr<KeyframeModelList> listModel = sourceEffect->getKeyframeModel();
if (m_ownerId.type == KdenliveObjectType::TimelineTrack) {
sourceEffect->filter().set("out", pCore->getItemDuration(m_ownerId));
sourceEffect->getAsset()->set("out", pCore->getItemDuration(m_ownerId));
}
return listModel->addKeyframe(frame, normalisedVal);
}
@@ -1912,7 +1912,7 @@ bool EffectStackModel::updateKeyFrame(int oldFrame, int newFrame, QVariant norma
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(ix));
std::shared_ptr<KeyframeModelList> listModel = sourceEffect->getKeyframeModel();
if (m_ownerId.type == KdenliveObjectType::TimelineTrack) {
sourceEffect->filter().set("out", pCore->getItemDuration(m_ownerId));
sourceEffect->getAsset()->set("out", pCore->getItemDuration(m_ownerId));
}
return listModel->updateKeyframe(GenTime(oldFrame, pCore->getCurrentFps()), GenTime(newFrame, pCore->getCurrentFps()), std::move(normalisedVal));
}
@@ -2097,8 +2097,8 @@ void EffectStackModel::appendAudioBuildInEffects()
}
QWriteLocker lock(&m_lock);
auto effect = EffectItemModel::construct(QStringLiteral("volume"), shared_from_this(), false);
effect->filter().set("disable", 1);
effect->filter().set("kdenlive:kfrhidden", 1);
effect->getAsset()->set("disable", 1);
effect->getAsset()->set("kdenlive:kfrhidden", 1);
effect->setBuiltIn();
effect->prepareKeyframes();
connect(effect.get(), &AssetParameterModel::modelChanged, this, &EffectStackModel::modelChanged);
@@ -2124,9 +2124,9 @@ void EffectStackModel::appendVideoBuildInEffects()
QWriteLocker locker(&m_lock);
std::shared_ptr<EffectItemModel> effect = EffectItemModel::construct(QStringLiteral("qtblend"), shared_from_this(), false);
effect->prepareKeyframes();
effect->filter().set("disable", 1);
// effect->filter().set("kdenlive:kfrhidden", 1);
effect->filter().set("kdenlive:collapsed", 1);
effect->getAsset()->set("disable", 1);
// effect->getAsset()->set("kdenlive:kfrhidden", 1);
effect->getAsset()->set("kdenlive:collapsed", 1);
effect->setBuiltIn();
connect(effect.get(), &AssetParameterModel::modelChanged, this, &EffectStackModel::modelChanged);
connect(effect.get(), &AssetParameterModel::replugEffect, this, &EffectStackModel::replugEffect, Qt::DirectConnection);

View File

@@ -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::Service> 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()));