Improve and fix some tests.
[dcpomatic.git] / test / reels_test.cc
1 /*
2     Copyright (C) 2015-2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /** @file  test/reels_test.cc
22  *  @brief Check manipulation of reels in various ways.
23  *  @ingroup specific
24  */
25
26 #include "lib/film.h"
27 #include "lib/ratio.h"
28 #include "lib/ffmpeg_content.h"
29 #include "lib/image_content.h"
30 #include "lib/dcp_content_type.h"
31 #include "lib/dcp_content.h"
32 #include "lib/video_content.h"
33 #include "lib/string_text_file_content.h"
34 #include "lib/content_factory.h"
35 #include "test.h"
36 #include <boost/test/unit_test.hpp>
37 #include <boost/foreach.hpp>
38 #include <iostream>
39
40 using std::list;
41 using std::cout;
42 using std::vector;
43 using std::string;
44 using boost::shared_ptr;
45 using boost::function;
46 using namespace dcpomatic;
47
48 /** Test Film::reels() */
49 BOOST_AUTO_TEST_CASE (reels_test1)
50 {
51         shared_ptr<Film> film = new_test_film ("reels_test1");
52         film->set_container (Ratio::from_id ("185"));
53         shared_ptr<FFmpegContent> A (new FFmpegContent("test/data/test.mp4"));
54         film->examine_and_add_content (A);
55         shared_ptr<FFmpegContent> B (new FFmpegContent("test/data/test.mp4"));
56         film->examine_and_add_content (B);
57         BOOST_REQUIRE (!wait_for_jobs());
58         BOOST_CHECK_EQUAL (A->full_length(film).get(), 288000);
59
60         film->set_reel_type (REELTYPE_SINGLE);
61         list<DCPTimePeriod> r = film->reels ();
62         BOOST_CHECK_EQUAL (r.size(), 1);
63         BOOST_CHECK_EQUAL (r.front().from.get(), 0);
64         BOOST_CHECK_EQUAL (r.front().to.get(), 288000 * 2);
65
66         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
67         r = film->reels ();
68         BOOST_CHECK_EQUAL (r.size(), 2);
69         BOOST_CHECK_EQUAL (r.front().from.get(), 0);
70         BOOST_CHECK_EQUAL (r.front().to.get(), 288000);
71         BOOST_CHECK_EQUAL (r.back().from.get(), 288000);
72         BOOST_CHECK_EQUAL (r.back().to.get(), 288000 * 2);
73
74         film->set_j2k_bandwidth (100000000);
75         film->set_reel_type (REELTYPE_BY_LENGTH);
76         /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */
77         film->set_reel_length (31253154);
78         r = film->reels ();
79         BOOST_CHECK_EQUAL (r.size(), 3);
80         list<DCPTimePeriod>::const_iterator i = r.begin ();
81         BOOST_CHECK_EQUAL (i->from.get(), 0);
82         BOOST_CHECK_EQUAL (i->to.get(), DCPTime::from_frames(60, 24).get());
83         ++i;
84         BOOST_CHECK_EQUAL (i->from.get(), DCPTime::from_frames(60, 24).get());
85         BOOST_CHECK_EQUAL (i->to.get(), DCPTime::from_frames(120, 24).get());
86         ++i;
87         BOOST_CHECK_EQUAL (i->from.get(), DCPTime::from_frames(120, 24).get());
88         BOOST_CHECK_EQUAL (i->to.get(), DCPTime::from_frames(144, 24).get());
89 }
90
91 /** Make a short DCP with multi reels split by video content, then import
92  *  this into a new project and make a new DCP referencing it.
93  */
94 BOOST_AUTO_TEST_CASE (reels_test2)
95 {
96         shared_ptr<Film> film = new_test_film ("reels_test2");
97         film->set_name ("reels_test2");
98         film->set_container (Ratio::from_id ("185"));
99         film->set_interop (false);
100         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
101
102         {
103                 shared_ptr<ImageContent> c (new ImageContent("test/data/flat_red.png"));
104                 film->examine_and_add_content (c);
105                 BOOST_REQUIRE (!wait_for_jobs());
106                 c->video->set_length (24);
107         }
108
109         {
110                 shared_ptr<ImageContent> c (new ImageContent("test/data/flat_green.png"));
111                 film->examine_and_add_content (c);
112                 BOOST_REQUIRE (!wait_for_jobs());
113                 c->video->set_length (24);
114         }
115
116         {
117                 shared_ptr<ImageContent> c (new ImageContent("test/data/flat_blue.png"));
118                 film->examine_and_add_content (c);
119                 BOOST_REQUIRE (!wait_for_jobs());
120                 c->video->set_length (24);
121         }
122
123         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
124         BOOST_CHECK_EQUAL (film->reels().size(), 3);
125         BOOST_REQUIRE (!wait_for_jobs());
126
127         film->make_dcp ();
128         BOOST_REQUIRE (!wait_for_jobs());
129
130         check_dcp ("test/data/reels_test2", film->dir (film->dcp_name()));
131
132         shared_ptr<Film> film2 = new_test_film ("reels_test2b");
133         film2->set_name ("reels_test2b");
134         film2->set_container (Ratio::from_id ("185"));
135         film2->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
136         film2->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
137
138         shared_ptr<DCPContent> c (new DCPContent(film->dir(film->dcp_name())));
139         film2->examine_and_add_content (c);
140         BOOST_REQUIRE (!wait_for_jobs ());
141
142         list<DCPTimePeriod> r = film2->reels ();
143         BOOST_CHECK_EQUAL (r.size(), 3);
144         list<DCPTimePeriod>::const_iterator i = r.begin ();
145         BOOST_CHECK_EQUAL (i->from.get(), 0);
146         BOOST_CHECK_EQUAL (i->to.get(), 96000);
147         ++i;
148         BOOST_CHECK_EQUAL (i->from.get(), 96000);
149         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 2);
150         ++i;
151         BOOST_CHECK_EQUAL (i->from.get(), 96000 * 2);
152         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 3);
153
154         c->set_reference_video (true);
155         c->set_reference_audio (true);
156
157         film2->make_dcp ();
158         BOOST_REQUIRE (!wait_for_jobs());
159 }
160
161 /** Check that REELTYPE_BY_VIDEO_CONTENT adds an extra reel, if necessary, at the end
162  *  of all the video content to mop up anything afterward.
163  */
164 BOOST_AUTO_TEST_CASE (reels_test3)
165 {
166         shared_ptr<Film> film = new_test_film ("reels_test3");
167         film->set_name ("reels_test3");
168         film->set_container (Ratio::from_id ("185"));
169         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
170         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
171
172         shared_ptr<Content> dcp (new DCPContent("test/data/reels_test2"));
173         film->examine_and_add_content (dcp);
174         shared_ptr<Content> sub (new StringTextFileContent("test/data/subrip.srt"));
175         film->examine_and_add_content (sub);
176         BOOST_REQUIRE (!wait_for_jobs());
177
178         list<DCPTimePeriod> reels = film->reels();
179         BOOST_REQUIRE_EQUAL (reels.size(), 4);
180         list<DCPTimePeriod>::const_iterator i = reels.begin ();
181         BOOST_CHECK_EQUAL (i->from.get(), 0);
182         BOOST_CHECK_EQUAL (i->to.get(), 96000);
183         ++i;
184         BOOST_CHECK_EQUAL (i->from.get(), 96000);
185         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 2);
186         ++i;
187         BOOST_CHECK_EQUAL (i->from.get(), 96000 * 2);
188         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 3);
189         ++i;
190         BOOST_CHECK_EQUAL (i->from.get(), 96000 * 3);
191         BOOST_CHECK_EQUAL (i->to.get(), sub->full_length(film).ceil(film->video_frame_rate()).get());
192 }
193
194 /** Check creation of a multi-reel DCP with a single .srt subtitle file;
195  *  make sure that the reel subtitle timing is done right.
196  */
197 BOOST_AUTO_TEST_CASE (reels_test4)
198 {
199         shared_ptr<Film> film = new_test_film ("reels_test4");
200         film->set_name ("reels_test4");
201         film->set_container (Ratio::from_id ("185"));
202         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
203         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
204         film->set_interop (false);
205
206         /* 4 piece of 1s-long content */
207         shared_ptr<ImageContent> content[4];
208         for (int i = 0; i < 4; ++i) {
209                 content[i].reset (new ImageContent("test/data/flat_green.png"));
210                 film->examine_and_add_content (content[i]);
211                 BOOST_REQUIRE (!wait_for_jobs());
212                 content[i]->video->set_length (24);
213         }
214
215         shared_ptr<StringTextFileContent> subs (new StringTextFileContent("test/data/subrip3.srt"));
216         film->examine_and_add_content (subs);
217         BOOST_REQUIRE (!wait_for_jobs());
218
219         list<DCPTimePeriod> reels = film->reels();
220         BOOST_REQUIRE_EQUAL (reels.size(), 4);
221         list<DCPTimePeriod>::const_iterator i = reels.begin ();
222         BOOST_CHECK_EQUAL (i->from.get(), 0);
223         BOOST_CHECK_EQUAL (i->to.get(), 96000);
224         ++i;
225         BOOST_CHECK_EQUAL (i->from.get(), 96000);
226         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 2);
227         ++i;
228         BOOST_CHECK_EQUAL (i->from.get(), 96000 * 2);
229         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 3);
230         ++i;
231         BOOST_CHECK_EQUAL (i->from.get(), 96000 * 3);
232         BOOST_CHECK_EQUAL (i->to.get(), 96000 * 4);
233
234         film->make_dcp ();
235         BOOST_REQUIRE (!wait_for_jobs());
236
237         check_dcp ("test/data/reels_test4", film->dir (film->dcp_name()));
238 }
239
240 BOOST_AUTO_TEST_CASE (reels_test5)
241 {
242         shared_ptr<Film> film = new_test_film ("reels_test5");
243         film->set_sequence (false);
244         shared_ptr<DCPContent> dcp (new DCPContent("test/data/reels_test4"));
245         film->examine_and_add_content (dcp);
246         BOOST_REQUIRE (!wait_for_jobs ());
247
248         /* Set to 2123 but it will be rounded up to the next frame (4000) */
249         dcp->set_position(film, DCPTime(2123));
250
251         {
252                 list<DCPTimePeriod> p = dcp->reels (film);
253                 BOOST_REQUIRE_EQUAL (p.size(), 4);
254                 list<DCPTimePeriod>::const_iterator i = p.begin();
255                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 0), DCPTime(4000 + 96000)));
256                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 96000), DCPTime(4000 + 192000)));
257                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 192000), DCPTime(4000 + 288000)));
258                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 288000), DCPTime(4000 + 384000)));
259         }
260
261         {
262                 dcp->set_trim_start (ContentTime::from_seconds (0.5));
263                 list<DCPTimePeriod> p = dcp->reels (film);
264                 BOOST_REQUIRE_EQUAL (p.size(), 4);
265                 list<DCPTimePeriod>::const_iterator i = p.begin();
266                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 0), DCPTime(4000 + 48000)));
267                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 48000), DCPTime(4000 + 144000)));
268                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 144000), DCPTime(4000 + 240000)));
269                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 240000), DCPTime(4000 + 336000)));
270         }
271
272         {
273                 dcp->set_trim_end (ContentTime::from_seconds (0.5));
274                 list<DCPTimePeriod> p = dcp->reels (film);
275                 BOOST_REQUIRE_EQUAL (p.size(), 4);
276                 list<DCPTimePeriod>::const_iterator i = p.begin();
277                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 0), DCPTime(4000 + 48000)));
278                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 48000), DCPTime(4000 + 144000)));
279                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 144000), DCPTime(4000 + 240000)));
280                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 240000), DCPTime(4000 + 288000)));
281         }
282
283         {
284                 dcp->set_trim_start (ContentTime::from_seconds (1.5));
285                 list<DCPTimePeriod> p = dcp->reels (film);
286                 BOOST_REQUIRE_EQUAL (p.size(), 3);
287                 list<DCPTimePeriod>::const_iterator i = p.begin();
288                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 0), DCPTime(4000 + 48000)));
289                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 48000), DCPTime(4000 + 144000)));
290                 BOOST_CHECK (*i++ == DCPTimePeriod (DCPTime(4000 + 144000), DCPTime(4000 + 192000)));
291         }
292 }
293
294 /** Check reel split with a muxed video/audio source */
295 BOOST_AUTO_TEST_CASE (reels_test6)
296 {
297         shared_ptr<Film> film = new_test_film ("reels_test6");
298         film->set_name ("reels_test6");
299         film->set_container (Ratio::from_id ("185"));
300         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
301         shared_ptr<FFmpegContent> A (new FFmpegContent("test/data/test2.mp4"));
302         film->examine_and_add_content (A);
303         BOOST_REQUIRE (!wait_for_jobs ());
304
305         film->set_j2k_bandwidth (100000000);
306         film->set_reel_type (REELTYPE_BY_LENGTH);
307         /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */
308         film->set_reel_length (31253154);
309         film->make_dcp ();
310         BOOST_REQUIRE (!wait_for_jobs ());
311 }
312
313 /** Check the case where the last bit of audio hangs over the end of the video
314  *  and we are using REELTYPE_BY_VIDEO_CONTENT.
315  */
316 BOOST_AUTO_TEST_CASE (reels_test7)
317 {
318         shared_ptr<Film> film = new_test_film ("reels_test7");
319         film->set_name ("reels_test7");
320         film->set_container (Ratio::from_id ("185"));
321         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
322         shared_ptr<Content> A = content_factory("test/data/flat_red.png").front();
323         film->examine_and_add_content (A);
324         BOOST_REQUIRE (!wait_for_jobs ());
325         shared_ptr<Content> B = content_factory("test/data/awkward_length.wav").front();
326         film->examine_and_add_content (B);
327         BOOST_REQUIRE (!wait_for_jobs ());
328         film->set_video_frame_rate (24);
329         A->video->set_length (2 * 24);
330
331         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
332         BOOST_REQUIRE_EQUAL (film->reels().size(), 2);
333         BOOST_CHECK (film->reels().front() == DCPTimePeriod(DCPTime(0), DCPTime::from_frames(2 * 24, 24)));
334         BOOST_CHECK (film->reels().back() == DCPTimePeriod(DCPTime::from_frames(2 * 24, 24), DCPTime::from_frames(3 * 24 + 1, 24)));
335
336         film->make_dcp ();
337         BOOST_REQUIRE (!wait_for_jobs ());
338 }
339
340 /** Check a reels-related error; make_dcp() would raise a ProgrammingError */
341 BOOST_AUTO_TEST_CASE (reels_test8)
342 {
343         shared_ptr<Film> film = new_test_film ("reels_test8");
344         film->set_name ("reels_test8");
345         film->set_container (Ratio::from_id ("185"));
346         film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
347         shared_ptr<FFmpegContent> A (new FFmpegContent("test/data/test2.mp4"));
348         film->examine_and_add_content (A);
349         BOOST_REQUIRE (!wait_for_jobs ());
350
351         A->set_trim_end (ContentTime::from_seconds (1));
352         film->make_dcp ();
353         BOOST_REQUIRE (!wait_for_jobs ());
354 }
355
356 /** Check another reels-related error; make_dcp() would raise a ProgrammingError */
357 BOOST_AUTO_TEST_CASE (reels_test9)
358 {
359         shared_ptr<Film> film = new_test_film2("reels_test9a");
360         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
361         film->examine_and_add_content(A);
362         BOOST_REQUIRE(!wait_for_jobs());
363         A->video->set_length(5 * 24);
364         film->set_video_frame_rate(24);
365         film->make_dcp();
366         BOOST_REQUIRE(!wait_for_jobs());
367
368         shared_ptr<Film> film2 = new_test_film2("reels_test9b");
369         shared_ptr<DCPContent> B(new DCPContent(film->dir(film->dcp_name())));
370         film2->examine_and_add_content(B);
371         film2->examine_and_add_content(content_factory("test/data/dcp_sub4.xml").front());
372         B->set_reference_video(true);
373         B->set_reference_audio(true);
374         BOOST_REQUIRE(!wait_for_jobs());
375         film2->set_reel_type(REELTYPE_BY_VIDEO_CONTENT);
376         film2->write_metadata();
377         film2->make_dcp();
378         BOOST_REQUIRE(!wait_for_jobs());
379 }
380
381 /** Another reels-related error; make_dcp() would raise a ProgrammingError
382  *  in AudioBuffers::allocate due to an attempt to allocate a negatively-sized buffer.
383  *  This was triggered by a VF where there are referenced audio reels followed by
384  *  VF audio.  When the VF audio arrives the Writer did not correctly skip over the
385  *  referenced reels.
386  */
387 BOOST_AUTO_TEST_CASE (reels_test10)
388 {
389         /* Make the OV */
390         shared_ptr<Film> ov = new_test_film2("reels_test10_ov");
391         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
392         ov->examine_and_add_content (A);
393         BOOST_REQUIRE (!wait_for_jobs());
394         A->video->set_length (5 * 24);
395
396         shared_ptr<FFmpegContent> B(new FFmpegContent("test/data/flat_red.png"));
397         ov->examine_and_add_content (B);
398         BOOST_REQUIRE (!wait_for_jobs());
399         B->video->set_length (5 * 24);
400
401         ov->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
402         ov->make_dcp ();
403         BOOST_REQUIRE (!wait_for_jobs());
404         ov->write_metadata ();
405
406         /* Now try to make the VF; this used to fail */
407         shared_ptr<Film> vf = new_test_film2("reels_test10_vf");
408         shared_ptr<DCPContent> ov_dcp(new DCPContent(ov->dir(ov->dcp_name())));
409         vf->examine_and_add_content (ov_dcp);
410         BOOST_REQUIRE (!wait_for_jobs());
411         vf->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
412         ov_dcp->set_reference_video (true);
413         ov_dcp->set_reference_audio (true);
414         vf->examine_and_add_content (content_factory("test/data/15s.srt").front());
415         BOOST_REQUIRE (!wait_for_jobs());
416
417         vf->make_dcp ();
418         BOOST_REQUIRE (!wait_for_jobs());
419         vf->write_metadata ();
420 }
421
422 /** Another reels error; REELTYPE_BY_VIDEO_CONTENT when the first content is not
423  *  at time 0.
424  */
425 BOOST_AUTO_TEST_CASE (reels_test11)
426 {
427         shared_ptr<Film> film = new_test_film2 ("reels_test11");
428         film->set_video_frame_rate (24);
429         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
430         film->examine_and_add_content (A);
431         BOOST_REQUIRE (!wait_for_jobs());
432         A->video->set_length (240);
433         A->set_video_frame_rate (24);
434         A->set_position (film, DCPTime::from_seconds(1));
435         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
436         film->make_dcp ();
437         BOOST_REQUIRE (!wait_for_jobs());
438         BOOST_CHECK_EQUAL (A->position().get(), DCPTime::from_seconds(1).get());
439         BOOST_CHECK_EQUAL (A->end(film).get(), DCPTime::from_seconds(1 + 10).get());
440
441         list<DCPTimePeriod> r = film->reels ();
442         BOOST_CHECK_EQUAL (r.size(), 2);
443         BOOST_CHECK_EQUAL (r.front().from.get(), 0);
444         BOOST_CHECK_EQUAL (r.front().to.get(), DCPTime::from_seconds(1).get());
445         BOOST_CHECK_EQUAL (r.back().from.get(), DCPTime::from_seconds(1).get());
446         BOOST_CHECK_EQUAL (r.back().to.get(), DCPTime::from_seconds(1 + 10).get());
447 }
448
449 /** For VFs to work right we have to make separate reels for empty bits between
450  *  video content.
451  */
452 BOOST_AUTO_TEST_CASE (reels_test12)
453 {
454         shared_ptr<Film> film = new_test_film2 ("reels_test12");
455         film->set_video_frame_rate (24);
456         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
457         film->set_sequence (false);
458
459         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
460         film->examine_and_add_content (A);
461         BOOST_REQUIRE (!wait_for_jobs());
462         A->video->set_length (240);
463         A->set_video_frame_rate (24);
464         A->set_position (film, DCPTime::from_seconds(1));
465
466         shared_ptr<FFmpegContent> B(new FFmpegContent("test/data/flat_red.png"));
467         film->examine_and_add_content (B);
468         BOOST_REQUIRE (!wait_for_jobs());
469         B->video->set_length (120);
470         B->set_video_frame_rate (24);
471         B->set_position (film, DCPTime::from_seconds(14));
472
473         list<DCPTimePeriod> r = film->reels ();
474         BOOST_REQUIRE_EQUAL (r.size(), 4);
475         list<DCPTimePeriod>::const_iterator i = r.begin ();
476
477         BOOST_CHECK_EQUAL (i->from.get(), 0);
478         BOOST_CHECK_EQUAL (i->to.get(),   DCPTime::from_seconds(1).get());
479         ++i;
480         BOOST_CHECK_EQUAL (i->from.get(), DCPTime::from_seconds(1).get());
481         BOOST_CHECK_EQUAL (i->to.get(),   DCPTime::from_seconds(11).get());
482         ++i;
483         BOOST_CHECK_EQUAL (i->from.get(), DCPTime::from_seconds(11).get());
484         BOOST_CHECK_EQUAL (i->to.get(),   DCPTime::from_seconds(14).get());
485         ++i;
486         BOOST_CHECK_EQUAL (i->from.get(), DCPTime::from_seconds(14).get());
487         BOOST_CHECK_EQUAL (i->to.get(),   DCPTime::from_seconds(19).get());
488 }
489
490 static void
491 no_op ()
492 {
493
494 }
495
496 static void
497 dump_notes (list<dcp::VerificationNote> const & notes)
498 {
499         BOOST_FOREACH (dcp::VerificationNote i, notes) {
500                 std::cout << dcp::note_to_string(i) << "\n";
501         }
502 }
503
504
505 /** Using less than 1 second's worth of content should not result in a reel
506  *  of less than 1 second's duration.
507  */
508 BOOST_AUTO_TEST_CASE (reels_should_not_be_short1)
509 {
510         shared_ptr<Film> film = new_test_film2 ("reels_should_not_be_short1");
511         film->set_video_frame_rate (24);
512
513         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
514         film->examine_and_add_content (A);
515         BOOST_REQUIRE (!wait_for_jobs());
516         A->video->set_length (23);
517
518         shared_ptr<FFmpegContent> B(new FFmpegContent("test/data/flat_red.png"));
519         film->examine_and_add_content (B);
520         BOOST_REQUIRE (!wait_for_jobs());
521         B->video->set_length (23);
522         B->set_position (film, DCPTime::from_frames(23, 24));
523
524         film->make_dcp ();
525         BOOST_REQUIRE (!wait_for_jobs());
526
527         vector<boost::filesystem::path> dirs;
528         dirs.push_back (film->dir(film->dcp_name(false)));
529         list<dcp::VerificationNote> const notes = dcp::verify(dirs, boost::bind(&no_op), boost::bind(&no_op), TestPaths::xsd);
530         dump_notes (notes);
531         BOOST_REQUIRE (notes.empty());
532 }
533
534 /** Leaving less than 1 second's gap between two pieces of content with
535  *  REELTYPE_BY_VIDEO_CONTENT should not make a <1s reel.
536  */
537 BOOST_AUTO_TEST_CASE (reels_should_not_be_short2)
538 {
539         shared_ptr<Film> film = new_test_film2 ("reels_should_not_be_short2");
540         film->set_video_frame_rate (24);
541         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
542
543         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
544         film->examine_and_add_content (A);
545         BOOST_REQUIRE (!wait_for_jobs());
546         A->video->set_length (240);
547
548         shared_ptr<FFmpegContent> B(new FFmpegContent("test/data/flat_red.png"));
549         film->examine_and_add_content (B);
550         BOOST_REQUIRE (!wait_for_jobs());
551         B->video->set_length (240);
552         B->set_position (film, DCPTime::from_seconds(10.2));
553
554         film->make_dcp ();
555         BOOST_REQUIRE (!wait_for_jobs());
556
557         vector<boost::filesystem::path> dirs;
558         dirs.push_back (film->dir(film->dcp_name(false)));
559         list<dcp::VerificationNote> const notes = dcp::verify(dirs, boost::bind(&no_op), boost::bind(&no_op), TestPaths::xsd);
560         dump_notes (notes);
561         BOOST_REQUIRE (notes.empty());
562 }
563
564 /** Setting REELTYPE_BY_LENGTH and using a small length value should not make
565  *  <1s reels.
566  */
567 BOOST_AUTO_TEST_CASE (reels_should_not_be_short3)
568 {
569         shared_ptr<Film> film = new_test_film2 ("reels_should_not_be_short3");
570         film->set_video_frame_rate (24);
571         film->set_reel_type (REELTYPE_BY_LENGTH);
572         film->set_reel_length (1024 * 1024 * 10);
573
574         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
575         film->examine_and_add_content (A);
576         BOOST_REQUIRE (!wait_for_jobs());
577         A->video->set_length (240);
578
579         film->make_dcp ();
580         BOOST_REQUIRE (!wait_for_jobs());
581
582         vector<boost::filesystem::path> dirs;
583         list<dcp::VerificationNote> const notes = dcp::verify(dirs, boost::bind(&no_op), boost::bind(&no_op), TestPaths::xsd);
584         dump_notes (notes);
585         BOOST_REQUIRE (notes.empty());
586 }
587
588 /** Having one piece of content less than 1s long in REELTYPE_BY_VIDEO_CONTENT
589  *  should not make a reel less than 1s long.
590  */
591 BOOST_AUTO_TEST_CASE (reels_should_not_be_short4)
592 {
593         shared_ptr<Film> film = new_test_film2 ("reels_should_not_be_short4");
594         film->set_video_frame_rate (24);
595         film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
596
597         shared_ptr<FFmpegContent> A(new FFmpegContent("test/data/flat_red.png"));
598         film->examine_and_add_content (A);
599         BOOST_REQUIRE (!wait_for_jobs());
600         A->video->set_length (240);
601
602         shared_ptr<FFmpegContent> B(new FFmpegContent("test/data/flat_red.png"));
603         film->examine_and_add_content (B);
604         BOOST_REQUIRE (!wait_for_jobs());
605         B->video->set_length (23);
606         B->set_position (film, DCPTime::from_frames(240, 24));
607
608         film->make_dcp ();
609         BOOST_REQUIRE (!wait_for_jobs());
610
611         vector<boost::filesystem::path> dirs;
612         dirs.push_back (film->dir(film->dcp_name(false)));
613         list<dcp::VerificationNote> const notes = dcp::verify(dirs, boost::bind(&no_op), boost::bind(&no_op), TestPaths::xsd);
614         dump_notes (notes);
615         BOOST_REQUIRE (notes.empty());
616 }
617