Commit 3fc4464f authored by Nicolas Carion's avatar Nicolas Carion
Browse files

Steps towards better gestion of the master producers in the projectClip

parent 64c152b3
......@@ -28,9 +28,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "doc/kthumb.h"
#include "effects/effectstack/model/effectstackmodel.hpp"
#include "jobs/jobmanager.h"
#include "jobs/thumbjob.hpp"
#include "jobs/loadjob.hpp"
#include <jobs/proxyclipjob.h>
#include "jobs/thumbjob.hpp"
#include "kdenlivesettings.h"
#include "lib/audio/audioStreamInfo.h"
#include "mltcontroller/clip.h"
......@@ -49,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "utils/thumbnailcache.hpp"
#include "xml/xml.hpp"
#include <QPainter>
#include <jobs/proxyclipjob.h>
#include <kimagecache.h>
#include "kdenlive_debug.h"
......@@ -77,7 +77,8 @@ ProjectClip::ProjectClip(const QString &id, const QIcon &thumb, std::shared_ptr<
} else {
m_thumbnail = thumb;
}
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video ||
m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->addWatchFile(id, clipUrl());
}
// Make sure we have a hash for this clip
......@@ -138,7 +139,8 @@ std::shared_ptr<ProjectClip> ProjectClip::construct(const QString &id, const QDo
ProjectClip::~ProjectClip()
{
// controller is deleted in bincontroller
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video ||
m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->removeWatchFile(clipId(), clipUrl());
}
m_thumbMutex.lock();
......@@ -146,11 +148,6 @@ ProjectClip::~ProjectClip()
m_thumbMutex.unlock();
m_thumbThread.waitForFinished();
audioFrameCache.clear();
// delete all timeline producers
std::map<int, std::shared_ptr<Mlt::Producer>>::iterator itr = m_timelineProducers.begin();
while (itr != m_timelineProducers.end()) {
itr = m_timelineProducers.erase(itr);
}
}
void ProjectClip::connectEffectStack()
......@@ -301,7 +298,7 @@ void ProjectClip::reloadProducer(bool refreshOnly)
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadjobId, QString(), 150, -1, true, true);
} else {
//TODO: check if another load job is running?
// TODO: check if another load job is running?
QDomDocument doc;
QDomElement xml = toXml(doc);
if (!xml.isNull()) {
......@@ -341,7 +338,8 @@ void ProjectClip::setThumbnail(const QImage &img)
}
m_thumbnail = QIcon(thumb);
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataThumbnail);
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()),
AbstractProjectItem::DataThumbnail);
}
}
......@@ -379,11 +377,13 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshPanel(m_binId);
}
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataDuration);
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()),
AbstractProjectItem::DataDuration);
}
// Make sure we have a hash for this clip
getFileHash();
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
if (m_clipType == ClipType::AV || m_clipType == ClipType::Audio || m_clipType == ClipType::Image || m_clipType == ClipType::Video ||
m_clipType == ClipType::Playlist || m_clipType == ClipType::TextTemplate) {
pCore->bin()->addWatchFile(clipId(), clipUrl());
}
// set parent again (some info need to be stored in producer)
......@@ -405,7 +405,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
return nullptr;
}
if (KdenliveSettings::gpu_accel()) {
//TODO: when the original producer changes, we must reload this thumb producer
// TODO: when the original producer changes, we must reload this thumb producer
Clip clip(*prod.get());
m_thumbsProducer = std::make_shared<Mlt::Producer>(clip.softClone(ClipController::getPassPropertiesList()));
Mlt::Filter scaler(*prod->profile(), "swscale");
......@@ -418,6 +418,127 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
return m_thumbsProducer;
}
void ProjectClip::createVideoMasterProducer()
{
if (!m_videoProducer) {
m_videoProducer = cloneProducer(&pCore->getCurrentProfile()->profile());
// disable audio but activate video
m_videoProducer->set("set.test_audio", 1);
m_videoProducer->set("set.test_image", 0);
}
}
std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int clipId, PlaylistState state, double speed)
{
if (qFuzzyCompare(speed, 1.0)) {
// we are requesting a normal speed producer
// We can first cleen the speed producers we have for the current id
m_timewarpProducers.erase(clipId);
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]->set("set.test_audio", 0);
m_audioProducers[clipId]->set("set.test_image", 1);
}
return std::shared_ptr<Mlt::Producer>(m_audioProducers[clipId]->cut());
}
// we return the video producer
m_audioProducers.erase(clipId);
createVideoMasterProducer();
return std::shared_ptr<Mlt::Producer>(m_videoProducer->cut());
}
// in that case, we need to create a warp producer, if we don't have one
m_audioProducers.erase(clipId);
std::shared_ptr<Mlt::Producer> warpProducer;
if (m_timewarpProducers.count(clipId) > 0) {
if (qFuzzyCompare(m_timewarpProducers[clipId]->get_double("warp_speed"), speed)) {
// the producer we have is good, use it !
warpProducer = m_timewarpProducers[clipId];
}
}
if (!warpProducer) {
QString resource = QString("timewarp:%1:%2").arg(speed).arg(originalProducer()->get("resource"));
warpProducer.reset(new Mlt::Producer(*originalProducer()->profile(), resource.toUtf8().constData()));
}
warpProducer->set("set.test_audio", 1);
warpProducer->set("set.test_image", 1);
if (state == PlaylistState::AudioOnly) {
warpProducer->set("set.test_audio", 0);
}
if (state == PlaylistState::VideoOnly) {
warpProducer->set("set.test_image", 0);
}
m_timewarpProducers[clipId] = warpProducer;
return warpProducer;
}
std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master,
PlaylistState state)
{
int in = master->get_in();
int out = master->get_out();
if (master->parent().is_valid()) {
// in that case, we have a cut
// check whether it's a timewarp
double speed = 1.0;
double timeWarp = false;
if (QString::fromUtf8(master->parent().get("mlt_service")) == QLatin1String("timewarp")) {
speed = master->parent().get_double("warp_speed");
timeWarp = true;
}
if (master->parent().get_int("loaded") == 1) {
// we already have a clip that shares the same master
if (state == PlaylistState::AudioOnly || timeWarp) {
// In that case, we must create copies
return {getTimelineProducer(clipId, state, speed), false};
}
// if it's a video or disabled clip, we must make sure that its master clip matches our video master
if (!m_videoProducer) {
qDebug() << "Warning: weird, we found a video clip whose master is already loaded but we don't have any yet";
createVideoMasterProducer();
return {std::shared_ptr<Mlt::Producer>(m_videoProducer->cut(in, out)), false};
}
if (QString::fromUtf8(m_videoProducer->get("id")) != QString::fromUtf8(master->parent().get("id"))) {
qDebug() << "Warning: weird, we found a video clip whose master is already loaded but doesn't match ours";
return {std::shared_ptr<Mlt::Producer>(m_videoProducer->cut(in, out)), false};
}
// We have a good id, this clip can be used
return {master, true};
} else {
master->parent().set("loaded", 1);
if (state == PlaylistState::AudioOnly) {
m_audioProducers[clipId] = std::shared_ptr<Mlt::Producer>(&master->parent());
return {master, true};
}
if (timeWarp) {
m_timewarpProducers[clipId] = std::shared_ptr<Mlt::Producer>(&master->parent());
return {master, true};
}
if (!m_videoProducer) {
// good, we found a master video producer, and we didn't have any
m_videoProducer.reset(&master->parent());
return {master, true};
}
qDebug() << "Warning: weird, we found a video clip whose master is not loaded but we already have a master";
return {std::shared_ptr<Mlt::Producer>(m_videoProducer->cut(in, out)), false};
}
} else if (master->is_valid()) {
// in that case, we have a master
qDebug() << "Warning: weird, we received a master clip in lieue of a cut";
double speed = 1.0;
if (QString::fromUtf8(master->get("mlt_service")) == QLatin1String("timewarp")) {
speed = master->get_double("warp_speed");
}
return {getTimelineProducer(clipId, state, speed), false};
}
// we have a problem
return {std::shared_ptr<Mlt::Producer>(ClipController::mediaUnavailable->cut()), false};
}
/*
std::shared_ptr<Mlt::Producer> ProjectClip::timelineProducer(PlaylistState::ClipState state, int track)
{
if (!m_service.startsWith(QLatin1String("avformat"))) {
......@@ -452,7 +573,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::timelineProducer(PlaylistState::Clip
std::shared_ptr<Mlt::Producer> normalProd = cloneProducer();
m_timelineProducers[track] = normalProd;
return std::shared_ptr<Mlt::Producer>(normalProd->cut());
}
}*/
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer(Mlt::Profile *destProfile)
{
......@@ -554,7 +675,7 @@ const QString ProjectClip::getFileHash()
break;
}
if (fileHash.isEmpty()) {
qDebug()<<"// WARNING EMPTY CLIP HASH: ";
qDebug() << "// WARNING EMPTY CLIP HASH: ";
return QString();
}
QString result = fileHash.toHex();
......@@ -585,7 +706,8 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (properties.contains(QStringLiteral("templatetext"))) {
m_description = properties.value(QStringLiteral("templatetext"));
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::ClipStatus);
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()),
AbstractProjectItem::ClipStatus);
refreshPanel = true;
}
timelineProperties << QStringLiteral("force_aspect_ratio") << QStringLiteral("video_index") << QStringLiteral("audio_index")
......@@ -639,7 +761,8 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (properties.contains(QStringLiteral("length")) || properties.contains(QStringLiteral("kdenlive:duration"))) {
m_duration = getStringDuration();
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataDuration);
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()),
AbstractProjectItem::DataDuration);
refreshOnly = false;
reload = true;
}
......@@ -648,7 +771,8 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
m_name = properties.value(QStringLiteral("kdenlive:clipname"));
refreshPanel = true;
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataName);
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()),
AbstractProjectItem::DataName);
}
// update timeline clips
updateTimelineClips(QVector<int>() << TimelineModel::NameRole);
......@@ -980,6 +1104,8 @@ bool ProjectClip::isIncludedInTimeline()
void ProjectClip::updateChildProducers()
{
// TODO refac: the effect should be managed by an effectstack on the master
/*
// pass effect stack on all child producers
QMutexLocker locker(&m_producerMutex);
for (const auto &clip : m_timelineProducers) {
......@@ -989,6 +1115,7 @@ void ProjectClip::updateChildProducers()
clp.replaceEffects(*m_masterProducer);
}
}
*/
}
void ProjectClip::replaceInTimeline()
......
......@@ -49,7 +49,14 @@ class Properties;
/**
* @class ProjectClip
* @brief Represents a clip in the project (not timeline).
*
* It will be displayed as a bin item that can be dragged onto the timeline.
* A single bin clip can be inserted several times on the timeline, and the ProjectClip
* keeps track of all the ids of the corresponding ClipModel.
* Note that because of a limitation in melt and AvFilter, it is currently difficult to
* mix the audio of two producers that are cut from the same master producer
* (that produces small but noticeable clicking artifacts)
* To workaround this, we need to have a master clip for each instance of the audio clip in the timeline. This class is tracking them all. This track also holds
* a master clip for each clip where the timewarp producer has been applied
*/
class ProjectClip : public AbstractProjectItem, public ClipController
......@@ -140,7 +147,7 @@ public:
bool isReady() const;
/** @brief Returns this clip's producer. */
std::shared_ptr< Mlt::Producer > thumbProducer();
std::shared_ptr<Mlt::Producer> thumbProducer();
/** @brief Recursively disable/enable bin effects. */
void setBinEffectsEnabled(bool enabled) override;
......@@ -188,7 +195,19 @@ public:
bool isIncludedInTimeline() override;
/** @brief Returns a list of all timeline clip ids for this bin clip */
QList<int> timelineInstances() const;
std::shared_ptr<Mlt::Producer> timelineProducer(PlaylistState::ClipState state = PlaylistState::Original, int track = 1);
/** @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 clipId, PlaylistState st, double speed = 1.0);
/* @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
bool returned has the following sementic:
- if true, then the returned cut still possibly has effect on it. You need to rebuild the effectStack based on this
- if false, the the returned cut don't have effects anymore (it's a fresh one), so you need to reload effects from the old producer
*/
std::pair<std::shared_ptr<Mlt::Producer>, bool> giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master, PlaylistState state);
std::shared_ptr<Mlt::Producer> cloneProducer(Mlt::Profile *destProfile = nullptr);
void updateTimelineClips(QVector<int> roles);
......@@ -234,8 +253,16 @@ private:
const QString geometryWithOffset(const QString &data, int offset);
void doExtractImage();
// This is a helper function that creates the video producer. This is a clone of the original one, with audio disabled
void createVideoMasterProducer();
std::map<int, std::weak_ptr<TimelineModel>> m_registeredClips;
std::map<int, std::shared_ptr<Mlt::Producer>> m_timelineProducers;
// the following holds a producer for each audio clip in the timeline
// keys are the id of the clips in the timeline, values are their values
std::unordered_map<int, std::shared_ptr<Mlt::Producer>> m_audioProducers;
std::unordered_map<int, std::shared_ptr<Mlt::Producer>> m_timewarpProducers;
std::shared_ptr<Mlt::Producer> m_videoProducer;
signals:
void producerChanged(const QString &, const std::shared_ptr<Mlt::Producer> &);
......
......@@ -158,3 +158,19 @@ GroupType groupTypeFromStr(const QString &s)
Q_ASSERT(false);
return GroupType::Normal;
}
std::pair<bool, bool> stateToBool(PlaylistState state)
{
return {state == PlaylistState::VideoOnly, state == PlaylistState::AudioOnly};
}
PlaylistState stateFromBool(std::pair<bool, bool> av)
{
assert(!av.first || !av.second);
if (av.first) {
return PlaylistState::VideoOnly;
} else if (av.second) {
return PlaylistState::AudioOnly;
} else {
return PlaylistState::Disabled;
}
}
......@@ -77,10 +77,12 @@ enum OperationType {
ZoomTimeline
};
namespace PlaylistState {
enum class PlaylistState { VideoOnly = 1, AudioOnly = 2, Disabled = 3 };
Q_DECLARE_METATYPE(PlaylistState)
enum ClipState { Original = 0, VideoOnly = 1, AudioOnly = 2, Disabled = 3 };
}
// returns a pair corresponding to (video, audio)
std::pair<bool, bool> stateToBool(PlaylistState state);
PlaylistState stateFromBool(std::pair<bool, bool> av);
namespace TimelineMode {
enum EditMode { NormalEdit = 0, OverwriteEdit = 1, InsertEdit = 2 };
......
......@@ -48,36 +48,6 @@ std::shared_ptr<EffectStackModel> EffectStackModel::construct(std::weak_ptr<Mlt:
return self;
}
void EffectStackModel::loadEffects()
{
auto ptr = m_service.lock();
m_loadingExisting = true;
if (ptr) {
for (int i = 0; i < ptr->filter_count(); i++) {
if (ptr->filter(i)->get("kdenlive_id") == nullptr) {
// don't consider internal MLT stuff
continue;
}
QString effectId = ptr->filter(i)->get("kdenlive_id");
auto effect = EffectItemModel::construct(ptr->filter(i), shared_from_this());
// effect->setParameters
Fun redo = addItem_lambda(effect, rootItem->getId());
redo();
if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")) {
fadeIns << effect->getId();
} else if (effectId == QLatin1String("fadeout") || effectId == QLatin1String("fade_to_black")) {
fadeOuts << effect->getId();
}
connect(effect.get(), &AssetParameterModel::modelChanged, this, &EffectStackModel::modelChanged);
connect(effect.get(), &AssetParameterModel::replugEffect, this, &EffectStackModel::replugEffect, Qt::DirectConnection);
}
} else {
qDebug() << "// CANNOT LOCK CLIP SEEVCE";
}
this->modelChanged();
m_loadingExisting = false;
}
void EffectStackModel::resetService(std::weak_ptr<Mlt::Service> service)
{
m_service = std::move(service);
......@@ -112,8 +82,8 @@ void EffectStackModel::removeEffect(std::shared_ptr<EffectItemModel> effect)
if (res) {
int inFades = fadeIns.size();
int outFades = fadeOuts.size();
fadeIns.removeAll(effect->getId());
fadeOuts.removeAll(effect->getId());
fadeIns.erase(effect->getId());
fadeOuts.erase(effect->getId());
inFades = fadeIns.size() - inFades;
outFades = fadeOuts.size() - outFades;
QString effectName = EffectsRepository::get()->getName(effect->getAssetId());
......@@ -129,11 +99,10 @@ void EffectStackModel::removeEffect(std::shared_ptr<EffectItemModel> effect)
emit dataChanged(ix, ix, QVector<int>());
}
}
//TODO: only update if effect is fade or keyframe
// TODO: only update if effect is fade or keyframe
if (inFades < 0) {
pCore->updateItemModel(m_ownerId, QStringLiteral("fadein"));
}
else if (outFades < 0) {
} else if (outFades < 0) {
pCore->updateItemModel(m_ownerId, QStringLiteral("fadeout"));
}
pCore->updateItemKeyframes(m_ownerId);
......@@ -146,23 +115,30 @@ void EffectStackModel::removeEffect(std::shared_ptr<EffectItemModel> effect)
}
}
void EffectStackModel::copyEffect(std::shared_ptr<AbstractEffectItem> sourceItem)
void EffectStackModel::copyEffect(std::shared_ptr<AbstractEffectItem> sourceItem, bool logUndo)
{
if (sourceItem->childCount() > 0) {
// TODO: group
return;
}
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(sourceItem);
QString effectId = sourceEffect->getAssetId();
const QString effectId = sourceEffect->getAssetId();
auto effect = EffectItemModel::construct(effectId, shared_from_this());
effect->setParameters(sourceEffect->getAllParameters());
effect->filter().set("in", sourceEffect->filter().get_int("in"));
effect->filter().set("out", sourceEffect->filter().get_int("out"));
Fun undo = removeItem_lambda(effect->getId());
// TODO the parent should probably not always be the root
Fun redo = addItem_lambda(effect, rootItem->getId());
connect(effect.get(), &AssetParameterModel::modelChanged, this, &EffectStackModel::modelChanged);
connect(effect.get(), &AssetParameterModel::replugEffect, this, &EffectStackModel::replugEffect, Qt::DirectConnection);
if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")) {
fadeIns.insert(effect->getId());
} else if (effectId == QLatin1String("fadeout") || effectId == QLatin1String("fade_to_black")) {
fadeOuts.insert(effect->getId());
}
bool res = redo();
if (res) {
if (res && logUndo) {
QString effectName = EffectsRepository::get()->getName(effectId);
PUSH_UNDO(undo, redo, i18n("copy effect %1", effectName));
}
......@@ -188,19 +164,18 @@ void EffectStackModel::appendEffect(const QString &effectId, bool makeCurrent)
int inFades = 0;
int outFades = 0;
if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")) {
fadeIns << effect->getId();
fadeIns.insert(effect->getId());
inFades++;
} else if (effectId == QLatin1String("fadeout") || effectId == QLatin1String("fade_to_black")) {
fadeOuts << effect->getId();
outFades ++;
fadeOuts.insert(effect->getId());
outFades++;
}
QString effectName = EffectsRepository::get()->getName(effectId);
Fun update = [this, inFades, outFades]() {
//TODO: only update if effect is fade or keyframe
// TODO: only update if effect is fade or keyframe
if (inFades > 0) {
pCore->updateItemModel(m_ownerId, QStringLiteral("fadein"));
}
else if (outFades > 0) {
} else if (outFades > 0) {
pCore->updateItemModel(m_ownerId, QStringLiteral("fadeout"));
}
pCore->updateItemKeyframes(m_ownerId);
......@@ -227,11 +202,11 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
auto ptr = m_service.lock();
int out = newIn + duration;
for (int i = 0; i < rootItem->childCount(); ++i) {
if (fadeInDuration > 0 && fadeIns.contains(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId())) {
if (fadeInDuration > 0 && 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));
int oldEffectIn = qMax(0, effect->filter().get_in());
int oldEffectOut = effect->filter().get_out();
qDebug()<<"--previous effect: "<<oldEffectIn<<"-"<<oldEffectOut;
qDebug() << "--previous effect: " << oldEffectIn << "-" << oldEffectOut;
int effectDuration = qMin(effect->filter().get_length() - 1, duration);
indexes << getIndexFromItem(effect);
if (!adjustFromEnd && (oldIn != newIn || duration != oldDuration)) {
......@@ -239,7 +214,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
Fun operation = [this, effect, newIn, effectDuration, logUndo]() {
effect->setParameter(QStringLiteral("in"), newIn, false);
effect->setParameter(QStringLiteral("out"), newIn + effectDuration, logUndo);
qDebug()<<"--new effect: "<<newIn<<"-"<<newIn + effectDuration;
qDebug() << "--new effect: " << newIn << "-" << newIn + effectDuration;
return true;
};
operation();
......@@ -264,14 +239,14 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
if (operation() && logUndo) {
Fun reverse = [this, effect, referenceEffectOut]() {
effect->setParameter(QStringLiteral("out"), referenceEffectOut, true);
effect->filter().set("_refout", (char*) nullptr);
effect->filter().set("_refout", (char *)nullptr);
return true;
};
PUSH_LAMBDA(operation, redo);
PUSH_LAMBDA(reverse, undo);
}
}
} else if (fadeOutDuration > 0 && fadeOuts.contains(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId())) {
} else if (fadeOutDuration > 0 && 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));
int effectDuration = qMin(fadeOutDuration, duration);
int newFadeIn = out - effectDuration;
......@@ -291,7 +266,7 @@ bool EffectStackModel::adjustStackLength(bool adjustFromEnd, int oldIn, int oldD
Fun reverse = [this, effect, referenceEffectIn, oldOut]() {
effect->setParameter(QStringLiteral("in"), referenceEffectIn, false);
effect->setParameter(QStringLiteral("out"), oldOut, true);
effect->filter().set("_refin", (char*) nullptr);
effect->filter().set("_refin", (char *)nullptr);
return true;
};
PUSH_LAMBDA(operation, redo);
......@@ -322,7 +297,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
{
if (fromStart) {
// Fade in
if (fadeIns.isEmpty()) {
if (fadeIns.empty()) {
if (audioFade) {
appendEffect(QStringLiteral("fadein"));
}
......@@ -336,9 +311,9 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
if (ptr) {
in = ptr->get_int("in");
}
qDebug()<<"//// SETTING CLIP FADIN: "<<duration;
qDebug() << "//// SETTING CLIP FADIN: " << duration;
for (int i = 0; i < rootItem->childCount(); ++i) {
if (fadeIns.contains(std::static_pointer_cast<TreeItem>(rootItem->child(i))->getId())) {
if (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));
effect->filter().set("in", in);
duration = qMin(pCore->getItemDuration(m_ownerId), duration);
......@@ -352,7 +327,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
}
} else {
// Fade out
if (fadeOuts.isEmpty()) {
if (fadeOuts.empty()) {
if (audioFade) {
appendEffect(QStringLiteral("fadeout"));
}
......@@ -368,7 +343,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
int out = in + pCore->getItemDurat