Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Switch to previous behavior for producers (store audio only / video only producers in project clip)

parent acb6c14c
......@@ -148,12 +148,17 @@ ProjectClip::~ProjectClip()
m_thumbThread.waitForFinished();
delete m_thumbsProducer;
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()
{
connect(m_effectStack.get(), &EffectStackModel::dataChanged, [&](QModelIndex,QModelIndex,QVector<int>){
replaceInTimeline();
updateChildProducers();
});
}
......@@ -403,7 +408,38 @@ Mlt::Producer *ProjectClip::thumbProducer()
return m_thumbsProducer;
}
Mlt::Producer *ProjectClip::cloneProducer()
std::shared_ptr<Mlt::Producer> ProjectClip::timelineProducer(PlaylistState::ClipState state, int track)
{
if (!m_service.startsWith(QLatin1String("avformat"))) {
return originalProducer();
}
if (state == PlaylistState::VideoOnly) {
if (m_timelineProducers.count(0) > 0) {
return m_timelineProducers.find(0)->second;
}
std::shared_ptr<Mlt::Producer> videoProd = cloneProducer();
videoProd->set("audio_index", -1);
m_timelineProducers[0] = videoProd;
return videoProd;
}
if (state == PlaylistState::AudioOnly) {
if (m_timelineProducers.count(-track) > 0) {
return m_timelineProducers.find(-track)->second;
}
std::shared_ptr<Mlt::Producer> audioProd = cloneProducer();
audioProd->set("video_index", -1);
m_timelineProducers[-track] = audioProd;
return audioProd;
}
if (m_timelineProducers.count(track) > 0) {
return m_timelineProducers.find(track)->second;
}
std::shared_ptr<Mlt::Producer> normalProd = cloneProducer();
m_timelineProducers[track] = normalProd;
return normalProd;
}
std::shared_ptr<Mlt::Producer> ProjectClip::cloneProducer()
{
Mlt::Consumer c(*m_masterProducer->profile(), "xml", "string");
Mlt::Service s(m_masterProducer->get_service());
......@@ -423,10 +459,8 @@ Mlt::Producer *ProjectClip::cloneProducer()
s.set("ignore_points", ignore);
}
const QByteArray clipXml = c.get("string");
QScopedPointer<Mlt::Producer> master(new Mlt::Producer(*m_masterProducer->profile(), "xml-string", clipXml.constData()));
Mlt::Producer *clone = master->cut();
clone->set("kdenlive:id", m_binId.toUtf8().constData());
return clone;
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(*m_masterProducer->profile(), "xml-string", clipXml.constData()));
return prod;
}
bool ProjectClip::isReady() const
......@@ -1307,6 +1341,16 @@ bool ProjectClip::isIncludedInTimeline()
return m_registeredClips.size() > 0;
}
void ProjectClip::updateChildProducers()
{
// pass effect stack on all child producers
for (const auto &clip : m_timelineProducers) {
if (auto producer = clip.second) {
Clip(*producer.get()).replaceEffects(*m_masterProducer);
}
}
}
void ProjectClip::replaceInTimeline()
{
for (const auto &clip : m_registeredClips) {
......
......@@ -195,7 +195,8 @@ public:
bool isIncludedInTimeline() override;
/** @brief Returns a list of all timeline clip ids for this bin clip */
QList <int> timelineInstances() const;
Mlt::Producer *cloneProducer();
std::shared_ptr<Mlt::Producer> timelineProducer(PlaylistState::ClipState state = PlaylistState::Original, int track = 1);
std::shared_ptr<Mlt::Producer> cloneProducer();
protected:
friend class ClipModel;
......@@ -212,6 +213,7 @@ protected:
void emitProducerChanged(const QString& id, const std::shared_ptr<Mlt::Producer> &producer) override {emit producerChanged(id, producer);};
/** @brief Replace instance of this clip in timeline */
void updateChildProducers();
void replaceInTimeline();
void connectEffectStack();
......@@ -248,6 +250,7 @@ private:
void updateTimelineClips(QVector<int> roles);
std::map<int, std::weak_ptr<TimelineModel>> m_registeredClips;
std::map<int, std::shared_ptr<Mlt::Producer>> m_timelineProducers;
private slots:
void updateFfmpegProgress();
......
......@@ -56,7 +56,7 @@ int ClipModel::construct(const std::shared_ptr<TimelineModel> &parent, const QSt
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(binClipId);
//std::shared_ptr<Mlt::Producer> originalProducer = binClip->originalProducer();
//std::shared_ptr<Mlt::Producer> cutProducer(originalProducer->cut());
std::shared_ptr<Mlt::Producer> cutProducer(binClip->cloneProducer());
std::shared_ptr<Mlt::Producer> cutProducer = binClip->timelineProducer();
return construct(parent, binClipId, cutProducer, id);
}
......@@ -276,8 +276,8 @@ void ClipModel::refreshProducerFromBin()
int in = getIn();
int out = getOut();
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(m_binClipId);
std::shared_ptr<Mlt::Producer> originalProducer = binClip->originalProducer();
m_producer.reset(originalProducer->cut(in, out));
std::shared_ptr<Mlt::Producer> binProducer = binClip->timelineProducer(PlaylistState::Original, m_currentTrackId);
m_producer.reset(binProducer->cut(in, out));
// replant effect stack in updated service
m_effectStack->resetService(m_producer);
m_producer->set("kdenlive:id", binClip->AbstractProjectItem::clipId().toUtf8().constData());
......@@ -388,38 +388,25 @@ bool ClipModel::setClipState(PlaylistState::ClipState state)
if (!getProperty("mlt_service").startsWith(QStringLiteral("avformat"))) {
return false;
}
switch (state) {
case PlaylistState::Original:
m_producer->parent().set("audio_index", 0);
m_producer->parent().set("video_index", 0);
break;
case PlaylistState::AudioOnly:
m_producer->parent().set("video_index", -1);
m_producer->parent().set("audio_index", 0);
break;
case PlaylistState::VideoOnly:
m_producer->parent().set("audio_index", -1);
m_producer->parent().set("video_index", 0);
break;
case PlaylistState::Disabled:
m_producer->parent().set("audio_index", -1);
m_producer->parent().set("video_index", -1);
break;
default:
break;
}
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(m_binClipId);
std::shared_ptr<Mlt::Producer> binProducer = binClip->timelineProducer(state, m_currentTrackId);
int in = getIn();
int out = getOut();
m_producer.reset(binProducer->cut(in, out));
// replant effect stack in updated service
m_effectStack->resetService(m_producer);
return true;
}
PlaylistState::ClipState ClipModel::clipState() const
{
if (m_producer->parent().get_int("audio_index") == -1) {
if (m_producer->parent().get_int("video_index") == -1) {
if (service()->parent().get_int("audio_index") == -1) {
if (service()->parent().get_int("video_index") == -1) {
return PlaylistState::Disabled;
} else {
return PlaylistState::VideoOnly;
}
} else if (m_producer->parent().get_int("video_index") == -1) {
} else if (service()->parent().get_int("video_index") == -1) {
return PlaylistState::AudioOnly;
}
return PlaylistState::Original;
......
......@@ -315,22 +315,35 @@ bool TimelineFunctions::changeClipState(std::shared_ptr<TimelineItemModel> timel
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
redo = [timeline, clipId, status]() {
int trackId = timeline->getClipTrackId(clipId);
bool res = timeline->m_allClips[clipId]->setClipState(status);
// in order to make the producer change effective, we need to unplant / replant the clip in int track
int start = timeline->getItemPosition(clipId);
int end = start + timeline->getItemPlaytime(clipId);
if (trackId != -1) {
timeline->getTrackById(trackId)->replugClip(clipId);
}
QModelIndex ix = timeline->makeClipIndexFromID(clipId);
timeline->dataChanged(ix, ix, {TimelineModel::StatusRole});
timeline->invalidateClip(clipId);
int start = timeline->getItemPosition(clipId);
int end = start + timeline->getItemPlaytime(clipId);
timeline->checkRefresh(start, end);
return res;
};
undo = [timeline, clipId, oldState]() {
bool res = timeline->m_allClips[clipId]->setClipState(oldState);
// in order to make the producer change effective, we need to unplant / replant the clip in int track
int start = timeline->getItemPosition(clipId);
int end = start + timeline->getItemPlaytime(clipId);
int trackId = timeline->getClipTrackId(clipId);
std::function<bool(void)> local_undo = []() { return true; };
std::function<bool(void)> local_redo = []() { return true; };
if (trackId != -1) {
timeline->getTrackById(trackId)->requestClipDeletion(clipId, false, false, local_undo, local_redo);
timeline->getTrackById(trackId)->requestClipInsertion(clipId, start, true, true, local_undo, local_redo);
}
QModelIndex ix = timeline->makeClipIndexFromID(clipId);
timeline->dataChanged(ix, ix, {TimelineModel::StatusRole});
timeline->invalidateClip(clipId);
int start = timeline->getItemPosition(clipId);
int end = start + timeline->getItemPlaytime(clipId);
timeline->checkRefresh(start, end);
return res;
};
......
......@@ -1784,6 +1784,14 @@ void TimelineModel::requestClipReload(int clipId)
}
}
void TimelineModel::replugClip(int clipId)
{
int old_trackId = getClipTrackId(clipId);
if (old_trackId != -1) {
getTrackById(old_trackId)->replugClip(clipId);
}
}
void TimelineModel::requestClipUpdate(int clipId, QVector<int> roles)
{
QModelIndex modelIndex = makeClipIndexFromID(clipId);
......
......@@ -497,6 +497,7 @@ public:
/** @brief Add slowmotion effect to clip in timeline. */
bool requestClipTimeWarp(int clipId, double speed);
bool changeItemSpeed(int clipId, int speed);
void replugClip(int clipId);
protected:
/* @brief Register a new track. This is a call-back meant to be called from TrackModel
......
......@@ -208,6 +208,26 @@ bool TrackModel::requestClipInsertion(int clipId, int position, bool updateView,
return false;
}
void TrackModel::replugClip(int clipId)
{
int clip_position = m_allClips[clipId]->getPosition();
qDebug()<<"--------------replugging clp";
auto clip_loc = getClipIndexAt(clip_position);
int target_track = clip_loc.first;
int target_clip = clip_loc.second;
// lock MLT playlist so that we don't end up with invalid frames in monitor
m_playlists[target_track].lock();
Q_ASSERT(target_clip < m_playlists[target_track].count());
Q_ASSERT(!m_playlists[target_track].is_blank(target_clip));
auto prod = m_playlists[target_track].replace_with_blank(target_clip);
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(clipId);
int index = m_playlists[target_track].insert_at(clip_position, *clip, 1);
}
delete prod;
m_playlists[target_track].unlock();
}
Fun TrackModel::requestClipDeletion_lambda(int clipId, bool updateView, bool finalMove)
{
QWriteLocker locker(&m_lock);
......
......@@ -193,8 +193,10 @@ protected:
/* @brief Returns the composition id on this track starting position requested, or -1 if not found */
int getCompositionByPosition(int position);
/* @brief Add a track effect */
bool addEffect(const QString &effectId);
void replugClip(int clipId);
public slots:
/*Delete the current track and all its associated clips */
void slotDelete();
......
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