Commit 3f6b18b3 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix same track transition if one clip has no frame at its end

parent 3edca1b2
Pipeline #89844 passed with stage
in 8 minutes and 45 seconds
......@@ -842,9 +842,12 @@ bool TimelineModel::mixClip(int idToMove, int delta)
return false;
}
std::pair<int, int> clipsToMix;
std::pair<int, int> mixDurations;
int mixPosition = 0;
int previousClip = -1;
int noSpaceInClip = 0;
int leftMax = 0;
int rightMax = 0;
if (idToMove != -1) {
initialSelection = {idToMove};
idToMove = -1;
......@@ -897,8 +900,11 @@ bool TimelineModel::mixClip(int idToMove, int delta)
continue;
}
// Make sure we have enough space in clip to resize
int maxLength = m_allClips[previousClip]->getMaxDuration();
if ((m_allClips[s]->getMaxDuration() > -1 && m_allClips[s]->getIn() < 2) || (maxLength > -1 && m_allClips[previousClip]->getOut() + 2 >= maxLength)) {
int maxLengthLeft = m_allClips[previousClip]->getMaxDuration();
int maxLengthRight = m_allClips[s]->getMaxDuration();
leftMax = maxLengthLeft > -1 ? (maxLengthLeft - 1 - m_allClips[previousClip]->getOut()) : -1;
rightMax = maxLengthRight > -1 ? (m_allClips[s]->getIn()) : -1;
if (leftMax > -1 && rightMax > -1 && (leftMax + rightMax < 3)) {
noSpaceInClip = 1;
continue;
}
......@@ -910,8 +916,11 @@ bool TimelineModel::mixClip(int idToMove, int delta)
} else {
// Mix at end of selected clip
// Make sure we have enough space in clip to resize
int maxLength = m_allClips[s]->getMaxDuration();
if ((m_allClips[nextClip]->getMaxDuration() > -1 && m_allClips[nextClip]->getIn() < 2) || (maxLength > -1 && m_allClips[s]->getOut() + 2 >= maxLength)) {
int maxLengthLeft = m_allClips[s]->getMaxDuration();
int maxLengthRight = m_allClips[nextClip]->getMaxDuration();
leftMax = maxLengthLeft > -1 ? (maxLengthLeft - 1 - m_allClips[s]->getOut()) : -1;
rightMax = maxLengthRight > -1 ? (m_allClips[nextClip]->getIn()) : -1;
if (leftMax > -1 && rightMax > -1 && (leftMax + rightMax < 3)) {
noSpaceInClip = 2;
continue;
}
......@@ -933,7 +942,34 @@ bool TimelineModel::mixClip(int idToMove, int delta)
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
bool result = requestClipMix(clipsToMix, selectedTrack, mixPosition, true, true, true, undo,
int mixDuration = pCore->getDurationFromString(KdenliveSettings::mix_duration());
if (leftMax > -1) {
if (rightMax > -1) {
// Both clips have limited durations
mixDurations.first = qMin(mixDuration / 2, leftMax);
mixDurations.second = qMin(mixDuration - mixDuration / 2, rightMax);
int offset = mixDuration - (mixDurations.first + mixDurations.second);
if (offset > 0) {
if (leftMax > mixDurations.first) {
mixDurations.first = qMin(leftMax, mixDurations.first + offset);
} else if (rightMax > mixDurations.second) {
mixDurations.second = qMin(rightMax, mixDurations.second + offset);
}
}
} else {
mixDurations.first = qMin(mixDuration - mixDuration / 2, leftMax);
mixDurations.second = mixDuration - mixDurations.second;
}
} else {
if (rightMax > -1) {
mixDurations.second = qMin(mixDuration - mixDuration / 2, rightMax);
mixDurations.first= mixDuration - mixDurations.first;
} else {
mixDurations.first = mixDuration / 2;
mixDurations.second = mixDuration - mixDurations.first;
}
}
bool result = requestClipMix(clipsToMix, mixDurations, selectedTrack, mixPosition, true, true, true, undo,
redo, false);
if (result) {
// Check if this is an AV split group
......@@ -958,7 +994,7 @@ bool TimelineModel::mixClip(int idToMove, int delta)
clipsToMix.second = current_id;
}
if (splitId > -1 && clipsToMix.first != clipsToMix.second) {
result = requestClipMix(clipsToMix, splitTrack, mixPosition, true, true, true, undo, redo, false);
result = requestClipMix(clipsToMix, mixDurations, splitTrack, mixPosition, true, true, true, undo, redo, false);
}
}
}
......@@ -979,7 +1015,7 @@ bool TimelineModel::mixClip(int idToMove, int delta)
}
}
bool TimelineModel::requestClipMix(std::pair<int, int> clipIds, int trackId, int position, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove)
bool TimelineModel::requestClipMix(std::pair<int, int> clipIds, std::pair<int, int> mixDurations, int trackId, int position, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove)
{
if (trackId == -1) {
return false;
......@@ -993,21 +1029,20 @@ bool TimelineModel::requestClipMix(std::pair<int, int> clipIds, int trackId, int
// Move on same track, simply inform the view
updateView = false;
notifyViewOnly = true;
int mixDuration = pCore->getDurationFromString(KdenliveSettings::mix_duration());
update_model = [clipIds, this, trackId, position, invalidateTimeline, mixDuration]() {
update_model = [clipIds, this, trackId, position, invalidateTimeline, mixDurations]() {
QModelIndex modelIndex = makeClipIndexFromID(clipIds.second);
notifyChange(modelIndex, modelIndex, {StartRole,DurationRole});
QModelIndex modelIndex2 = makeClipIndexFromID(clipIds.first);
notifyChange(modelIndex2, modelIndex2, DurationRole);
if (invalidateTimeline && !getTrackById_const(trackId)->isAudioTrack()) {
emit invalidateZone(position - mixDuration / 2, position + mixDuration);
emit invalidateZone(position - mixDurations.second, position + mixDurations.first);
}
return true;
};
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_undo);
}
ok = getTrackById(trackId)->requestClipMix(clipIds, mixDuration, updateView, finalMove, local_undo, local_redo, groupMove);
ok = getTrackById(trackId)->requestClipMix(clipIds, mixDurations, updateView, finalMove, local_undo, local_redo, groupMove);
if (!ok) {
qWarning() << "mix failed, reverting";
bool undone = local_undo();
......
......@@ -359,7 +359,7 @@ public:
Q_INVOKABLE bool requestSubtitleMove(int clipId, int position, bool updateView = true, bool logUndo = true, bool invalidateTimeline = false);
bool requestSubtitleMove(int clipId, int position, bool updateView, bool first, bool last, bool invalidateTimeline, Fun &undo, Fun &redo);
bool cutSubtitle(int position, Fun &undo, Fun &redo);
bool requestClipMix(std::pair<int, int> clipIds, int trackId, int position, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove);
bool requestClipMix(std::pair<int, int> clipIds, std::pair<int, int> mixDurations, int trackId, int position, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove);
/** @brief Move a composition to a specific position This action is undoable
Returns true on success. If it fails, nothing is modified. If the clip is
......
......@@ -1678,7 +1678,7 @@ bool TrackModel::requestRemoveMix(std::pair<int, int> clipIds, Fun &undo, Fun &r
return false;
}
bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove)
bool TrackModel::requestClipMix(std::pair<int, int> clipIds, std::pair<int, int> mixDurations, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove)
{
QWriteLocker locker(&m_lock);
// By default, insertion occurs in topmost track
......@@ -1696,17 +1696,6 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (auto ptr = m_parent.lock()) {
// The clip that will be moved to playlist 1
std::shared_ptr<ClipModel> secondClip(ptr->getClipPtr(clipIds.second));
if (secondClip->getMaxDuration() > -1) {
// check if we have enough frames, or limit duration
int leftFrames = secondClip->getIn();
if (leftFrames < 3) {
pCore->displayMessage(i18n("Not enough frames at clip %1 to apply the mix", i18n("start")), ErrorMessage, 500);
return false;
}
if (leftFrames < mixDuration / 2) {
mixDuration = 2 * leftFrames;
}
}
secondClipDuration = secondClip->getPlaytime();
secondClipPos = secondClip->getPosition();
source_track = secondClip->getSubPlaylistIndex();
......@@ -1717,8 +1706,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (firstClip->getSubPlaylistIndex() == 1) {
dest_track = 0;
}
mixPosition = qMax(firstClipPos, secondClipPos - mixDuration / 2);
int maxPos = qMin(secondClipPos + secondClipDuration, secondClipPos + mixDuration - (mixDuration / 2));
mixPosition = qMax(firstClipPos, secondClipPos - mixDurations.second);
int maxPos = qMin(secondClipPos + secondClipDuration, secondClipPos + mixDurations.first);
if (hasStartMix(clipIds.first)) {
std::pair<MixInfo, MixInfo> mixData = getMixInfo(clipIds.first);
mixPosition = qMax(mixData.first.firstClipInOut.second, mixPosition);
......@@ -1731,7 +1720,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
remixPlaylists = true;
}
}
mixDuration = qMin(mixDuration, maxPos - mixPosition);
mixDurations.first = qMin(mixDurations.first, maxPos - mixPosition);
secondClipCut = maxPos - secondClipPos;
} else {
// Error, timeline unavailable
......@@ -1884,16 +1873,16 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
};
}
// Create mix compositing
Fun build_mix = [clipIds, mixPosition, mixDuration, dest_track, secondClipCut, this]() {
Fun build_mix = [clipIds, mixPosition, mixDurations, dest_track, secondClipCut, this]() {
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> movedClip(ptr->getClipPtr(clipIds.second));
movedClip->setMixDuration(mixDuration, secondClipCut);
movedClip->setMixDuration(mixDurations.first + mixDurations.second, secondClipCut);
// Insert mix transition
QString assetName;
std::unique_ptr<Mlt::Transition>t;
if (isAudioTrack()) {
t = std::make_unique<Mlt::Transition>(*ptr->getProfile(), "mix");
t->set_in_and_out(mixPosition, mixPosition + mixDuration);
t->set_in_and_out(mixPosition, mixPosition + mixDurations.first + mixDurations.second);
t->set("kdenlive:mixcut", secondClipCut);
t->set("start", -1);
t->set("accepts_blanks", 1);
......@@ -1901,7 +1890,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
assetName = QStringLiteral("mix");
} else {
t = std::make_unique<Mlt::Transition>(*ptr->getProfile(), "luma");
t->set_in_and_out(mixPosition, mixPosition + mixDuration);
t->set_in_and_out(mixPosition, mixPosition + mixDurations.first + mixDurations.second);
t->set("kdenlive:mixcut", secondClipCut);
t->set("kdenlive_id", "luma");
m_track->plant_transition(*t.get(), 0, 1);
......@@ -1941,7 +1930,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
auto operation = requestClipDeletion_lambda(clipIds.second, updateView, finalMove, groupMove, false);
bool res = operation();
if (res) {
Fun replay = [this, clipIds, dest_track, firstClipPos, secondClipDuration, mixPosition, mixDuration, build_mix, secondClipPos, clipHasEndMix, updateView, finalMove, groupMove, rearrange_playlists]() {
Fun replay = [this, clipIds, dest_track, firstClipPos, secondClipDuration, mixPosition, mixDurations, build_mix, secondClipPos, clipHasEndMix, updateView, finalMove, groupMove, rearrange_playlists]() {
if (auto ptr = m_parent.lock()) {
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(dest_track, m_id);
}
......@@ -1954,7 +1943,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std::function<bool(void)> local_redo = []() { return true; };
if (auto ptr = m_parent.lock()) {
result = ptr->getClipPtr(clipIds.second)->requestResize(secondClipPos + secondClipDuration - mixPosition, false, local_undo, local_redo, true, clipHasEndMix);
result = result && ptr->getClipPtr(clipIds.first)->requestResize(mixPosition + mixDuration - firstClipPos, true, local_undo, local_redo, true, true);
result = result && ptr->getClipPtr(clipIds.first)->requestResize(mixPosition + mixDurations.first + mixDurations.second - firstClipPos, true, local_undo, local_redo, true, true);
QModelIndex ix = ptr->makeClipIndexFromID(clipIds.second);
emit ptr->dataChanged(ix, ix, {TimelineModel::StartRole,TimelineModel::MixRole,TimelineModel::MixCutRole});
}
......
......@@ -110,7 +110,7 @@ public:
/** @brief Remove a composition between 2 same track clips */
bool requestRemoveMix(std::pair<int, int> clipIds, Fun &undo, Fun &redo);
/** @brief Create a composition between 2 same track clips */
bool requestClipMix(std::pair<int, int> clipIds, int mixDuration, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove);
bool requestClipMix(std::pair<int, int> clipIds, std::pair<int, int> mixDurations, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove);
/** @brief Get clip ids and in/out position for mixes in this clip */
std::pair<MixInfo, MixInfo> getMixInfo(int cid) const;
/** @brief Delete a mix composition */
......
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