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