Refactor bin effects to fix major corruption

Fixes #15
parent 5e2374e2
......@@ -176,7 +176,7 @@ void AssetParameterModel::setParameter(const QString &name, const QString &value
Q_ASSERT(m_asset->is_valid());
QLocale locale;
locale.setNumberOptions(QLocale::OmitGroupSeparator);
qDebug()<<"// PROCESSING PARAM CHANGE!!! ";
qDebug()<<"// PROCESSING PARAM CHANGE: "<<name;
bool conversionSuccess;
double doubleValue = locale.toDouble(value, &conversionSuccess);
if (conversionSuccess) {
......@@ -212,11 +212,13 @@ void AssetParameterModel::setParameter(const QString &name, const QString &value
if (paramIndex.isValid()) {
emit dataChanged(paramIndex, paramIndex);
} else {
emit dataChanged(index(0, 0), index(m_rows.count(), 0));
QModelIndex ix = index(m_rows.indexOf(name), 0);
emit dataChanged(ix, ix);
}
emit modelChanged();
}
}
emit updateChildren(name);
// Update timeline view if necessary
if (m_ownerId.first == ObjectType::NoItem) {
// Used for generator clips
......
......@@ -195,6 +195,9 @@ protected:
signals:
void modelChanged();
/** @brief inform child effects (in case of bin effect with timeline producers)
* that a change occured and a param update is needed **/
void updateChildren(const QString &name);
void compositionTrackChanged();
void replugEffect(std::shared_ptr<AssetParameterModel> asset);
void rebuildEffect(std::shared_ptr<AssetParameterModel> asset);
......
......@@ -458,7 +458,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
Mlt::Filter converter(*prod->profile(), "avcolor_space");
m_thumbsProducer->attach(converter);
} else {
m_thumbsProducer = cloneProducer(pCore->thumbProfile());
m_thumbsProducer = cloneProducer(pCore->thumbProfile(), true);
Mlt::Filter converter(*pCore->thumbProfile(), "avcolor_space");
m_thumbsProducer->attach(converter);
}
......@@ -487,7 +487,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int clipId, Play
if (state == PlaylistState::AudioOnly) {
// We need to get an audio producer, if none exists
if (m_audioProducers.count(clipId) == 0) {
m_audioProducers[clipId] = cloneProducer(&pCore->getCurrentProfile()->profile());
m_audioProducers[clipId] = cloneProducer(&pCore->getCurrentProfile()->profile(), true);
m_audioProducers[clipId]->set("set.test_audio", 0);
m_audioProducers[clipId]->set("set.test_image", 1);
m_effectStack->addService(m_audioProducers[clipId]);
......@@ -502,7 +502,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int clipId, Play
// we return the video producer
// We need to get an audio producer, if none exists
if (m_videoProducers.count(clipId) == 0) {
m_videoProducers[clipId] = cloneProducer(&pCore->getCurrentProfile()->profile());
m_videoProducers[clipId] = cloneProducer(&pCore->getCurrentProfile()->profile(), true);
m_videoProducers[clipId]->set("set.test_audio", 1);
m_videoProducers[clipId]->set("set.test_image", 0);
m_effectStack->addService(m_videoProducers[clipId]);
......@@ -608,24 +608,24 @@ std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTim
master->parent().set("_loaded", 1);
if (state == PlaylistState::AudioOnly) {
m_audioProducers[clipId] = std::shared_ptr<Mlt::Producer>(new Mlt::Producer(&master->parent()));
m_effectStack->addService(m_audioProducers[clipId]);
m_effectStack->loadService(m_audioProducers[clipId]);
return {master, true};
}
if (timeWarp) {
m_timewarpProducers[clipId] = std::shared_ptr<Mlt::Producer>(new Mlt::Producer(&master->parent()));
m_effectStack->addService(m_timewarpProducers[clipId]);
m_effectStack->loadService(m_timewarpProducers[clipId]);
return {master, true};
}
if (state == PlaylistState::VideoOnly) {
// good, we found a master video producer, and we didn't have any
m_videoProducers[clipId] = std::shared_ptr<Mlt::Producer>(new Mlt::Producer(&master->parent()));
m_effectStack->addService(m_videoProducers[clipId]);
m_effectStack->loadService(m_videoProducers[clipId]);
return {master, true};
}
if (state == PlaylistState::Disabled && !m_disabledProducer) {
// good, we found a master disabled producer, and we didn't have any
m_disabledProducer.reset(master->parent().cut());
m_effectStack->addService(m_disabledProducer);
m_effectStack->loadService(m_disabledProducer);
return {master, true};
}
qDebug() << "Warning: weird, we found a clip whose master is not loaded but we already have a master";
......@@ -681,7 +681,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::timelineProducer(PlaylistState::Clip
return std::shared_ptr<Mlt::Producer>(normalProd->cut());
}*/
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProfile)
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProfile, bool removeEffects)
{
Mlt::Consumer c(*m_masterProducer->profile(), "xml", "string");
Mlt::Service s(m_masterProducer->get_service());
......@@ -705,6 +705,26 @@ std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProf
if (strcmp(prod->get("mlt_service"), "avformat") == 0) {
prod->set("mlt_service", "avformat-novalidate");
}
if (removeEffects) {
int ct = 0;
Mlt::Filter *filter = prod->filter(ct);
while (filter) {
qDebug()<<"// EFFECT "<<ct<<" : "<<filter->get("mlt_service");
QString ix = QString::fromLatin1(filter->get("kdenlive_id"));
if (!ix.isEmpty()) {
qDebug()<<"/ + + DELTING";
if (prod->detach(*filter) == 0) {
} else {
ct++;
}
} else {
ct++;
}
delete filter;
filter = prod->filter(ct);
}
}
prod->set("id", (char*)nullptr);
return prod;
}
......@@ -1234,6 +1254,24 @@ void ProjectClip::setBinEffectsEnabled(bool enabled)
ClipController::setBinEffectsEnabled(enabled);
}
void ProjectClip::registerService(std::weak_ptr<TimelineModel> timeline, int clipId, std::shared_ptr <Mlt::Producer> service, bool forceRegister)
{
if (!service->is_cut() || forceRegister) {
int hasAudio = service->get_int("set.test_audio") == 0;
int hasVideo = service->get_int("set.test_image") == 0;
if (hasVideo && m_videoProducers.count(clipId) == 0) {
// This is an undo producer, register it!
m_videoProducers[clipId] = service;
m_effectStack->addService(m_videoProducers[clipId]);
} else if (hasAudio && m_audioProducers.count(clipId) == 0) {
// This is an undo producer, register it!
m_audioProducers[clipId] = service;
m_effectStack->addService(m_audioProducers[clipId]);
}
}
registerTimelineClip(timeline, clipId);
}
void ProjectClip::registerTimelineClip(std::weak_ptr<TimelineModel> timeline, int clipId)
{
Q_ASSERT(m_registeredClips.count(clipId) == 0);
......@@ -1244,8 +1282,17 @@ void ProjectClip::registerTimelineClip(std::weak_ptr<TimelineModel> timeline, in
void ProjectClip::deregisterTimelineClip(int clipId)
{
qDebug()<<" ** * DEREGISTERING TIMELINE CLIP: "<<clipId;
Q_ASSERT(m_registeredClips.count(clipId) > 0);
m_registeredClips.erase(clipId);
if (m_videoProducers.count(clipId) > 0) {
m_effectStack->removeService(m_videoProducers[clipId]);
m_videoProducers.erase(clipId);
}
if (m_audioProducers.count(clipId) > 0) {
m_effectStack->removeService(m_audioProducers[clipId]);
m_audioProducers.erase(clipId);
}
setRefCount((uint)m_registeredClips.size());
}
......
......@@ -213,7 +213,7 @@ public:
std::pair<std::shared_ptr<Mlt::Producer>, bool> giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master,
PlaylistState::ClipState state);
std::shared_ptr<Mlt::Producer> cloneProducer(Mlt::Profile *destProfile = nullptr);
std::shared_ptr<Mlt::Producer> cloneProducer(Mlt::Profile *destProfile = nullptr, bool removeEffects = false);
static std::shared_ptr<Mlt::Producer> cloneProducer(std::shared_ptr<Mlt::Producer> producer);
std::shared_ptr<Mlt::Producer> softClone(const char *list);
void updateTimelineClips(QVector<int> roles);
......@@ -225,6 +225,7 @@ protected:
@param clipId id of the inserted clip
*/
void registerTimelineClip(std::weak_ptr<TimelineModel> timeline, int clipId);
void registerService(std::weak_ptr<TimelineModel> timeline, int clipId, std::shared_ptr <Mlt::Producer> service, bool forceRegister = false);
/* @brief update the producer to reflect new parent folder */
void updateParent(std::shared_ptr<TreeItem> parent) override;
......
......@@ -56,9 +56,11 @@ public:
/* @brief This function plants the effect into the given service in last position
*/
virtual void plant(const std::weak_ptr<Mlt::Service> &service) = 0;
virtual void plantClone(const std::weak_ptr<Mlt::Service> &service) = 0;
/* @brief This function unplants (removes) the effect from the given service
*/
virtual void unplant(const std::weak_ptr<Mlt::Service> &service) = 0;
virtual void unplantClone(const std::weak_ptr<Mlt::Service> &service) = 0;
protected:
/* @brief Toogles the mlt effect according to the current activation state*/
......
......@@ -65,9 +65,21 @@ void EffectGroupModel::plant(const std::weak_ptr<Mlt::Service> &service)
std::static_pointer_cast<AbstractEffectItem>(child(i))->plant(service);
}
}
void EffectGroupModel::plantClone(const std::weak_ptr<Mlt::Service> &service)
{
for (int i = 0; i < childCount(); ++i) {
std::static_pointer_cast<AbstractEffectItem>(child(i))->plantClone(service);
}
}
void EffectGroupModel::unplant(const std::weak_ptr<Mlt::Service> &service)
{
for (int i = 0; i < childCount(); ++i) {
std::static_pointer_cast<AbstractEffectItem>(child(i))->unplant(service);
}
}
void EffectGroupModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
{
for (int i = 0; i < childCount(); ++i) {
std::static_pointer_cast<AbstractEffectItem>(child(i))->unplantClone(service);
}
}
......@@ -43,9 +43,11 @@ public:
/* @brief This function plants the effect into the given service in last position
*/
void plant(const std::weak_ptr<Mlt::Service> &service) override;
void plantClone(const std::weak_ptr<Mlt::Service> &service) override;
/* @brief This function unplants (removes) the effect from the given service
*/
void unplant(const std::weak_ptr<Mlt::Service> &service) override;
void unplantClone(const std::weak_ptr<Mlt::Service> &service) override;
protected:
EffectGroupModel(const QList<QVariant> &data, const QString &name, const std::shared_ptr<AbstractTreeModel> &stack, bool isRoot = false);
......
......@@ -26,11 +26,23 @@
#include "effectstackmodel.hpp"
#include <utility>
EffectItemModel::EffectItemModel(const QList<QVariant> &data, Mlt::Properties *effect, const QDomElement &xml, const QString &effectId,
EffectItemModel::EffectItemModel(const QList<QVariant> &effectData, Mlt::Properties *effect, const QDomElement &xml, const QString &effectId,
const std::shared_ptr<AbstractTreeModel> &stack, bool isEnabled)
: AbstractEffectItem(EffectItemType::Effect, data, stack, false, isEnabled)
: AbstractEffectItem(EffectItemType::Effect, effectData, stack, false, isEnabled)
, AssetParameterModel(effect, xml, effectId, std::static_pointer_cast<EffectStackModel>(stack)->getOwnerId())
, m_childId(0)
{
connect(this, &AssetParameterModel::updateChildren, [&](const QString &name) {
if (m_childEffects.size() == 0) {
return;
}
qDebug()<<"* * *SETTING EFFECT PARAM: "<<name<<" = "<<m_asset->get(name.toUtf8().constData());
QMapIterator<int, std::shared_ptr<EffectItemModel> > i(m_childEffects);
while (i.hasNext()) {
i.next();
i.value()->filter().set(name.toUtf8().constData(), m_asset->get(name.toUtf8().constData()));
}
});
}
// static
......@@ -87,6 +99,57 @@ void EffectItemModel::plant(const std::weak_ptr<Mlt::Service> &service)
}
}
void EffectItemModel::loadClone(const std::weak_ptr<Mlt::Service> &service)
{
if (auto ptr = service.lock()) {
const QString effectId = getAssetId();
std::shared_ptr<EffectItemModel> effect = nullptr;
for (int i = 0; i < ptr->filter_count(); i++) {
std::shared_ptr<Mlt::Filter> filt(ptr->filter(i));
QString effName = filt->get("kdenlive_id");
if (effName == effectId && filt->get_int("_kdenlive_processed") == 0) {
if (auto ptr2 = m_model.lock()) {
effect = EffectItemModel::construct(ptr->filter(i), ptr2);
int childId = ptr->get_int("_childid");
if (childId == 0) {
childId = m_childId++;
ptr->set("_childid", childId);
}
m_childEffects.insert(childId, effect);
}
break;
}
filt->set("_kdenlive_processed", 1);
}
return;
}
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
Q_ASSERT(false);
}
void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service)
{
if (auto ptr = service.lock()) {
const QString effectId = getAssetId();
std::shared_ptr<EffectItemModel> effect = nullptr;
if (auto ptr2 = m_model.lock()) {
effect = EffectItemModel::construct(effectId, ptr2);
effect->setParameters(getAllParameters());
int childId = ptr->get_int("_childid");
if (childId == 0) {
childId = m_childId++;
ptr->set("_childid", childId);
}
m_childEffects.insert(childId, effect);
int ret = ptr->attach(effect->filter());
Q_ASSERT(ret == 0);
return;
}
}
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
Q_ASSERT(false);
}
void EffectItemModel::unplant(const std::weak_ptr<Mlt::Service> &service)
{
if (auto ptr = service.lock()) {
......@@ -98,11 +161,36 @@ void EffectItemModel::unplant(const std::weak_ptr<Mlt::Service> &service)
}
}
void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service)
{
if (m_childEffects.size() == 0) {
return;
}
if (auto ptr = service.lock()) {
int ret = ptr->detach(filter());
Q_ASSERT(ret == 0);
int childId = ptr->get_int("_childid");
auto effect = m_childEffects.take(childId);
if (effect && effect->isValid()) {
ptr->detach(effect->filter());
effect.reset();
}
} else {
qDebug() << "Error : Cannot plant effect because parent service is not available anymore";
Q_ASSERT(false);
}
}
Mlt::Filter &EffectItemModel::filter() const
{
return *static_cast<Mlt::Filter *>(m_asset.get());
}
bool EffectItemModel::isValid() const
{
return m_asset && m_asset->is_valid();
}
void EffectItemModel::updateEnable()
{
filter().set("disable", isEnabled() ? 0 : 1);
......@@ -114,6 +202,8 @@ void EffectItemModel::updateEnable()
qDebug() << "Error, unable to send update to deleted model";
Q_ASSERT(false);
}
// Update timeline child producers
AssetParameterModel::updateChildren(QStringLiteral("disable"));
}
void EffectItemModel::setCollapsed(bool collapsed)
......
......@@ -46,9 +46,12 @@ public:
/* @brief This function plants the effect into the given service in last position
*/
void plant(const std::weak_ptr<Mlt::Service> &service) override;
void plantClone(const std::weak_ptr<Mlt::Service> &service) override;
void loadClone(const std::weak_ptr<Mlt::Service> &service);
/* @brief This function unplants (removes) the effect from the given service
*/
void unplant(const std::weak_ptr<Mlt::Service> &service) override;
void unplantClone(const std::weak_ptr<Mlt::Service> &service) override;
Mlt::Filter &filter() const;
......@@ -57,12 +60,14 @@ public:
void setCollapsed(bool collapsed);
bool isCollapsed();
bool isValid() const;
protected:
EffectItemModel(const QList<QVariant> &data, Mlt::Properties *effect, const QDomElement &xml, const QString &effectId,
EffectItemModel(const QList<QVariant> &effectData, Mlt::Properties *effect, const QDomElement &xml, const QString &effectId,
const std::shared_ptr<AbstractTreeModel> &stack, bool isEnabled = true);
QMap <int, std::shared_ptr<EffectItemModel> > m_childEffects;
void updateEnable() override;
int m_childId;
};
#endif
......@@ -122,6 +122,8 @@ public:
/* @brief Append a new service to be managed by this stack */
void addService(std::weak_ptr<Mlt::Service> service);
/* @brief Append an existing service to be managed by this stack (on document load)*/
void loadService(std::weak_ptr<Mlt::Service> service);
/* @brief Remove a service from those managed by this stack */
void removeService(std::shared_ptr<Mlt::Service> service);
......@@ -152,7 +154,8 @@ protected:
/* @brief This is a convenience function that helps check if the tree is in a valid state */
bool checkConsistency() override;
std::vector<std::weak_ptr<Mlt::Service>> m_services;
std::weak_ptr<Mlt::Service> m_masterService;
std::vector<std::weak_ptr<Mlt::Service>> m_childServices;
bool m_effectStackEnabled;
ObjectId m_ownerId;
......
......@@ -110,14 +110,14 @@ int ClipModel::construct(const std::shared_ptr<TimelineModel> &parent, const QSt
return id;
}
void ClipModel::registerClipToBin()
void ClipModel::registerClipToBin(std::shared_ptr <Mlt::Producer> service, bool registerProducer)
{
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(m_binClipId);
if (!binClip) {
qDebug() << "Error : Bin clip for id: " << m_binClipId << " NOT AVAILABLE!!!";
}
qDebug() << "REGISTRATION " << m_id << "ptr count" << m_parent.use_count();
binClip->registerTimelineClip(m_parent, m_id);
binClip->registerService(m_parent, m_id, service, registerProducer);
}
void ClipModel::deregisterClipToBin()
......@@ -259,6 +259,12 @@ Mlt::Producer *ClipModel::service() const
return m_producer.get();
}
std::shared_ptr<Mlt::Producer> ClipModel::getProducer()
{
READ_LOCK();
return m_producer;
}
int ClipModel::getPlaytime() const
{
READ_LOCK();
......
......@@ -118,7 +118,7 @@ public:
/** @brief Returns the bin clip's id */
const QString &binId() const;
void registerClipToBin();
void registerClipToBin(std::shared_ptr <Mlt::Producer> service, bool registerProducer);
void deregisterClipToBin();
bool addEffect(const QString &effectId);
......@@ -189,6 +189,7 @@ protected:
protected:
std::shared_ptr<Mlt::Producer> m_producer;
std::shared_ptr<Mlt::Producer> getProducer();
std::shared_ptr<EffectStackModel> m_effectStack;
......
......@@ -842,10 +842,10 @@ bool TimelineModel::requestClipCreation(const QString &binClipId, int &id, Playl
Fun local_undo = deregisterClip_lambda(clipId);
ClipModel::construct(shared_from_this(), bid, clipId, state);
auto clip = m_allClips[clipId];
Fun local_redo = [clip, this, state]() {
Fun local_redo = [clip, this, state, clipId]() {
// We capture a shared_ptr to the clip, which means that as long as this undo object lives, the clip object is not deleted. To insert it back it is
// sufficient to register it.
registerClip(clip);
registerClip(clip, true);
clip->refreshProducerFromBin(state);
return true;
};
......@@ -1039,7 +1039,7 @@ bool TimelineModel::requestClipDeletion(int clipId, Fun &undo, Fun &redo)
Fun reverse = [this, clip]() {
// We capture a shared_ptr to the clip, which means that as long as this undo object lives, the clip object is not deleted. To insert it back it is
// sufficient to register it.
registerClip(clip);
registerClip(clip, true);
return true;
};
if (operation()) {
......@@ -1741,13 +1741,13 @@ void TimelineModel::registerTrack(std::shared_ptr<TrackModel> track, int pos, bo
}
}
void TimelineModel::registerClip(const std::shared_ptr<ClipModel> &clip)
void TimelineModel::registerClip(const std::shared_ptr<ClipModel> &clip, bool registerProducer)
{
int id = clip->getId();
qDebug() << " // /REQUEST TL CLP REGSTR: " << id << "\n--------\nCLIPS COUNT: " << m_allClips.size();
Q_ASSERT(m_allClips.count(id) == 0);
m_allClips[id] = clip;
clip->registerClipToBin();
clip->registerClipToBin(clip->getProducer(), registerProducer);
m_groups->createGroupItem(id);
clip->setTimelineEffectsEnabled(m_timelineEffectsEnabled);
}
......
......@@ -607,7 +607,7 @@ protected:
/* @brief Register a new clip. This is a call-back meant to be called from ClipModel
*/
void registerClip(const std::shared_ptr<ClipModel> &clip);
void registerClip(const std::shared_ptr<ClipModel> &clip, bool registerProducer = false);
/* @brief Register a new composition. This is a call-back meant to be called from CompositionModel
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment