Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Multimedia
Kdenlive
Commits
03cf9745
Commit
03cf9745
authored
Aug 28, 2020
by
Jean-Baptiste Mardelle
Browse files
Same track mix update: resize both clips and create a mix in between
parent
761393e4
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/timeline2/model/timelinemodel.cpp
View file @
03cf9745
...
...
@@ -668,13 +668,13 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
}
bool
TimelineModel
::
requestClipMix
Move
(
int
clipId
,
int
trackId
,
int
position
,
bool
updateView
,
bool
invalidateTimeline
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
)
bool
TimelineModel
::
requestClipMix
(
std
::
pair
<
int
,
int
>
clipId
s
,
int
trackId
,
int
position
,
bool
updateView
,
bool
invalidateTimeline
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
)
{
// qDebug() << "// FINAL MOVE: " << invalidateTimeline << ", UPDATE VIEW: " << updateView<<", FINAL: "<<finalMove;
if
(
trackId
==
-
1
)
{
return
false
;
}
Q_ASSERT
(
isClip
(
clipId
));
Q_ASSERT
(
isClip
(
clipId
s
.
first
));
std
::
function
<
bool
(
void
)
>
local_undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
local_redo
=
[]()
{
return
true
;
};
bool
ok
=
true
;
...
...
@@ -683,20 +683,22 @@ bool TimelineModel::requestClipMixMove(int clipId, int trackId, int position, bo
// Move on same track, simply inform the view
updateView
=
false
;
notifyViewOnly
=
true
;
update_model
=
[
clipId
,
this
,
trackId
,
invalidateTimeline
]()
{
int
mixDuration
=
8
;
update_model
=
[
clipIds
,
this
,
trackId
,
position
,
invalidateTimeline
,
mixDuration
]()
{
qDebug
()
<<
"==== PROCESSING UPDATE MODEL"
;
QModelIndex
modelIndex
=
makeClipIndexFromID
(
clipId
);
QModelIndex
modelIndex
=
makeClipIndexFromID
(
clipId
s
.
second
);
notifyChange
(
modelIndex
,
modelIndex
,
StartRole
);
QModelIndex
modelIndex2
=
makeClipIndexFromID
(
clipIds
.
first
);
notifyChange
(
modelIndex2
,
modelIndex2
,
DurationRole
);
if
(
invalidateTimeline
&&
!
getTrackById_const
(
trackId
)
->
isAudioTrack
())
{
int
in
=
getClipPosition
(
clipId
);
emit
invalidateZone
(
in
,
in
+
getClipPlaytime
(
clipId
));
emit
invalidateZone
(
position
-
mixDuration
,
position
+
mixDuration
);
}
return
true
;
};
if
(
notifyViewOnly
)
{
PUSH_LAMBDA
(
update_model
,
local_undo
);
}
ok
=
getTrackById
(
trackId
)
->
requestClipMix
(
clipId
,
posi
tion
,
updateView
,
finalMove
,
local_undo
,
local_redo
,
groupMove
);
ok
=
getTrackById
(
trackId
)
->
requestClipMix
(
clipId
s
,
mixDura
tion
,
updateView
,
finalMove
,
local_undo
,
local_redo
,
groupMove
);
if
(
!
ok
)
{
qDebug
()
<<
"-------------
\n
MIX FAILED, REVERTING
\n\n
-------------------"
;
bool
undone
=
local_undo
();
...
...
@@ -707,7 +709,7 @@ bool TimelineModel::requestClipMixMove(int clipId, int trackId, int position, bo
if
(
notifyViewOnly
)
{
PUSH_LAMBDA
(
update_model
,
local_redo
);
}
qDebug
()
<<
"======== FINISHED MIX CREATION FOR CLIP: "
<<
clipId
;
qDebug
()
<<
"======== FINISHED MIX CREATION FOR CLIP: "
<<
clipId
s
;
UPDATE_UNDO_REDO
(
local_redo
,
local_undo
,
undo
,
redo
);
return
ok
;
...
...
src/timeline2/model/timelinemodel.hpp
View file @
03cf9745
...
...
@@ -356,7 +356,7 @@ public:
*/
Q_INVOKABLE
bool
requestClipMove
(
int
clipId
,
int
trackId
,
int
position
,
bool
moveMirrorTracks
=
true
,
bool
updateView
=
true
,
bool
logUndo
=
true
,
bool
invalidateTimeline
=
false
);
bool
requestClipMix
Move
(
int
clipId
,
int
trackId
,
int
position
,
bool
updateView
,
bool
invalidateTimeline
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
);
bool
requestClipMix
(
std
::
pair
<
int
,
int
>
clipId
s
,
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
...
...
src/timeline2/model/trackmodel.cpp
View file @
03cf9745
...
...
@@ -519,7 +519,7 @@ int TrackModel::getBlankSizeNearComposition(int compoId, bool after)
return
length
;
}
Fun
TrackModel
::
requestClipResize_lambda
(
int
clipId
,
int
in
,
int
out
,
bool
right
)
Fun
TrackModel
::
requestClipResize_lambda
(
int
clipId
,
int
in
,
int
out
,
bool
right
,
bool
allowMix
)
{
QWriteLocker
locker
(
&
m_lock
);
int
clip_position
=
m_allClips
[
clipId
]
->
getPosition
();
...
...
@@ -598,7 +598,7 @@ Fun TrackModel::requestClipResize_lambda(int clipId, int in, int out, bool right
int
blank
=
-
1
;
int
other_blank_end
=
getBlankEnd
(
clip_position
,
(
target_track
+
1
)
%
2
);
if
(
right
)
{
if
(
target_clip
==
m_playlists
[
target_track
].
count
()
-
1
&&
other_blank_end
>=
out
)
{
if
(
target_clip
==
m_playlists
[
target_track
].
count
()
-
1
&&
(
allowMix
||
other_blank_end
>=
out
)
)
{
// clip is last, it can always be extended
return
[
this
,
target_clip
,
target_track
,
in
,
out
,
update_snaps
,
clipId
]()
{
if
(
isLocked
())
return
false
;
...
...
@@ -634,7 +634,7 @@ Fun TrackModel::requestClipResize_lambda(int clipId, int in, int out, bool right
}
if
(
m_playlists
[
target_track
].
is_blank
(
blank
))
{
int
blank_length
=
m_playlists
[
target_track
].
clip_length
(
blank
);
if
(
blank_length
+
delta
>=
0
&&
other_blank_end
>=
out
)
{
if
(
blank_length
+
delta
>=
0
&&
(
allowMix
||
other_blank_end
>=
out
)
)
{
return
[
blank_length
,
blank
,
right
,
clipId
,
delta
,
update_snaps
,
this
,
in
,
out
,
target_clip
,
target_track
]()
{
if
(
isLocked
())
return
false
;
int
target_clip_mutable
=
target_clip
;
...
...
@@ -1361,22 +1361,30 @@ bool TrackModel::isAvailable(int position, int duration)
return
m_playlists
[
0
].
is_blank
(
start_clip
);
}
bool
TrackModel
::
requestClipMix
(
int
clipId
,
int
posi
tion
,
bool
updateView
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
)
bool
TrackModel
::
requestClipMix
(
std
::
pair
<
int
,
int
>
clipId
s
,
int
mixDura
tion
,
bool
updateView
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
)
{
QWriteLocker
locker
(
&
m_lock
);
// By default, insertion occurs in topmost track
// Find out the clip id at position
int
clipInitialPos
;
int
secondClipPos
;
int
secondClipDuration
;
int
firstClipPos
;
int
firstClipDuration
;
int
source_track
;
MixInfo
mixInfo
;
qDebug
()
<<
"=========MIXING CLIPS: "
<<
clipIds
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
// The clip that will be moved to playlist 1
std
::
shared_ptr
<
ClipModel
>
movedClip
(
ptr
->
getClipPtr
(
clipId
));
source_track
=
movedClip
->
getSubPlaylistIndex
();
clipInitialPos
=
movedClip
->
getPosition
();
movedClip
->
setMixDuration
(
mixInfo
.
mixDuration
);
mixInfo
.
mixDuration
=
clipInitialPos
-
position
;
mixInfo
.
mixPosition
=
position
;
std
::
shared_ptr
<
ClipModel
>
secondClip
(
ptr
->
getClipPtr
(
clipIds
.
second
));
secondClipDuration
=
secondClip
->
getPlaytime
()
-
1
;
secondClipPos
=
secondClip
->
getPosition
();
source_track
=
secondClip
->
getSubPlaylistIndex
();
std
::
shared_ptr
<
ClipModel
>
firstClip
(
ptr
->
getClipPtr
(
clipIds
.
first
));
firstClipDuration
=
firstClip
->
getPlaytime
()
-
1
;
firstClipPos
=
firstClip
->
getPosition
();
mixInfo
.
mixPosition
=
secondClipPos
-
mixDuration
;
mixInfo
.
mixDuration
=
mixDuration
*
2
;
secondClip
->
setMixDuration
(
mixInfo
.
mixDuration
);
}
else
{
// Error, timeline unavailable
return
false
;
...
...
@@ -1388,57 +1396,63 @@ bool TrackModel::requestClipMix(int clipId, int position, bool updateView, bool
}
// Create mix compositing
Fun
build_mix
=
[
clipId
,
mixInfo
,
this
]()
{
Fun
build_mix
=
[
clipId
s
,
mixInfo
,
this
]()
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
std
::
shared_ptr
<
ClipModel
>
movedClip
(
ptr
->
getClipPtr
(
clipId
));
std
::
shared_ptr
<
ClipModel
>
movedClip
(
ptr
->
getClipPtr
(
clipId
s
.
second
));
movedClip
->
setMixDuration
(
mixInfo
.
mixDuration
);
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
clipId
);
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
clipId
s
.
second
);
emit
ptr
->
dataChanged
(
ix
,
ix
,
{
TimelineModel
::
StartRole
,
TimelineModel
::
MixRole
});
// Insert mix transition
if
(
isAudioTrack
())
{
std
::
shared_ptr
<
Mlt
::
Transition
>
t
(
new
Mlt
::
Transition
(
*
ptr
->
getProfile
(),
"mix"
));
t
->
set_in_and_out
(
mixInfo
.
mixPosition
,
mixInfo
.
mixPosition
+
mixInfo
.
mixDuration
);
m_track
->
plant_transition
(
*
t
.
get
(),
0
,
1
);
m_sameCompositions
[
clipId
]
=
t
;
m_sameCompositions
[
clipId
s
.
second
]
=
t
;
}
else
{
std
::
shared_ptr
<
Mlt
::
Transition
>
t
(
new
Mlt
::
Transition
(
*
ptr
->
getProfile
(),
"luma"
));
t
->
set_in_and_out
(
mixInfo
.
mixPosition
,
mixInfo
.
mixPosition
+
mixInfo
.
mixDuration
);
qDebug
()
<<
"==== INSERTING MIX: : "
<<
mixInfo
.
mixPosition
<<
" - "
<<
(
mixInfo
.
mixPosition
+
mixInfo
.
mixDuration
);
m_track
->
plant_transition
(
*
t
.
get
(),
0
,
1
);
m_sameCompositions
[
clipId
]
=
t
;
m_sameCompositions
[
clipId
s
.
second
]
=
t
;
}
}
return
true
;
};
Fun
destroy_mix
=
[
clipId
,
mixInfo
,
this
]()
{
Fun
destroy_mix
=
[
clipId
s
,
mixInfo
,
this
]()
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
Mlt
::
Transition
&
transition
=
*
m_sameCompositions
[
clipId
].
get
();
std
::
shared_ptr
<
ClipModel
>
movedClip
(
ptr
->
getClipPtr
(
clipId
));
Mlt
::
Transition
&
transition
=
*
m_sameCompositions
[
clipId
s
.
second
].
get
();
std
::
shared_ptr
<
ClipModel
>
movedClip
(
ptr
->
getClipPtr
(
clipId
s
.
second
));
movedClip
->
setMixDuration
(
0
);
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
clipId
);
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
clipId
s
.
second
);
emit
ptr
->
dataChanged
(
ix
,
ix
,
{
TimelineModel
::
StartRole
,
TimelineModel
::
MixRole
});
QScopedPointer
<
Mlt
::
Field
>
field
(
m_track
->
field
());
field
->
lock
();
field
->
disconnect_service
(
transition
);
field
->
unlock
();
m_sameCompositions
.
erase
(
clipId
);
m_sameCompositions
.
erase
(
clipId
s
.
second
);
}
return
true
;
};
// lock MLT playlist so that we don't end up with invalid frames in monitor
auto
operation
=
requestClipDeletion_lambda
(
clipId
,
updateView
,
finalMove
,
groupMove
,
finalMove
);
auto
operation
=
requestClipDeletion_lambda
(
clipId
s
.
second
,
updateView
,
finalMove
,
groupMove
,
finalMove
);
bool
res
=
operation
();
if
(
res
)
{
qDebug
()
<<
"=== CLIP DELETED; OK"
;
auto
reverse
=
requestClipInsertion_lambda
(
clipId
,
clipInitial
Pos
,
updateView
,
finalMove
,
groupMove
);
auto
reverse
=
requestClipInsertion_lambda
(
clipId
s
.
second
,
secondClip
Pos
,
updateView
,
finalMove
,
groupMove
);
if
(
auto
ptr
=
m_parent
.
lock
())
{
ptr
->
getClipPtr
(
clipId
)
->
setSubPlaylistIndex
(
dest_track
);
ptr
->
getClipPtr
(
clipId
s
.
second
)
->
setSubPlaylistIndex
(
dest_track
);
}
auto
operation2
=
requestClipInsertion_lambda
(
clipId
,
position
,
updateView
,
finalMove
,
groupMove
);
auto
operation2
=
requestClipInsertion_lambda
(
clipId
s
.
second
,
secondClipPos
,
updateView
,
finalMove
,
groupMove
);
res
=
res
&&
operation2
();
if
(
res
)
{
auto
reverse2
=
requestClipDeletion_lambda
(
clipId
,
updateView
,
finalMove
,
groupMove
,
finalMove
);
auto
operation3
=
requestClipResize_lambda
(
clipIds
.
second
,
secondClipPos
-
mixDuration
,
secondClipPos
+
secondClipDuration
,
false
,
true
);
qDebug
()
<<
"==== PROCESSING 2nd CLIP RESIZE: "
<<
clipIds
.
second
<<
", FROM: "
<<
(
secondClipPos
-
mixDuration
)
<<
"-"
<<
(
secondClipPos
+
secondClipDuration
);
res
=
operation3
();
auto
operation4
=
requestClipResize_lambda
(
clipIds
.
first
,
firstClipPos
,
firstClipPos
+
firstClipDuration
+
mixDuration
,
true
,
true
);
res
=
res
&&
operation4
();
auto
reverse2
=
requestClipDeletion_lambda
(
clipIds
.
second
,
updateView
,
finalMove
,
groupMove
,
finalMove
);
// Create mix composition
build_mix
();
qDebug
()
<<
"=============
\n
SECOND INSERT SUCCESS
\n\n
================="
;
...
...
src/timeline2/model/trackmodel.hpp
View file @
03cf9745
...
...
@@ -123,7 +123,7 @@ public:
QVariant
getProperty
(
const
QString
&
name
)
const
;
void
setProperty
(
const
QString
&
name
,
const
QString
&
value
);
/** @brief Create a composition between 2 same track clips */
bool
requestClipMix
(
int
clipId
,
int
posi
tion
,
bool
updateView
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
);
bool
requestClipMix
(
std
::
pair
<
int
,
int
>
clipId
s
,
int
mixDura
tion
,
bool
updateView
,
bool
finalMove
,
Fun
&
undo
,
Fun
&
redo
,
bool
groupMove
);
/** @brief Get in/out position for mix composition */
std
::
pair
<
int
,
int
>
getMixInfo
(
int
position
)
const
;
/** @brief Delete a mix composition */
...
...
@@ -149,7 +149,7 @@ protected:
@param out is the new ending on the clip
@param right is true if we change the right side of the clip, false otherwise
*/
Fun
requestClipResize_lambda
(
int
clipId
,
int
in
,
int
out
,
bool
right
);
Fun
requestClipResize_lambda
(
int
clipId
,
int
in
,
int
out
,
bool
right
,
bool
allowMix
=
false
);
/* @brief Performs an insertion of the given clip.
Returns true if the operation succeeded, and otherwise, the track is not modified.
...
...
src/timeline2/view/timelinecontroller.cpp
View file @
03cf9745
...
...
@@ -3672,13 +3672,43 @@ void TimelineController::mixClip()
if
(
sel
.
empty
())
{
return
;
}
int
idToMove
=
*
sel
.
begin
();
// Mix duration currently hardcoded to 75 frames
int
mixPosition
=
m_model
->
getItemPosition
(
idToMove
)
-
75
;
int
selectedTrack
=
-
1
;
int
idToMove
=
-
1
;
for
(
int
s
:
sel
)
{
if
(
!
m_model
->
isClip
(
s
))
{
continue
;
}
int
tid
=
m_model
->
getItemTrackId
(
s
);
if
(
selectedTrack
==
-
1
)
{
selectedTrack
=
tid
;
idToMove
=
s
;
break
;
}
}
if
(
idToMove
==
-
1
)
{
pCore
->
displayMessage
(
i18n
(
"Select a clip to apply the mix"
),
InformationMessage
,
500
);
return
;
}
int
cursor
=
pCore
->
getTimelinePosition
();
int
cid2
=
-
1
;
int
mixPosition
=
m_model
->
getItemPosition
(
idToMove
);
int
clipDuration
=
m_model
->
getItemPlaytime
(
idToMove
);
std
::
pair
<
int
,
int
>
clipsToMix
;
if
(
cursor
<
mixPosition
+
clipDuration
)
{
// Mix at start of selected clip
cid2
=
m_model
->
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
-
1
);
clipsToMix
.
first
=
cid2
;
clipsToMix
.
second
=
idToMove
;
}
else
{
// Mix at end of selected clip
mixPosition
+=
clipDuration
+
1
;
cid2
=
m_model
->
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
);
clipsToMix
.
first
=
idToMove
;
clipsToMix
.
second
=
cid2
;
}
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
int
selectedTrack
=
m_model
->
getItemTrackId
(
idToMove
);
bool
result
=
m_model
->
requestClipMixMove
(
idToMove
,
selectedTrack
,
mixPosition
,
true
,
true
,
true
,
undo
,
redo
,
false
);
bool
result
=
m_model
->
requestClipMix
(
clipsToMix
,
selectedTrack
,
mixPosition
,
true
,
true
,
true
,
undo
,
redo
,
false
);
pCore
->
pushUndo
(
undo
,
redo
,
i18n
(
"Create mix"
));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment