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