Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Kdenlive
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
259
Issues
259
List
Boards
Labels
Service Desk
Milestones
Merge Requests
14
Merge Requests
14
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Multimedia
Kdenlive
Commits
a976d33f
Commit
a976d33f
authored
Sep 17, 2020
by
Jean-Baptiste Mardelle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More fixes and tests for chained mixes
parent
a3bc1439
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
197 additions
and
26 deletions
+197
-26
src/timeline2/model/clipmodel.cpp
src/timeline2/model/clipmodel.cpp
+1
-1
src/timeline2/model/timelinemodel.cpp
src/timeline2/model/timelinemodel.cpp
+4
-0
src/timeline2/model/trackmodel.cpp
src/timeline2/model/trackmodel.cpp
+114
-25
tests/mixtest.cpp
tests/mixtest.cpp
+78
-0
No files found.
src/timeline2/model/clipmodel.cpp
View file @
a976d33f
...
...
@@ -255,7 +255,7 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
return
false
;
};
if
(
operation
())
{
Fun
reverse
=
[
hasMix
]()
{
return
true
;
};
Fun
reverse
=
[]()
{
return
true
;
};
if
(
logUndo
)
{
// Now, we are in the state in which the timeline should be when we try to revert current action. So we can build the reverse action from here
if
(
m_currentTrackId
!=
-
1
)
{
...
...
src/timeline2/model/timelinemodel.cpp
View file @
a976d33f
...
...
@@ -842,6 +842,10 @@ bool TimelineModel::mixClip(int idToMove)
nextClip
=
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
+
clipDuration
+
1
);
}
else
if
(
getTrackById_const
(
selectedTrack
)
->
hasEndMix
(
idToMove
))
{
previousClip
=
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
-
1
);
if
(
previousClip
>
-
1
&&
getTrackById_const
(
selectedTrack
)
->
hasEndMix
(
previousClip
))
{
// Could happen if 2 clips before are mixed to full length
previousClip
=
-
1
;
}
}
else
{
previousClip
=
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
-
1
);
nextClip
=
getTrackById_const
(
selectedTrack
)
->
getClipByPosition
(
mixPosition
+
clipDuration
+
1
);
...
...
src/timeline2/model/trackmodel.cpp
View file @
a976d33f
...
...
@@ -1443,7 +1443,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
int
source_track
;
int
mixPosition
;
int
dest_track
=
1
;
qDebug
()
<<
"=========MIXING CLIPS: "
<<
clipIds
;
bool
remixPlaylists
=
false
;
bool
clipHasEndMix
=
false
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
// The clip that will be moved to playlist 1
std
::
shared_ptr
<
ClipModel
>
secondClip
(
ptr
->
getClipPtr
(
clipIds
.
second
));
...
...
@@ -1452,14 +1453,26 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
source_track
=
secondClip
->
getSubPlaylistIndex
();
std
::
shared_ptr
<
ClipModel
>
firstClip
(
ptr
->
getClipPtr
(
clipIds
.
first
));
firstClipDuration
=
firstClip
->
getPlaytime
();
// Ensure mix is not longer than clip
// Ensure mix is not longer than clip
and doesn't overlap other mixes
firstClipPos
=
firstClip
->
getPosition
();
mixPosition
=
qMax
(
firstClipPos
,
secondClipPos
-
mixDuration
/
2
);
int
maxPos
=
qMin
(
secondClipPos
+
secondClipDuration
,
secondClipPos
+
mixDuration
-
(
mixDuration
/
2
));
mixDuration
=
qMin
(
mixDuration
,
maxPos
-
mixPosition
);
if
(
firstClip
->
getSubPlaylistIndex
()
==
1
)
{
dest_track
=
0
;
}
mixPosition
=
qMax
(
firstClipPos
,
secondClipPos
-
mixDuration
/
2
);
int
maxPos
=
qMin
(
secondClipPos
+
secondClipDuration
,
secondClipPos
+
mixDuration
-
(
mixDuration
/
2
));
if
(
hasStartMix
(
clipIds
.
first
))
{
std
::
pair
<
MixInfo
,
MixInfo
>
mixData
=
getMixInfo
(
clipIds
.
first
);
mixPosition
=
qMax
(
mixData
.
first
.
firstClipInOut
.
second
,
mixPosition
);
}
if
(
hasEndMix
(
clipIds
.
second
))
{
std
::
pair
<
MixInfo
,
MixInfo
>
mixData
=
getMixInfo
(
clipIds
.
second
);
clipHasEndMix
=
true
;
maxPos
=
qMin
(
mixData
.
second
.
secondClipInOut
.
first
,
maxPos
);
if
(
ptr
->
m_allClips
[
mixData
.
second
.
secondClipId
]
->
getSubPlaylistIndex
()
==
dest_track
)
{
remixPlaylists
=
true
;
}
}
mixDuration
=
qMin
(
mixDuration
,
maxPos
-
mixPosition
);
}
else
{
// Error, timeline unavailable
return
false
;
...
...
@@ -1468,13 +1481,14 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
// Rearrange subsequent mixes
Fun
rearrange_playlists
=
[]()
{
return
true
;
};
Fun
rearrange_playlists_undo
=
[]()
{
return
true
;
};
if
(
source_track
!=
dest_track
&&
hasEndMix
(
clipIds
.
second
)
)
{
if
(
remixPlaylists
&&
source_track
!=
dest_track
)
{
// A list of clip ids x playlists
QMap
<
int
,
int
>
rearrangedPlaylists
;
int
ix
=
0
;
int
moveId
=
m_mixList
.
value
(
clipIds
.
second
,
-
1
);
while
(
moveId
>
-
1
)
{
rearrangedPlaylists
.
insert
(
moveId
,
ix
%
2
?
1
-
dest_track
:
dest_track
);
int
current
=
m_allClips
[
moveId
]
->
getSubPlaylistIndex
();
rearrangedPlaylists
.
insert
(
moveId
,
current
);
if
(
hasEndMix
(
moveId
))
{
moveId
=
m_mixList
.
value
(
moveId
,
-
1
);
}
else
{
...
...
@@ -1482,31 +1496,106 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
}
ix
++
;
}
rearrange_playlists
=
[
this
,
rearrangedPlaylists
]()
{
bool
result
=
true
;
// First, remove all clips on playlist 0
QMapIterator
<
int
,
int
>
i
(
rearrangedPlaylists
);
i
.
toBack
();
while
(
i
.
hasPrevious
())
{
i
.
previous
();
result
=
switchPlaylist
(
i
.
key
(),
m_allClips
[
i
.
key
()]
->
getPosition
(),
m_allClips
[
i
.
key
()]
->
getSubPlaylistIndex
(),
i
.
value
());
if
(
!
result
)
{
break
;
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
0
)
{
int
target_clip
=
m_playlists
[
0
].
get_clip_index_at
(
m_allClips
[
i
.
key
()]
->
getPosition
());
std
::
unique_ptr
<
Mlt
::
Producer
>
prod
(
m_playlists
[
0
].
replace_with_blank
(
target_clip
));
}
m_playlists
[
0
].
consolidate_blanks
();
}
return
true
;
// Then move all clips from playlist 1 to playlist 0
i
.
toFront
();
if
(
auto
ptr
=
m_parent
.
lock
())
{
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
1
)
{
// Remove
int
pos
=
m_allClips
[
i
.
key
()]
->
getPosition
();
int
target_clip
=
m_playlists
[
1
].
get_clip_index_at
(
pos
);
std
::
unique_ptr
<
Mlt
::
Producer
>
prod
(
m_playlists
[
1
].
replace_with_blank
(
target_clip
));
// Replug
std
::
shared_ptr
<
ClipModel
>
clip
=
ptr
->
getClipPtr
(
i
.
key
());
int
index
=
m_playlists
[
0
].
insert_at
(
pos
,
*
clip
,
1
);
clip
->
setSubPlaylistIndex
(
0
);
m_playlists
[
0
].
consolidate_blanks
();
}
m_playlists
[
1
].
consolidate_blanks
();
}
// Finally replug playlist 0 clips in playlist 1 and fix transition direction
i
.
toFront
();
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
0
)
{
int
pos
=
m_allClips
[
i
.
key
()]
->
getPosition
();
std
::
shared_ptr
<
ClipModel
>
clip
=
ptr
->
getClipPtr
(
i
.
key
());
int
index
=
m_playlists
[
1
].
insert_at
(
pos
,
*
clip
,
1
);
clip
->
setSubPlaylistIndex
(
1
);
m_playlists
[
1
].
consolidate_blanks
();
}
if
(
m_sameCompositions
.
count
(
i
.
key
())
>
0
)
{
// There is a mix at clip start, adjust direction
Mlt
::
Transition
&
transition
=
*
m_sameCompositions
[
i
.
key
()].
get
();
transition
.
set
(
"reverse"
,
i
.
value
());
}
}
return
true
;
}
else
return
false
;
};
rearrange_playlists_undo
=
[
this
,
rearrangedPlaylists
]()
{
bool
result
=
true
;
// First, remove all clips on playlist 1
QMapIterator
<
int
,
int
>
i
(
rearrangedPlaylists
);
i
.
toBack
();
while
(
i
.
hasPrevious
())
{
i
.
previous
();
result
=
switchPlaylist
(
i
.
key
(),
m_allClips
[
i
.
key
()]
->
getPosition
(),
m_allClips
[
i
.
key
()]
->
getSubPlaylistIndex
(),
1
-
i
.
value
());
if
(
!
result
)
{
break
;
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
0
)
{
int
target_clip
=
m_playlists
[
1
].
get_clip_index_at
(
m_allClips
[
i
.
key
()]
->
getPosition
());
std
::
unique_ptr
<
Mlt
::
Producer
>
prod
(
m_playlists
[
1
].
replace_with_blank
(
target_clip
));
}
m_playlists
[
1
].
consolidate_blanks
();
}
return
true
;
// Then move all clips from playlist 0 to playlist 1
i
.
toFront
();
if
(
auto
ptr
=
m_parent
.
lock
())
{
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
1
)
{
// Remove
int
pos
=
m_allClips
[
i
.
key
()]
->
getPosition
();
int
target_clip
=
m_playlists
[
0
].
get_clip_index_at
(
pos
);
std
::
unique_ptr
<
Mlt
::
Producer
>
prod
(
m_playlists
[
0
].
replace_with_blank
(
target_clip
));
// Replug
std
::
shared_ptr
<
ClipModel
>
clip
=
ptr
->
getClipPtr
(
i
.
key
());
int
index
=
m_playlists
[
1
].
insert_at
(
pos
,
*
clip
,
1
);
clip
->
setSubPlaylistIndex
(
1
);
m_playlists
[
1
].
consolidate_blanks
();
}
m_playlists
[
0
].
consolidate_blanks
();
}
// Finally replug playlist 1 clips in playlist 0 and fix transition direction
i
.
toFront
();
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
i
.
value
()
==
0
)
{
int
pos
=
m_allClips
[
i
.
key
()]
->
getPosition
();
std
::
shared_ptr
<
ClipModel
>
clip
=
ptr
->
getClipPtr
(
i
.
key
());
int
index
=
m_playlists
[
0
].
insert_at
(
pos
,
*
clip
,
1
);
clip
->
setSubPlaylistIndex
(
0
);
m_playlists
[
0
].
consolidate_blanks
();
}
if
(
m_sameCompositions
.
count
(
i
.
key
())
>
0
)
{
// There is a mix at clip start, adjust direction
Mlt
::
Transition
&
transition
=
*
m_sameCompositions
[
i
.
key
()].
get
();
transition
.
set
(
"reverse"
,
1
-
i
.
value
());
}
}
return
true
;
}
else
return
false
;
};
}
// Create mix compositing
...
...
@@ -1557,7 +1646,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
auto
operation
=
requestClipDeletion_lambda
(
clipIds
.
second
,
updateView
,
finalMove
,
groupMove
,
finalMove
);
bool
res
=
operation
();
if
(
res
)
{
Fun
replay
=
[
this
,
clipIds
,
dest_track
,
firstClipPos
,
secondClipDuration
,
mixPosition
,
mixDuration
,
build_mix
,
secondClipPos
,
updateView
,
finalMove
,
groupMove
,
rearrange_playlists
]()
{
Fun
replay
=
[
this
,
clipIds
,
dest_track
,
firstClipPos
,
secondClipDuration
,
mixPosition
,
mixDuration
,
build_mix
,
secondClipPos
,
clipHasEndMix
,
updateView
,
finalMove
,
groupMove
,
rearrange_playlists
]()
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
ptr
->
getClipPtr
(
clipIds
.
second
)
->
setSubPlaylistIndex
(
dest_track
);
}
...
...
@@ -1569,8 +1658,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std
::
function
<
bool
(
void
)
>
local_undo
=
[]()
{
return
true
;
};
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
,
false
);
result
=
ptr
->
getClipPtr
(
clipIds
.
first
)
->
requestResize
(
mixPosition
+
mixDuration
-
firstClipPos
,
true
,
local_undo
,
local_redo
,
false
);
result
=
ptr
->
getClipPtr
(
clipIds
.
second
)
->
requestResize
(
secondClipPos
+
secondClipDuration
-
mixPosition
,
false
,
local_undo
,
local_redo
,
clipHasEndMix
);
result
=
result
&&
ptr
->
getClipPtr
(
clipIds
.
first
)
->
requestResize
(
mixPosition
+
mixDuration
-
firstClipPos
,
true
,
local_undo
,
local_redo
,
false
);
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
clipIds
.
second
);
emit
ptr
->
dataChanged
(
ix
,
ix
,
{
TimelineModel
::
StartRole
,
TimelineModel
::
MixRole
});
}
...
...
@@ -1590,9 +1679,9 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if
(
auto
ptr
=
m_parent
.
lock
())
{
ptr
->
getClipPtr
(
clipIds
.
second
)
->
setSubPlaylistIndex
(
source_track
);
}
rearrange_playlists_undo
();
auto
op
=
requestClipInsertion_lambda
(
clipIds
.
second
,
secondClipPos
,
updateView
,
finalMove
,
groupMove
);
op
();
rearrange_playlists_undo
();
return
true
;
};
res
=
res
&&
replay
();
...
...
tests/mixtest.cpp
View file @
a976d33f
...
...
@@ -355,6 +355,84 @@ TEST_CASE("Simple Mix", "[SameTrackMix]")
state0
();
}
SECTION
(
"Test chained mixes on color clips"
)
{
// Add 2 more color clips
int
cid5
;
int
cid6
;
int
cid7
;
state0
();
REQUIRE
(
timeline
->
requestClipInsertion
(
binId2
,
tid2
,
540
,
cid5
));
REQUIRE
(
timeline
->
requestItemResize
(
cid5
,
20
,
true
,
true
));
REQUIRE
(
timeline
->
requestClipInsertion
(
binId2
,
tid2
,
560
,
cid6
));
REQUIRE
(
timeline
->
requestItemResize
(
cid6
,
20
,
true
,
true
));
REQUIRE
(
timeline
->
requestClipInsertion
(
binId2
,
tid2
,
580
,
cid7
));
REQUIRE
(
timeline
->
requestItemResize
(
cid7
,
20
,
true
,
true
));
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=20
// Mix 3 and 4
REQUIRE
(
timeline
->
mixClip
(
cid4
));
REQUIRE
(
timeline
->
m_allClips
[
cid3
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid4
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid5
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid6
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid7
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
getTrackById_const
(
tid2
)
->
mixCount
()
==
1
);
// Mix 6 and 7
REQUIRE
(
timeline
->
mixClip
(
cid7
));
REQUIRE
(
timeline
->
m_allClips
[
cid3
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid4
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid5
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid6
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid7
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
getTrackById_const
(
tid2
)
->
mixCount
()
==
2
);
// Mix 5 and 6
REQUIRE
(
timeline
->
mixClip
(
cid6
));
REQUIRE
(
timeline
->
m_allClips
[
cid3
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid4
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid5
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid6
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid7
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
getTrackById_const
(
tid2
)
->
mixCount
()
==
3
);
// Undo mix 5 and 6
undoStack
->
undo
();
REQUIRE
(
timeline
->
m_allClips
[
cid3
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid4
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid5
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid6
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid7
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
getTrackById_const
(
tid2
)
->
mixCount
()
==
2
);
// Undo mix 6 and 7
undoStack
->
undo
();
REQUIRE
(
timeline
->
m_allClips
[
cid3
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid4
]
->
getSubPlaylistIndex
()
==
1
);
REQUIRE
(
timeline
->
m_allClips
[
cid5
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid6
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
m_allClips
[
cid7
]
->
getSubPlaylistIndex
()
==
0
);
REQUIRE
(
timeline
->
getTrackById_const
(
tid2
)
->
mixCount
()
==
1
);
// Undo mix 3 and 4
undoStack
->
undo
();
// Undo insert/resize ops
undoStack
->
undo
();
undoStack
->
undo
();
undoStack
->
undo
();
undoStack
->
undo
();
undoStack
->
undo
();
undoStack
->
undo
();
state0
();
}
binModel
->
clean
();
pCore
->
m_projectManager
=
nullptr
;
Logger
::
print_trace
();
...
...
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