Move ScopeGuard into libdcp.
[dcpomatic.git] / test / vf_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/vf_Test.cc
23  *  @brief Various VF-related tests.
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/examine_content_job.h"
32 #include "lib/ffmpeg_content.h"
33 #include "lib/film.h"
34 #include "lib/job_manager.h"
35 #include "lib/make_dcp.h"
36 #include "lib/player.h"
37 #include "lib/ratio.h"
38 #include "lib/text_content.h"
39 #include "lib/referenced_reel_asset.h"
40 #include "lib/video_content.h"
41 #include "test.h"
42 #include <dcp/cpl.h>
43 #include <dcp/mono_picture_asset.h>
44 #include <dcp/picture_asset_writer.h>
45 #include <dcp/reel.h>
46 #include <dcp/reel_mono_picture_asset.h>
47 #include <dcp/reel_sound_asset.h>
48 #include <dcp/reel_smpte_subtitle_asset.h>
49 #include <dcp/smpte_subtitle_asset.h>
50 #include <dcp/subtitle_string.h>
51 #include <boost/test/unit_test.hpp>
52 #include <iostream>
53
54
55 using std::cout;
56 using std::dynamic_pointer_cast;
57 using std::list;
58 using std::make_shared;
59 using std::shared_ptr;
60 using std::string;
61 using std::vector;
62 using namespace dcpomatic;
63
64
65 /** Test the logic which decides whether a DCP can be referenced or not */
66 BOOST_AUTO_TEST_CASE (vf_test1)
67 {
68         auto film = new_test_film ("vf_test1");
69         film->set_interop (false);
70         auto dcp = make_shared<DCPContent>("test/data/reels_test2");
71         film->examine_and_add_content (dcp);
72         BOOST_REQUIRE (!wait_for_jobs());
73
74         /* Multi-reel DCP can't be referenced if we are using a single reel for the project */
75         film->set_reel_type (ReelType::SINGLE);
76         string why_not;
77         BOOST_CHECK (!dcp->can_reference_video(film, why_not));
78         BOOST_CHECK (!dcp->can_reference_audio(film, why_not));
79         BOOST_CHECK (!dcp->can_reference_text(film, TextType::OPEN_SUBTITLE, why_not));
80         BOOST_CHECK (!dcp->can_reference_text(film, TextType::CLOSED_CAPTION, why_not));
81
82         /* Multi-reel DCP can be referenced if we are using by-video-content */
83         film->set_reel_type (ReelType::BY_VIDEO_CONTENT);
84         BOOST_CHECK (dcp->can_reference_video(film, why_not));
85         BOOST_CHECK (dcp->can_reference_audio(film, why_not));
86         /* (but reels_test2 has no texts to reference) */
87         BOOST_CHECK (!dcp->can_reference_text(film, TextType::OPEN_SUBTITLE, why_not));
88         BOOST_CHECK (!dcp->can_reference_text(film, TextType::CLOSED_CAPTION, why_not));
89
90         auto other = make_shared<FFmpegContent>("test/data/test.mp4");
91         film->examine_and_add_content (other);
92         BOOST_REQUIRE (!wait_for_jobs());
93         BOOST_CHECK (!other->audio);
94
95         /* Not possible if there is overlap; we only check video here as that's all test.mp4 has */
96         other->set_position (film, DCPTime());
97         BOOST_CHECK (!dcp->can_reference_video(film, why_not));
98
99         /* This should not be considered an overlap */
100         other->set_position (film, dcp->end(film));
101         BOOST_CHECK (dcp->can_reference_video(film, why_not));
102         BOOST_CHECK (dcp->can_reference_audio(film, why_not));
103         /* (reels_test2 has no texts to reference) */
104         BOOST_CHECK (!dcp->can_reference_text(film, TextType::OPEN_SUBTITLE, why_not));
105         BOOST_CHECK (!dcp->can_reference_text(film, TextType::CLOSED_CAPTION, why_not));
106 }
107
108
109 /** Make a OV with video and audio and a VF referencing the OV and adding subs */
110 BOOST_AUTO_TEST_CASE (vf_test2)
111 {
112         /* Make the OV */
113         auto ov = new_test_film ("vf_test2_ov");
114         ov->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
115         ov->set_name ("vf_test2_ov");
116         auto video = content_factory("test/data/flat_red.png")[0];
117         ov->examine_and_add_content (video);
118         BOOST_REQUIRE (!wait_for_jobs());
119         video->video->set_length (24 * 5);
120         auto audio = content_factory("test/data/white.wav")[0];
121         ov->examine_and_add_content (audio);
122         BOOST_REQUIRE (!wait_for_jobs());
123         make_and_verify_dcp (ov);
124
125         /* Make the VF */
126         auto vf = new_test_film ("vf_test2_vf");
127         vf->set_name ("vf_test2_vf");
128         vf->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
129         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
130         auto dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
131         vf->examine_and_add_content (dcp);
132         BOOST_REQUIRE (!wait_for_jobs());
133         dcp->set_reference_video (true);
134         dcp->set_reference_audio (true);
135         auto sub = content_factory("test/data/subrip4.srt")[0];
136         vf->examine_and_add_content (sub);
137         BOOST_REQUIRE (!wait_for_jobs());
138         make_and_verify_dcp (
139                 vf,
140                 {
141                         dcp::VerificationNote::Code::EXTERNAL_ASSET,
142                         dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
143                         dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME,
144                         dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION
145                 });
146
147         dcp::DCP ov_c (ov->dir(ov->dcp_name()));
148         ov_c.read ();
149         BOOST_REQUIRE_EQUAL (ov_c.cpls().size(), 1U);
150         BOOST_REQUIRE_EQUAL (ov_c.cpls()[0]->reels().size(), 1U);
151         BOOST_REQUIRE (ov_c.cpls()[0]->reels()[0]->main_picture());
152         string const pic_id = ov_c.cpls()[0]->reels()[0]->main_picture()->id();
153         BOOST_REQUIRE (ov_c.cpls()[0]->reels()[0]->main_sound());
154         string const sound_id = ov_c.cpls()[0]->reels()[0]->main_sound()->id();
155         BOOST_REQUIRE (!ov_c.cpls()[0]->reels()[0]->main_subtitle());
156
157         dcp::DCP vf_c (vf->dir(vf->dcp_name()));
158         vf_c.read ();
159         BOOST_REQUIRE_EQUAL (vf_c.cpls().size(), 1U);
160         BOOST_REQUIRE_EQUAL (vf_c.cpls()[0]->reels().size(), 1U);
161         BOOST_REQUIRE (vf_c.cpls()[0]->reels()[0]->main_picture());
162         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_picture()->id(), pic_id);
163         BOOST_REQUIRE (vf_c.cpls()[0]->reels()[0]->main_sound());
164         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_sound()->id(), sound_id);
165         BOOST_REQUIRE (vf_c.cpls()[0]->reels()[0]->main_subtitle());
166 }
167
168
169 /** Test creation of a VF using a trimmed OV; the output should have entry point /
170  *  duration altered to effect the trimming.
171  */
172 BOOST_AUTO_TEST_CASE (vf_test3)
173 {
174         /* Make the OV */
175         auto ov = new_test_film ("vf_test3_ov");
176         ov->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
177         ov->set_name ("vf_test3_ov");
178         auto video = content_factory("test/data/flat_red.png")[0];
179         ov->examine_and_add_content (video);
180         BOOST_REQUIRE (!wait_for_jobs());
181         video->video->set_length (24 * 5);
182         auto audio = content_factory("test/data/white.wav")[0];
183         ov->examine_and_add_content (audio);
184         BOOST_REQUIRE (!wait_for_jobs());
185         make_and_verify_dcp (ov);
186
187         /* Make the VF */
188         auto vf = new_test_film ("vf_test3_vf");
189         vf->set_name ("vf_test3_vf");
190         vf->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
191         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
192         auto dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
193         BOOST_REQUIRE (dcp);
194         dcp->set_trim_start(vf, ContentTime::from_seconds (1));
195         dcp->set_trim_end (ContentTime::from_seconds (1));
196         vf->examine_and_add_content (dcp);
197         BOOST_REQUIRE (!wait_for_jobs());
198         dcp->set_reference_video (true);
199         dcp->set_reference_audio (true);
200         make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET});
201
202         dcp::DCP vf_c (vf->dir(vf->dcp_name()));
203         vf_c.read ();
204         BOOST_REQUIRE_EQUAL (vf_c.cpls().size(), 1U);
205         BOOST_REQUIRE_EQUAL (vf_c.cpls()[0]->reels().size(), 1U);
206         BOOST_REQUIRE (vf_c.cpls()[0]->reels()[0]->main_picture());
207         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_picture()->entry_point().get_value_or(0), 24);
208         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_picture()->actual_duration(), 72);
209         BOOST_REQUIRE (vf_c.cpls()[0]->reels()[0]->main_sound());
210         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_sound()->entry_point().get_value_or(0), 24);
211         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels()[0]->main_sound()->actual_duration(), 72);
212 }
213
214
215 /** Make a OV with video and audio and a VF referencing the OV and adding some more video */
216 BOOST_AUTO_TEST_CASE (vf_test4)
217 {
218         /* Make the OV */
219         auto ov = new_test_film ("vf_test4_ov");
220         ov->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
221         ov->set_name ("vf_test4_ov");
222         auto video = content_factory("test/data/flat_red.png")[0];
223         ov->examine_and_add_content (video);
224         BOOST_REQUIRE (!wait_for_jobs());
225         video->video->set_length (24 * 5);
226         auto audio = content_factory("test/data/white.wav")[0];
227         ov->examine_and_add_content (audio);
228         BOOST_REQUIRE (!wait_for_jobs());
229         make_and_verify_dcp (ov);
230
231         /* Make the VF */
232         auto vf = new_test_film ("vf_test4_vf");
233         vf->set_name ("vf_test4_vf");
234         vf->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
235         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
236         vf->set_sequence (false);
237         auto dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
238         BOOST_REQUIRE (dcp);
239         vf->examine_and_add_content (dcp);
240         BOOST_REQUIRE (!wait_for_jobs());
241         dcp->set_position(vf, DCPTime::from_seconds(10));
242         dcp->set_reference_video (true);
243         dcp->set_reference_audio (true);
244         auto more_video = content_factory("test/data/flat_red.png")[0];
245         vf->examine_and_add_content (more_video);
246         BOOST_REQUIRE (!wait_for_jobs());
247         more_video->set_position (vf, DCPTime());
248         vf->write_metadata ();
249         make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET});
250
251         dcp::DCP ov_c (ov->dir(ov->dcp_name()));
252         ov_c.read ();
253         BOOST_REQUIRE_EQUAL (ov_c.cpls().size(), 1U);
254         BOOST_REQUIRE_EQUAL (ov_c.cpls()[0]->reels().size(), 1U);
255         BOOST_REQUIRE (ov_c.cpls()[0]->reels()[0]->main_picture());
256         string const pic_id = ov_c.cpls()[0]->reels()[0]->main_picture()->id();
257         BOOST_REQUIRE (ov_c.cpls()[0]->reels()[0]->main_sound());
258         string const sound_id = ov_c.cpls()[0]->reels()[0]->main_sound()->id();
259         BOOST_REQUIRE (!ov_c.cpls()[0]->reels()[0]->main_subtitle());
260
261         dcp::DCP vf_c (vf->dir (vf->dcp_name ()));
262         vf_c.read ();
263         BOOST_REQUIRE_EQUAL (vf_c.cpls().size(), 1U);
264         BOOST_REQUIRE_EQUAL (vf_c.cpls()[0]->reels().size(), 2U);
265         BOOST_REQUIRE (vf_c.cpls()[0]->reels().back()->main_picture());
266         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels().back()->main_picture()->id(), pic_id);
267         BOOST_REQUIRE (vf_c.cpls()[0]->reels().back()->main_sound());
268         BOOST_CHECK_EQUAL (vf_c.cpls()[0]->reels().back()->main_sound()->id(), sound_id);
269 }
270
271
272 /** Test bug #1495 */
273 BOOST_AUTO_TEST_CASE (vf_test5)
274 {
275         /* Make the OV */
276         auto ov = new_test_film ("vf_test5_ov");
277         ov->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
278         ov->set_reel_type (ReelType::BY_VIDEO_CONTENT);
279         for (int i = 0; i < 3; ++i) {
280                 auto video = content_factory("test/data/flat_red.png")[0];
281                 ov->examine_and_add_content (video);
282                 BOOST_REQUIRE (!wait_for_jobs());
283                 video->video->set_length (24 * 10);
284         }
285
286         BOOST_REQUIRE (!wait_for_jobs());
287         make_and_verify_dcp (ov);
288
289         /* Make the VF */
290         auto vf = new_test_film ("vf_test5_vf");
291         vf->set_name ("vf_test5_vf");
292         vf->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
293         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
294         vf->set_sequence (false);
295         auto dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
296         BOOST_REQUIRE (dcp);
297         vf->examine_and_add_content (dcp);
298         BOOST_REQUIRE (!wait_for_jobs());
299         dcp->set_reference_video (true);
300         dcp->set_reference_audio (true);
301         dcp->set_trim_end (ContentTime::from_seconds(15));
302         make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET});
303
304         /* Check that the selected reel assets are right */
305         auto a = get_referenced_reel_assets(vf, vf->playlist());
306         BOOST_REQUIRE_EQUAL (a.size(), 4U);
307         auto i = a.begin();
308         BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(0), DCPTime(960000)));
309         ++i;
310         BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(0), DCPTime(960000)));
311         ++i;
312         BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(960000), DCPTime(1440000)));
313         ++i;
314         BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(960000), DCPTime(1440000)));
315         ++i;
316 }
317
318
319 /** Test bug #1528 */
320 BOOST_AUTO_TEST_CASE (vf_test6)
321 {
322         /* Make the OV */
323         auto ov = new_test_film ("vf_test6_ov");
324         ov->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
325         ov->set_reel_type (ReelType::BY_VIDEO_CONTENT);
326         auto video = content_factory("test/data/flat_red.png")[0];
327         ov->examine_and_add_content (video);
328         BOOST_REQUIRE (!wait_for_jobs());
329         video->video->set_length (24 * 10);
330         make_and_verify_dcp (ov);
331
332         /* Make the VF */
333         auto vf = new_test_film ("vf_test6_vf");
334         vf->set_name ("vf_test6_vf");
335         vf->set_dcp_content_type (DCPContentType::from_isdcf_name("TST"));
336         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
337         vf->set_sequence (false);
338         auto dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
339         vf->examine_and_add_content (dcp);
340         BOOST_REQUIRE (!wait_for_jobs());
341         dcp->set_reference_video (true);
342         dcp->set_reference_audio (true);
343
344         auto sub = content_factory("test/data/15s.srt")[0];
345         vf->examine_and_add_content (sub);
346         BOOST_REQUIRE (!wait_for_jobs());
347
348         make_and_verify_dcp (
349                 vf,
350                 {
351                         dcp::VerificationNote::Code::EXTERNAL_ASSET,
352                         dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
353                         dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
354                 });
355 }
356
357
358 /** Test bug #1643 (the second part; referring fails if there are gaps) */
359 BOOST_AUTO_TEST_CASE (vf_test7)
360 {
361         /* First OV */
362         auto ov1 = new_test_film2 ("vf_test7_ov1", {content_factory("test/data/flat_red.png")[0]});
363         ov1->set_video_frame_rate (24);
364         make_and_verify_dcp (ov1);
365
366         /* Second OV */
367         auto ov2 = new_test_film2 ("vf_test7_ov2", {content_factory("test/data/flat_red.png")[0]});
368         ov2->set_video_frame_rate (24);
369         make_and_verify_dcp (ov2);
370
371         /* VF */
372         auto ov1_dcp = make_shared<DCPContent>(ov1->dir(ov1->dcp_name()));
373         auto ov2_dcp = make_shared<DCPContent>(ov2->dir(ov2->dcp_name()));
374         auto vf = new_test_film2 ("vf_test7_vf", {ov1_dcp, ov2_dcp});
375         vf->set_reel_type (ReelType::BY_VIDEO_CONTENT);
376         ov1_dcp->set_reference_video (true);
377         ov2_dcp->set_reference_video (true);
378         ov1_dcp->set_position (vf, DCPTime::from_seconds(1));
379         ov2_dcp->set_position (vf, DCPTime::from_seconds(20));
380         vf->write_metadata ();
381         make_and_verify_dcp (vf);
382 }
383
384
385 /** Test bug #2116 */
386 BOOST_AUTO_TEST_CASE (test_vf_with_trimmed_multi_reel_dcp)
387 {
388         /* Make an OV with 3 reels */
389         std::vector<std::shared_ptr<Content>> ov_content;
390         for (int i = 0; i < 3; ++i) {
391                 auto c = content_factory("test/data/flat_red.png")[0];
392                 c->video->set_length(240);
393                 ov_content.push_back(c);
394         }
395         auto ov = new_test_film2 ("test_vf_with_trimmed_multi_reel_dcp_ov", ov_content);
396         ov->set_reel_type(ReelType::BY_VIDEO_CONTENT);
397         make_and_verify_dcp (ov);
398
399         /* Make a VF with a specific arrangement */
400         auto vf_image = content_factory("test/data/flat_red.png")[0];
401         auto vf_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
402         auto vf = new_test_film2 ("test_vf_with_trimmed_multi_reel_dcp_vf", { vf_image, vf_dcp });
403         vf->set_reel_type(ReelType::BY_VIDEO_CONTENT);
404         vf_dcp->set_reference_video(true);
405         vf_dcp->set_reference_audio(true);
406         vf_dcp->set_trim_start(vf, ContentTime::from_seconds(10));
407         vf_dcp->set_position(vf, DCPTime::from_seconds(10));
408         make_and_verify_dcp (vf, { dcp::VerificationNote::Code::EXTERNAL_ASSET });
409 }
410
411
412 /** Test bug #2599: unable to reference open subtitles in an OV when creating a VF that adds closed captions */
413 BOOST_AUTO_TEST_CASE(test_referencing_ov_with_subs_when_adding_ccaps)
414 {
415         string const name("test_referencing_ov_with_subs_when_adding_ccaps");
416         auto subs = content_factory("test/data/15s.srt");
417         auto ov = new_test_film2(name + "_ov", subs);
418         make_and_verify_dcp(
419                 ov,
420                 {
421                         dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
422                         dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME,
423                         dcp::VerificationNote::Code::MISSING_CPL_METADATA
424                 });
425
426         auto ccaps = content_factory("test/data/15s.srt")[0];
427         auto ov_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name(false)));
428         auto vf = new_test_film2(name + "_vf", { ov_dcp, ccaps });
429         ccaps->text[0]->set_type(TextType::CLOSED_CAPTION);
430
431         string why_not;
432         BOOST_CHECK(ov_dcp->can_reference_text(vf, TextType::OPEN_SUBTITLE, why_not));
433         std::cout << why_not << "\n";
434 }
435
436
437 BOOST_AUTO_TEST_CASE(test_duplicate_font_id_in_vf)
438 {
439         string const name("test_duplicate_font_id_in_vf");
440         auto subs = content_factory("test/data/15s.srt");
441         auto ov = new_test_film2(name + "_ov", subs);
442         make_and_verify_dcp(
443                 ov,
444                 {
445                         dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
446                         dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME,
447                         dcp::VerificationNote::Code::MISSING_CPL_METADATA
448                 });
449
450         auto ccaps = content_factory("test/data/15s.srt")[0];
451         auto ov_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name(false)));
452         auto vf = new_test_film2(name + "_vf", { ov_dcp, ccaps });
453         ov_dcp->set_reference_audio(true);
454         ov_dcp->set_reference_video(true);
455         ov_dcp->text[0]->set_use(true);
456         ccaps->text[0]->set_type(TextType::CLOSED_CAPTION);
457         string why_not;
458         BOOST_CHECK_MESSAGE(ov_dcp->can_reference_text(vf, TextType::OPEN_SUBTITLE, why_not), why_not);
459         ov_dcp->set_reference_text(TextType::OPEN_SUBTITLE, true);
460         vf->write_metadata();
461         make_dcp(vf, TranscodeJob::ChangedBehaviour::IGNORE);
462         BOOST_REQUIRE(!wait_for_jobs());
463
464         auto vf_dcp = make_shared<DCPContent>(vf->dir(vf->dcp_name(false)));
465
466         auto test = new_test_film2(name + "_test", { vf_dcp });
467         vf_dcp->add_ov(ov->dir(ov->dcp_name(false)));
468         JobManager::instance()->add(make_shared<ExamineContentJob>(test, vf_dcp));
469         BOOST_CHECK(!wait_for_jobs());
470
471         make_and_verify_dcp(
472                 test,
473                 {
474                         dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
475                         dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME,
476                         dcp::VerificationNote::Code::MISSING_CPL_METADATA,
477                 });
478 }
479
480
481 BOOST_AUTO_TEST_CASE(test_referencing_ov_with_missing_subtitle_in_some_reels)
482 {
483         auto const path = boost::filesystem::path("build/test/test_referencing_ov_with_missing_subtitle_in_some_reels");
484         boost::filesystem::remove_all(path);
485
486         boost::filesystem::create_directories(path / "ov");
487         dcp::DCP ov(path / "ov");
488
489         auto make_picture = [path](string filename) {
490                 auto pic = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
491                 auto writer = pic->start_write(path / "ov" / filename, dcp::PictureAsset::Behaviour::MAKE_NEW);
492                 auto frame = dcp::ArrayData("test/data/picture.j2c");
493                 for (int i = 0; i < 240; ++i) {
494                         writer->write(frame);
495                 }
496                 writer->finalize();
497                 return pic;
498         };
499
500         auto pic1 = make_picture("pic1.mxf");
501         auto pic2 = make_picture("pic2.mxf");
502
503         auto sub1 = make_shared<dcp::SMPTESubtitleAsset>();
504
505         sub1->add(std::make_shared<dcp::SubtitleString>(
506                 boost::optional<string>(), false, false, false, dcp::Colour(255, 255, 255),
507                 42, 1, dcp::Time(0, 0, 5, 0, 24), dcp::Time(0, 0, 9, 0, 24),
508                 0, dcp::HAlign::CENTER,
509                 0, dcp::VAlign::CENTER,
510                 0, dcp::Direction::LTR,
511                 "Hello",
512                 dcp::Effect::NONE, dcp::Colour(0, 0, 0),
513                 dcp::Time{}, dcp::Time{},
514                 0, vector<dcp::Ruby>{}
515                 ));
516         sub1->write(path / "ov" / "sub.mxf");
517
518         auto reel1_pic = make_shared<dcp::ReelMonoPictureAsset>(pic1, 0);
519         auto reel1_sub = make_shared<dcp::ReelSMPTESubtitleAsset>(sub1, dcp::Fraction(24, 1), 240, 0);
520
521         auto reel2_pic = make_shared<dcp::ReelMonoPictureAsset>(pic1, 0);
522
523         auto reel1 = make_shared<dcp::Reel>(reel1_pic, shared_ptr<dcp::ReelSoundAsset>(), reel1_sub);
524         auto reel2 = make_shared<dcp::Reel>(reel2_pic);
525
526         auto cpl = make_shared<dcp::CPL>("Test CPL", dcp::ContentKind::FEATURE, dcp::Standard::SMPTE);
527         cpl->add(reel1);
528         cpl->add(reel2);
529
530         ov.add(cpl);
531         ov.write_xml();
532
533         auto dcp_ov = make_shared<DCPContent>(path / "ov");
534         auto vf = make_shared<Film>(path / "vf");
535         vf->set_dcp_content_type(DCPContentType::from_isdcf_name("TST"));
536         vf->set_container(Ratio::from_id("185"));
537         vf->write_metadata();
538         vf->examine_and_add_content(dcp_ov);
539         BOOST_REQUIRE(!wait_for_jobs());
540         vf->set_reel_type(ReelType::BY_VIDEO_CONTENT);
541         dcp_ov->set_reference_video(true);
542         dcp_ov->set_reference_text(TextType::OPEN_SUBTITLE, true);
543
544         vf->write_metadata();
545         make_dcp(vf, TranscodeJob::ChangedBehaviour::IGNORE);
546         BOOST_REQUIRE(!wait_for_jobs());
547
548         vector<dcp::VerificationNote::Code> ignore = {
549                 dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE,
550                 dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME,
551                 dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING,
552                 dcp::VerificationNote::Code::EXTERNAL_ASSET,
553         };
554
555         verify_dcp(vf->dir(vf->dcp_name()), ignore);
556 }
557