Commit b3552c98 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 761b20a9
......@@ -835,9 +835,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;
......@@ -890,8 +893,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;
}
......@@ -903,8 +909,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;
}
......@@ -926,7 +935,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
......@@ -951,7 +987,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);
}
}
}
......@@ -972,7 +1008,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;
......@@ -986,21 +1022,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();
......
......@@ -375,7 +375,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
......
......@@ -1662,7 +1662,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
......@@ -1680,17 +1680,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();
......@@ -1701,8 +1690,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);
......@@ -1715,7 +1704,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
......@@ -1868,16 +1857,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);
......@@ -1885,7 +1874,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);
......@@ -1925,7 +1914,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);
}
......@@ -1938,7 +1927,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});
}
......
......@@ -126,7 +126,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