1 #include "test_utils.hpp"
2 
3 Mlt::Profile profile_composition;
4 QString aCompo;
5 TEST_CASE("Basic creation/deletion of a composition", "[CompositionModel]")
6 {
7     // Check whether repo works
8     QVector<QPair<QString, QString>> transitions = TransitionsRepository::get()->getNames();
9     REQUIRE(!transitions.isEmpty());
10 
11     // Look for a compo
12     for (const auto &trans : qAsConst(transitions)) {
13         if (TransitionsRepository::get()->isComposition(trans.first)) {
14             aCompo = trans.first;
15             break;
16         }
17     }
18 
19     REQUIRE(!aCompo.isEmpty());
20 
21     // Check construction from repo
22     std::unique_ptr<Mlt::Transition> mlt_transition(TransitionsRepository::get()->getTransition(aCompo));
23 
24     REQUIRE(mlt_transition->is_valid());
25 
26     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
27     std::shared_ptr<MarkerListModel> guideModel(new MarkerListModel(undoStack));
28     std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(&profile_composition, guideModel, undoStack);
29 
30     REQUIRE(timeline->getCompositionsCount() == 0);
31     int id1 = CompositionModel::construct(timeline, aCompo, QString());
32     REQUIRE(timeline->getCompositionsCount() == 1);
33 
34     int id2 = CompositionModel::construct(timeline, aCompo, QString());
35     REQUIRE(timeline->getCompositionsCount() == 2);
36 
37     int id3 = CompositionModel::construct(timeline, aCompo, QString());
38     REQUIRE(timeline->getCompositionsCount() == 3);
39 
40     // Test deletion
41     REQUIRE(timeline->requestItemDeletion(id2));
42     REQUIRE(timeline->getCompositionsCount() == 2);
43     REQUIRE(timeline->requestItemDeletion(id3));
44     REQUIRE(timeline->getCompositionsCount() == 1);
45     REQUIRE(timeline->requestItemDeletion(id1));
46     REQUIRE(timeline->getCompositionsCount() == 0);
47 }
48 
49 TEST_CASE("Composition manipulation", "[CompositionModel]")
50 {
51     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
52     std::shared_ptr<MarkerListModel> guideModel(new MarkerListModel(undoStack));
53     std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(&profile_composition, guideModel, undoStack);
54 
55     int tid0 = TrackModel::construct(timeline);
56     Q_UNUSED(tid0);
57     int tid1 = TrackModel::construct(timeline);
58     int cid2 = CompositionModel::construct(timeline, aCompo, QString());
59     int tid2 = TrackModel::construct(timeline);
60     int tid3 = TrackModel::construct(timeline);
61     Q_UNUSED(tid3);
62     int cid1 = CompositionModel::construct(timeline, aCompo, QString());
63 
64     REQUIRE(timeline->getCompositionPlaytime(cid1) == 1);
65     REQUIRE(timeline->getCompositionPlaytime(cid2) == 1);
66 
67     SECTION("Insert a composition in a track and change track")
68     {
69         REQUIRE(timeline->checkConsistency());
70         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
71         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 0);
72 
73         REQUIRE(timeline->getCompositionPlaytime(cid1) == 1);
74         REQUIRE(timeline->getCompositionPlaytime(cid2) == 1);
75         REQUIRE(timeline->getCompositionTrackId(cid1) == -1);
76         REQUIRE(timeline->getCompositionPosition(cid1) == -1);
77 
78         int pos = 10;
79         REQUIRE(timeline->requestCompositionMove(cid1, tid1, pos));
80         REQUIRE(timeline->checkConsistency());
81         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
82         REQUIRE(timeline->getCompositionPosition(cid1) == pos);
83         REQUIRE(timeline->getCompositionPlaytime(cid1) == 1);
84         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
85         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 0);
86 
87         pos = 10;
88         REQUIRE(timeline->requestCompositionMove(cid1, tid2, pos));
89         REQUIRE(timeline->checkConsistency());
90         REQUIRE(timeline->getCompositionTrackId(cid1) == tid2);
91         REQUIRE(timeline->getCompositionPosition(cid1) == pos);
92         REQUIRE(timeline->getCompositionPlaytime(cid1) == 1);
93         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
94         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
95 
96         REQUIRE(timeline->requestItemResize(cid1, 10, true) > -1);
97         REQUIRE(timeline->checkConsistency());
98         REQUIRE(timeline->getCompositionTrackId(cid1) == tid2);
99         REQUIRE(timeline->getCompositionPosition(cid1) == pos);
100         REQUIRE(timeline->getCompositionPlaytime(cid1) == 10);
101         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
102         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
103 
104         REQUIRE(timeline->requestCompositionMove(cid2, tid2, 0));
105         REQUIRE(timeline->requestItemResize(cid2, 10, true) > -1);
106         REQUIRE(timeline->checkConsistency());
107         REQUIRE(timeline->getCompositionPlaytime(cid2) == 10);
108 
109         // Check conflicts
110         int pos2 = timeline->getCompositionPlaytime(cid1);
111         REQUIRE(timeline->requestCompositionMove(cid2, tid1, pos2));
112         REQUIRE(timeline->checkConsistency());
113         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
114         REQUIRE(timeline->getCompositionPosition(cid2) == pos2);
115         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
116         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
117 
118         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, pos2 + 2));
119         REQUIRE(timeline->checkConsistency());
120         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
121         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
122         REQUIRE(timeline->getCompositionTrackId(cid1) == tid2);
123         REQUIRE(timeline->getCompositionPosition(cid1) == pos);
124         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
125         REQUIRE(timeline->getCompositionPosition(cid2) == pos2);
126 
127         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, pos2 - 2));
128         REQUIRE(timeline->checkConsistency());
129         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
130         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
131         REQUIRE(timeline->getCompositionTrackId(cid1) == tid2);
132         REQUIRE(timeline->getCompositionPosition(cid1) == pos);
133         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
134         REQUIRE(timeline->getCompositionPosition(cid2) == pos2);
135 
136         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
137         REQUIRE(timeline->checkConsistency());
138         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 0);
139         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
140         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
141         REQUIRE(timeline->getCompositionPosition(cid1) == 0);
142         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
143         REQUIRE(timeline->getCompositionPosition(cid2) == pos2);
144     }
145 
146     SECTION("Insert consecutive compositions")
147     {
148         int length = 12;
149         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
150         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
151         REQUIRE(timeline->getCompositionPlaytime(cid1) == length);
152         REQUIRE(timeline->getCompositionPlaytime(cid2) == length);
153         REQUIRE(timeline->checkConsistency());
154         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
155         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 0);
156 
157         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
158         REQUIRE(timeline->checkConsistency());
159         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
160         REQUIRE(timeline->getCompositionPosition(cid1) == 0);
161         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
162 
163         REQUIRE(timeline->requestCompositionMove(cid2, tid1, length));
164         REQUIRE(timeline->checkConsistency());
165         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
166         REQUIRE(timeline->getCompositionPosition(cid2) == length);
167         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
168     }
169 
170     SECTION("Resize orphan composition")
171     {
172         int length = 12;
173         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
174         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
175         REQUIRE(timeline->getCompositionPlaytime(cid1) == length);
176         REQUIRE(timeline->getCompositionPlaytime(cid2) == length);
177 
178         REQUIRE(timeline->getCompositionPlaytime(cid2) == length);
179         REQUIRE(timeline->requestItemResize(cid2, 5, true) > -1);
180         auto inOut = std::pair<int, int>{0, 4};
181         REQUIRE(timeline->m_allCompositions[cid2]->getInOut() == inOut);
182         REQUIRE(timeline->getCompositionPlaytime(cid2) == 5);
183         REQUIRE(timeline->requestItemResize(cid2, 10, false) > -1);
184         REQUIRE(timeline->getCompositionPlaytime(cid2) == 10);
185         REQUIRE(timeline->requestItemResize(cid2, length + 1, true) > -1);
186         REQUIRE(timeline->getCompositionPlaytime(cid2) == length + 1);
187         REQUIRE(timeline->requestItemResize(cid2, 2, false) > -1);
188         REQUIRE(timeline->getCompositionPlaytime(cid2) == 2);
189         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
190         REQUIRE(timeline->getCompositionPlaytime(cid2) == length);
191         REQUIRE(timeline->requestItemResize(cid2, length - 2, true) > -1);
192         REQUIRE(timeline->getCompositionPlaytime(cid2) == length - 2);
193         REQUIRE(timeline->requestItemResize(cid2, length - 3, true) > -1);
194         REQUIRE(timeline->getCompositionPlaytime(cid2) == length - 3);
195     }
196 
197     SECTION("Resize inserted compositions")
198     {
199         int length = 12;
200         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
201         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
202 
203         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
204         REQUIRE(timeline->checkConsistency());
205 
206         REQUIRE(timeline->requestItemResize(cid1, 5, true) > -1);
207         REQUIRE(timeline->checkConsistency());
208         REQUIRE(timeline->getCompositionPlaytime(cid1) == 5);
209         REQUIRE(timeline->getCompositionPosition(cid1) == 0);
210 
211         REQUIRE(timeline->requestCompositionMove(cid2, tid1, 5));
212         REQUIRE(timeline->checkConsistency());
213         REQUIRE(timeline->getCompositionPlaytime(cid2) == length);
214         REQUIRE(timeline->getCompositionPosition(cid2) == 5);
215 
216         REQUIRE(timeline->requestItemResize(cid1, 6, true) == -1);
217         REQUIRE(timeline->requestItemResize(cid1, 6, false) == -1);
218         REQUIRE(timeline->checkConsistency());
219 
220         REQUIRE(timeline->requestItemResize(cid2, length - 5, false) > -1);
221         REQUIRE(timeline->checkConsistency());
222         REQUIRE(timeline->getCompositionPosition(cid2) == 10);
223 
224         REQUIRE(timeline->requestItemResize(cid1, 10, true) > -1);
225         REQUIRE(timeline->checkConsistency());
226         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
227     }
228 
229     SECTION("Change track of resized compositions")
230     {
231         int length = 12;
232         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
233         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
234 
235         REQUIRE(timeline->requestCompositionMove(cid2, tid1, 5));
236         REQUIRE(timeline->checkConsistency());
237         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
238 
239         REQUIRE(timeline->requestCompositionMove(cid1, tid2, 10));
240         REQUIRE(timeline->checkConsistency());
241         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 1);
242 
243         REQUIRE(timeline->requestItemResize(cid1, 5, false) > -1);
244         REQUIRE(timeline->checkConsistency());
245 
246         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
247         REQUIRE(timeline->checkConsistency());
248         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
249         REQUIRE(timeline->getTrackCompositionsCount(tid2) == 0);
250     }
251 
252     SECTION("Composition Move")
253     {
254         int length = 12;
255         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
256         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
257 
258         REQUIRE(timeline->requestCompositionMove(cid2, tid1, 5));
259         REQUIRE(timeline->checkConsistency());
260         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
261         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
262         REQUIRE(timeline->getCompositionPosition(cid2) == 5);
263 
264         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 5 + length));
__anoneb73c10f0102() 265         auto state = [&]() {
266             REQUIRE(timeline->checkConsistency());
267             REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
268             REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
269             REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
270             REQUIRE(timeline->getCompositionPosition(cid1) == 5 + length);
271             REQUIRE(timeline->getCompositionPosition(cid2) == 5);
272         };
273         state();
274 
275         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, 3 + length));
276         state();
277 
278         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, 0));
279         state();
280 
281         REQUIRE(timeline->requestCompositionMove(cid2, tid1, 0));
__anoneb73c10f0202() 282         auto state2 = [&]() {
283             REQUIRE(timeline->checkConsistency());
284             REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
285             REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
286             REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
287             REQUIRE(timeline->getCompositionPosition(cid1) == 5 + length);
288             REQUIRE(timeline->getCompositionPosition(cid2) == 0);
289         };
290         state2();
291 
292         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, 0));
293         state2();
294 
295         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, length - 5));
296         state2();
297 
298         REQUIRE(timeline->requestCompositionMove(cid1, tid1, length));
299         REQUIRE(timeline->checkConsistency());
300         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
301         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
302         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
303         REQUIRE(timeline->getCompositionPosition(cid1) == length);
304         REQUIRE(timeline->getCompositionPosition(cid2) == 0);
305 
306         REQUIRE(timeline->requestItemResize(cid2, length - 5, true) > -1);
307         REQUIRE(timeline->checkConsistency());
308         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
309         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
310         REQUIRE(timeline->getCompositionPosition(cid1) == length);
311         REQUIRE(timeline->getCompositionPosition(cid2) == 0);
312 
313         // REQUIRE(timeline->allowCompositionMove(cid1, tid1, length - 5));
314         REQUIRE(timeline->requestCompositionMove(cid1, tid1, length - 5));
315         REQUIRE(timeline->checkConsistency());
316         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
317         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
318         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
319         REQUIRE(timeline->getCompositionPosition(cid1) == length - 5);
320         REQUIRE(timeline->getCompositionPosition(cid2) == 0);
321 
322         REQUIRE(timeline->requestItemResize(cid2, length - 10, false) > -1);
323         REQUIRE(timeline->checkConsistency());
324         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
325         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
326         REQUIRE(timeline->getCompositionPosition(cid1) == length - 5);
327         REQUIRE(timeline->getCompositionPosition(cid2) == 5);
328 
329         REQUIRE_FALSE(timeline->requestCompositionMove(cid1, tid1, 0));
330         REQUIRE(timeline->checkConsistency());
331         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
332         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
333         REQUIRE(timeline->getCompositionPosition(cid1) == length - 5);
334         REQUIRE(timeline->getCompositionPosition(cid2) == 5);
335 
336         REQUIRE(timeline->requestCompositionMove(cid2, tid1, 0));
337         REQUIRE(timeline->checkConsistency());
338         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
339         REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
340         REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
341         REQUIRE(timeline->getCompositionPosition(cid1) == length - 5);
342         REQUIRE(timeline->getCompositionPosition(cid2) == 0);
343     }
344 
345     SECTION("Move and resize")
346     {
347         int length = 12;
348         REQUIRE(timeline->requestCompositionMove(cid2, tid2, 0));
349         REQUIRE(timeline->requestItemResize(cid1, length, true) > -1);
350         REQUIRE(timeline->requestItemResize(cid2, length, true) > -1);
351 
352         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
353         REQUIRE(timeline->getCompositionPosition(cid1) == 0);
354         REQUIRE(timeline->requestItemResize(cid1, length - 2, false, 0) > -1);
355         REQUIRE(timeline->getCompositionPosition(cid1) == 2);
356         REQUIRE(timeline->requestCompositionMove(cid1, tid1, 0));
__anoneb73c10f0302() 357         auto state = [&]() {
358             REQUIRE(timeline->checkConsistency());
359             REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
360             REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
361             REQUIRE(timeline->getCompositionPosition(cid1) == 0);
362             REQUIRE(timeline->getCompositionPlaytime(cid1) == length - 2);
363         };
364         state();
365 
366         REQUIRE(timeline->requestItemResize(cid1, length - 4, true) > -1);
367         REQUIRE(timeline->requestCompositionMove(cid2, tid1, length - 4 + 1));
368         REQUIRE(timeline->requestItemResize(cid2, length - 2, false) > -1);
369         REQUIRE(timeline->requestCompositionMove(cid2, tid1, length - 4 + 1));
__anoneb73c10f0402() 370         auto state2 = [&]() {
371             REQUIRE(timeline->checkConsistency());
372             REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
373             REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
374             REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
375             REQUIRE(timeline->getCompositionPosition(cid1) == 0);
376             REQUIRE(timeline->getCompositionPlaytime(cid1) == length - 4);
377             REQUIRE(timeline->getCompositionPosition(cid2) == length - 4 + 1);
378             REQUIRE(timeline->getCompositionPlaytime(cid2) == length - 2);
379         };
380         state2();
381         // the gap between the two clips is 1 frame, we try to resize them by 2 frames
382         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) == -1);
383         state2();
384         REQUIRE(timeline->requestItemResize(cid2, length, false) == -1);
385         state2();
386 
387         REQUIRE(timeline->requestCompositionMove(cid2, tid1, length - 4));
__anoneb73c10f0502() 388         auto state3 = [&]() {
389             REQUIRE(timeline->checkConsistency());
390             REQUIRE(timeline->getCompositionTrackId(cid1) == tid1);
391             REQUIRE(timeline->getCompositionTrackId(cid2) == tid1);
392             REQUIRE(timeline->getTrackCompositionsCount(tid1) == 2);
393             REQUIRE(timeline->getCompositionPosition(cid1) == 0);
394             REQUIRE(timeline->getCompositionPlaytime(cid1) == length - 4);
395             REQUIRE(timeline->getCompositionPosition(cid2) == length - 4);
396             REQUIRE(timeline->getCompositionPlaytime(cid2) == length - 2);
397         };
398         state3();
399 
400         // Now the gap is 0 frames, the resize should still fail
401         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) == -1);
402         state3();
403         REQUIRE(timeline->requestItemResize(cid2, length, false) == -1);
404         state3();
405 
406         // We move cid1 out of the way
407         REQUIRE(timeline->requestCompositionMove(cid1, tid2, 0));
408         // now resize should work
409         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) > -1);
410         REQUIRE(timeline->requestItemResize(cid2, length, false) > -1);
411     }
412 }
413