2 Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp 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.
11 libdcp 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.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
38 #include "reel_mono_picture_asset.h"
39 #include "reel_sound_asset.h"
42 #include "openjpeg_image.h"
43 #include "mono_picture_asset.h"
44 #include "stereo_picture_asset.h"
45 #include "mono_picture_asset_writer.h"
46 #include "interop_subtitle_asset.h"
47 #include "smpte_subtitle_asset.h"
48 #include "reel_closed_caption_asset.h"
49 #include "reel_stereo_picture_asset.h"
50 #include "reel_subtitle_asset.h"
51 #include "reel_markers_asset.h"
52 #include "compose.hpp"
54 #include <boost/test/unit_test.hpp>
55 #include <boost/foreach.hpp>
56 #include <boost/algorithm/string.hpp>
65 using std::make_shared;
66 using boost::optional;
67 using std::shared_ptr;
70 static list<pair<string, optional<boost::filesystem::path>>> stages;
71 static string const dcp_test1_pkl = "pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml";
72 static string const dcp_test1_cpl = "cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
75 stage (string s, optional<boost::filesystem::path> p)
77 stages.push_back (make_pair (s, p));
87 prepare_directory (boost::filesystem::path path)
89 using namespace boost::filesystem;
91 create_directories (path);
95 static vector<boost::filesystem::path>
96 setup (int reference_number, int verify_test_number)
98 prepare_directory (dcp::String::compose("build/test/verify_test%1", verify_test_number));
99 for (auto i: boost::filesystem::directory_iterator(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number))) {
100 boost::filesystem::copy_file (i.path(), dcp::String::compose("build/test/verify_test%1", verify_test_number) / i.path().filename());
103 return { dcp::String::compose("build/test/verify_test%1", verify_test_number) };
110 write_dcp_with_single_asset (boost::filesystem::path dir, shared_ptr<dcp::ReelAsset> reel_asset, dcp::Standard standard = dcp::SMPTE)
112 auto reel = make_shared<dcp::Reel>();
113 reel->add (reel_asset);
114 reel->add (simple_markers());
116 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
118 auto dcp = make_shared<dcp::DCP>(dir);
120 dcp->write_xml (standard);
124 /** Class that can alter a file by searching and replacing strings within it.
125 * On destruction modifies the file whose name was given to the constructor.
130 Editor (boost::filesystem::path path)
133 _content = dcp::file_to_string (_path);
138 auto f = fopen(_path.string().c_str(), "w");
140 fwrite (_content.c_str(), _content.length(), 1, f);
144 void replace (string a, string b)
146 auto old_content = _content;
147 boost::algorithm::replace_all (_content, a, b);
148 BOOST_REQUIRE (_content != old_content);
151 void delete_lines (string from, string to)
153 vector<string> lines;
154 boost::algorithm::split (lines, _content, boost::is_any_of("\r\n"), boost::token_compress_on);
155 bool deleting = false;
156 auto old_content = _content;
158 for (auto i: lines) {
159 if (i.find(from) != string::npos) {
163 _content += i + "\n";
165 if (deleting && i.find(to) != string::npos) {
169 BOOST_REQUIRE (_content != old_content);
173 boost::filesystem::path _path;
174 std::string _content;
180 dump_notes (vector<dcp::VerificationNote> const & notes)
182 for (auto i: notes) {
183 std::cout << dcp::note_to_string(i) << "\n";
190 check_verify_result (vector<boost::filesystem::path> dir, vector<dcp::VerificationNote> test_notes)
192 auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
193 BOOST_REQUIRE_EQUAL (notes.size(), test_notes.size());
199 check_verify_result_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, vector<dcp::VerificationNote::Code> codes)
201 auto directories = setup (1, n);
205 e.replace (from, to);
208 auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
210 BOOST_REQUIRE_EQUAL (notes.size(), codes.size());
211 auto i = notes.begin();
212 auto j = codes.begin();
213 while (i != notes.end()) {
214 BOOST_CHECK_EQUAL (i->code(), *j);
221 /* Check DCP as-is (should be OK) */
222 BOOST_AUTO_TEST_CASE (verify_test1)
225 auto directories = setup (1, 1);
226 auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
228 boost::filesystem::path const cpl_file = boost::filesystem::path("build") / "test" / "verify_test1" / dcp_test1_cpl;
229 boost::filesystem::path const pkl_file = boost::filesystem::path("build") / "test" / "verify_test1" / dcp_test1_pkl;
230 boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
232 auto st = stages.begin();
233 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
234 BOOST_REQUIRE (st->second);
235 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
237 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
238 BOOST_REQUIRE (st->second);
239 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
241 BOOST_CHECK_EQUAL (st->first, "Checking reel");
242 BOOST_REQUIRE (!st->second);
244 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
245 BOOST_REQUIRE (st->second);
246 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
248 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
249 BOOST_REQUIRE (st->second);
250 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
252 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
253 BOOST_REQUIRE (st->second);
254 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
256 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
257 BOOST_REQUIRE (st->second);
258 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
260 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
261 BOOST_REQUIRE (st->second);
262 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
264 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
265 BOOST_REQUIRE (st->second);
266 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
268 BOOST_REQUIRE (st == stages.end());
270 BOOST_CHECK_EQUAL (notes.size(), 0);
273 /* Corrupt the MXFs and check that this is spotted */
274 BOOST_AUTO_TEST_CASE (verify_test2)
276 auto directories = setup (1, 2);
278 auto mod = fopen("build/test/verify_test2/video.mxf", "r+b");
280 fseek (mod, 4096, SEEK_SET);
282 fwrite (&x, sizeof(x), 1, mod);
285 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
287 BOOST_REQUIRE_EQUAL (fseek(mod, -64, SEEK_END), 0);
288 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
291 dcp::ASDCPErrorSuspender sus;
292 check_verify_result (
295 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PICTURE_HASH_INCORRECT },
296 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::SOUND_HASH_INCORRECT }
300 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
301 BOOST_AUTO_TEST_CASE (verify_test3)
303 auto directories = setup (1, 3);
306 Editor e (boost::filesystem::path("build") / "test" / "verify_test3" / dcp_test1_pkl);
307 e.replace ("<Hash>", "<Hash>x");
310 check_verify_result (
313 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
314 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DIFFER },
315 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DIFFER },
316 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
317 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
318 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR }
322 /* Corrupt the ContentKind in the CPL */
323 BOOST_AUTO_TEST_CASE (verify_test4)
325 auto directories = setup (1, 4);
328 Editor e (boost::filesystem::path("build") / "test" / "verify_test4" / dcp_test1_cpl);
329 e.replace ("<ContentKind>", "<ContentKind>x");
332 auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
334 BOOST_REQUIRE_EQUAL (notes.size(), 1);
335 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
336 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xtrailer'");
340 boost::filesystem::path
343 return dcp::String::compose("build/test/verify_test%1/%2", n, dcp_test1_cpl);
347 boost::filesystem::path
350 return dcp::String::compose("build/test/verify_test%1/%2", n, dcp_test1_pkl);
354 boost::filesystem::path
357 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
362 BOOST_AUTO_TEST_CASE (verify_test5)
364 check_verify_result_after_replace (
366 "<FrameRate>24 1", "<FrameRate>99 1",
367 { dcp::VerificationNote::CPL_HASH_INCORRECT,
368 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE }
373 BOOST_AUTO_TEST_CASE (verify_test6)
375 auto directories = setup (1, 6);
377 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
378 check_verify_result (directories, {{ dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::MISSING_ASSET }});
382 boost::filesystem::path
385 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
388 /* Empty asset filename in ASSETMAP */
389 BOOST_AUTO_TEST_CASE (verify_test7)
391 check_verify_result_after_replace (
393 "<Path>video.mxf</Path>", "<Path></Path>",
394 { dcp::VerificationNote::EMPTY_ASSET_PATH }
398 /* Mismatched standard */
399 BOOST_AUTO_TEST_CASE (verify_test8)
401 check_verify_result_after_replace (
403 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
404 { dcp::VerificationNote::MISMATCHED_STANDARD,
405 dcp::VerificationNote::XML_VALIDATION_ERROR,
406 dcp::VerificationNote::XML_VALIDATION_ERROR,
407 dcp::VerificationNote::XML_VALIDATION_ERROR,
408 dcp::VerificationNote::XML_VALIDATION_ERROR,
409 dcp::VerificationNote::XML_VALIDATION_ERROR,
410 dcp::VerificationNote::CPL_HASH_INCORRECT }
414 /* Badly formatted <Id> in CPL */
415 BOOST_AUTO_TEST_CASE (verify_test9)
417 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
418 check_verify_result_after_replace (
420 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
421 { dcp::VerificationNote::XML_VALIDATION_ERROR }
425 /* Badly formatted <IssueDate> in CPL */
426 BOOST_AUTO_TEST_CASE (verify_test10)
428 check_verify_result_after_replace (
430 "<IssueDate>", "<IssueDate>x",
431 { dcp::VerificationNote::XML_VALIDATION_ERROR,
432 dcp::VerificationNote::CPL_HASH_INCORRECT }
436 /* Badly-formatted <Id> in PKL */
437 BOOST_AUTO_TEST_CASE (verify_test11)
439 check_verify_result_after_replace (
441 "<Id>urn:uuid:2b9", "<Id>urn:uuid:xb9",
442 { dcp::VerificationNote::XML_VALIDATION_ERROR }
446 /* Badly-formatted <Id> in ASSETMAP */
447 BOOST_AUTO_TEST_CASE (verify_test12)
449 check_verify_result_after_replace (
451 "<Id>urn:uuid:07e", "<Id>urn:uuid:x7e",
452 { dcp::VerificationNote::XML_VALIDATION_ERROR }
456 /* Basic test of an Interop DCP */
457 BOOST_AUTO_TEST_CASE (verify_test13)
460 auto directories = setup (3, 13);
461 auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
463 boost::filesystem::path const cpl_file = boost::filesystem::path("build") / "test" / "verify_test13" / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
464 boost::filesystem::path const pkl_file = boost::filesystem::path("build") / "test" / "verify_test13" / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
465 boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
467 auto st = stages.begin();
468 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
469 BOOST_REQUIRE (st->second);
470 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13"));
472 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
473 BOOST_REQUIRE (st->second);
474 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
476 BOOST_CHECK_EQUAL (st->first, "Checking reel");
477 BOOST_REQUIRE (!st->second);
479 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
480 BOOST_REQUIRE (st->second);
481 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
483 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
484 BOOST_REQUIRE (st->second);
485 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
487 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
488 BOOST_REQUIRE (st->second);
489 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
491 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
492 BOOST_REQUIRE (st->second);
493 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
495 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
496 BOOST_REQUIRE (st->second);
497 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
499 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
500 BOOST_REQUIRE (st->second);
501 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
503 BOOST_REQUIRE (st == stages.end());
505 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
506 auto i = notes.begin ();
507 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
508 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
511 /* DCP with a short asset */
512 BOOST_AUTO_TEST_CASE (verify_test14)
514 auto directories = setup (8, 14);
515 check_verify_result (
518 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::NOT_SMPTE },
519 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::DURATION_TOO_SMALL },
520 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL },
521 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::DURATION_TOO_SMALL },
522 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL }
529 dcp_from_frame (dcp::ArrayData const& frame, boost::filesystem::path dir)
531 auto asset = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::SMPTE);
532 boost::filesystem::create_directories (dir);
533 auto writer = asset->start_write (dir / "pic.mxf", true);
534 for (int i = 0; i < 24; ++i) {
535 writer->write (frame.data(), frame.size());
539 auto reel_asset = make_shared<dcp::ReelMonoPictureAsset>(asset, 0);
540 write_dcp_with_single_asset (dir, reel_asset);
544 /* DCP with an over-sized JPEG2000 frame */
545 BOOST_AUTO_TEST_CASE (verify_test15)
547 int const too_big = 1302083 * 2;
549 /* Compress a black image */
550 auto image = black_image ();
551 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
552 BOOST_REQUIRE (frame.size() < too_big);
554 /* Place it in a bigger block with some zero padding at the end */
555 dcp::ArrayData oversized_frame(too_big);
556 memcpy (oversized_frame.data(), frame.data(), frame.size());
557 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
559 boost::filesystem::path const dir("build/test/verify_test15");
560 boost::filesystem::remove_all (dir);
561 dcp_from_frame (oversized_frame, dir);
563 check_verify_result (
566 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE_IN_BYTES },
567 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
572 /* DCP with a nearly over-sized JPEG2000 frame */
573 BOOST_AUTO_TEST_CASE (verify_test16)
575 int const nearly_too_big = 1302083 * 0.98;
577 /* Compress a black image */
578 auto image = black_image ();
579 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
580 BOOST_REQUIRE (frame.size() < nearly_too_big);
582 /* Place it in a bigger block with some zero padding at the end */
583 dcp::ArrayData oversized_frame(nearly_too_big);
584 memcpy (oversized_frame.data(), frame.data(), frame.size());
585 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
587 boost::filesystem::path const dir("build/test/verify_test16");
588 boost::filesystem::remove_all (dir);
589 dcp_from_frame (oversized_frame, dir);
591 check_verify_result (
594 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE_IN_BYTES },
595 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
600 /* DCP with a within-range JPEG2000 frame */
601 BOOST_AUTO_TEST_CASE (verify_test17)
603 /* Compress a black image */
604 auto image = black_image ();
605 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
606 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
608 boost::filesystem::path const dir("build/test/verify_test17");
609 boost::filesystem::remove_all (dir);
610 dcp_from_frame (frame, dir);
612 check_verify_result ({ dir }, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
616 /* DCP with valid Interop subtitles */
617 BOOST_AUTO_TEST_CASE (verify_test18)
619 boost::filesystem::path const dir("build/test/verify_test18");
620 prepare_directory (dir);
621 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
622 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
623 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
624 write_dcp_with_single_asset (dir, reel_asset, dcp::INTEROP);
626 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::NOT_SMPTE }});
630 /* DCP with broken Interop subtitles */
631 BOOST_AUTO_TEST_CASE (verify_test19)
633 boost::filesystem::path const dir("build/test/verify_test19");
634 prepare_directory (dir);
635 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
636 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
637 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
638 write_dcp_with_single_asset (dir, reel_asset, dcp::INTEROP);
641 Editor e (dir / "subs.xml");
642 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
645 check_verify_result (
648 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::NOT_SMPTE },
649 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
650 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR }
655 /* DCP with valid SMPTE subtitles */
656 BOOST_AUTO_TEST_CASE (verify_test20)
658 boost::filesystem::path const dir("build/test/verify_test20");
659 prepare_directory (dir);
660 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
661 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
662 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
663 write_dcp_with_single_asset (dir, reel_asset);
665 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
669 /* DCP with broken SMPTE subtitles */
670 BOOST_AUTO_TEST_CASE (verify_test21)
672 boost::filesystem::path const dir("build/test/verify_test21");
673 prepare_directory (dir);
674 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
675 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
676 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
677 write_dcp_with_single_asset (dir, reel_asset);
679 check_verify_result (
682 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
683 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
684 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
685 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
691 BOOST_AUTO_TEST_CASE (verify_test22)
693 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
694 prepare_directory (ov_dir);
696 auto image = black_image ();
697 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
698 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
699 dcp_from_frame (frame, ov_dir);
701 dcp::DCP ov (ov_dir);
704 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
705 prepare_directory (vf_dir);
707 write_dcp_with_single_asset (vf_dir, ov.cpls().front()->reels().front()->main_picture());
709 check_verify_result (
712 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::EXTERNAL_ASSET },
713 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
718 /* DCP with valid CompositionMetadataAsset */
719 BOOST_AUTO_TEST_CASE (verify_test23)
721 boost::filesystem::path const dir("build/test/verify_test23");
722 prepare_directory (dir);
724 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
725 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
726 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
728 auto reel = make_shared<dcp::Reel>();
729 reel->add (reel_asset);
731 reel->add (simple_markers(16 * 24 - 1));
733 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
735 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
736 cpl->set_main_sound_sample_rate (48000);
737 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
738 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
742 dcp.write_xml (dcp::SMPTE);
744 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
748 boost::filesystem::path find_cpl (boost::filesystem::path dir)
750 for (auto i: boost::filesystem::directory_iterator(dir)) {
751 if (boost::starts_with(i.path().filename().string(), "cpl_")) {
756 BOOST_REQUIRE (false);
761 /* DCP with invalid CompositionMetadataAsset */
762 BOOST_AUTO_TEST_CASE (verify_test24)
764 boost::filesystem::path const dir("build/test/verify_test24");
765 prepare_directory (dir);
767 auto reel = make_shared<dcp::Reel>();
768 reel->add (black_picture_asset(dir));
769 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
771 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
772 cpl->set_main_sound_sample_rate (48000);
773 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
774 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
775 cpl->set_version_number (1);
777 reel->add (simple_markers());
781 dcp.write_xml (dcp::SMPTE);
784 Editor e (find_cpl("build/test/verify_test24"));
785 e.replace ("MainSound", "MainSoundX");
788 check_verify_result (
791 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
792 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
793 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
794 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT }
799 /* DCP with invalid CompositionMetadataAsset */
800 BOOST_AUTO_TEST_CASE (verify_test25)
802 boost::filesystem::path const dir("build/test/verify_test25");
803 prepare_directory (dir);
805 auto reel = make_shared<dcp::Reel>();
806 reel->add (black_picture_asset(dir));
807 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
809 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
810 cpl->set_main_sound_sample_rate (48000);
811 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
812 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
816 dcp.write_xml (dcp::SMPTE);
819 Editor e (find_cpl("build/test/verify_test25"));
820 e.replace ("meta:Width", "meta:WidthX");
823 check_verify_result (
825 {{ dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::GENERAL_READ }}
830 /* SMPTE DCP with invalid <Language> in the MainSubtitle reel and also in the XML within the MXF */
831 BOOST_AUTO_TEST_CASE (verify_test26)
833 boost::filesystem::path const dir("build/test/verify_test26");
834 prepare_directory (dir);
835 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
836 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
837 asset->_language = "wrong-andbad";
838 asset->write (dir / "subs.mxf");
839 auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
840 reel_asset->_language = "badlang";
841 write_dcp_with_single_asset (dir, reel_asset);
843 auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
844 BOOST_REQUIRE_EQUAL (notes.size(), 3U);
845 auto i = notes.begin();
846 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
847 BOOST_REQUIRE (i->note());
848 BOOST_CHECK_EQUAL (*i->note(), "badlang");
850 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
851 BOOST_REQUIRE (i->note());
852 BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
854 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_CPL_METADATA);
858 /* SMPTE DCP with invalid <Language> in the MainClosedCaption reel and also in the XML within the MXF */
859 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_languages)
861 boost::filesystem::path const dir("build/test/verify_invalid_closed_caption_languages");
862 prepare_directory (dir);
863 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
864 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
865 asset->_language = "wrong-andbad";
866 asset->write (dir / "subs.mxf");
867 auto reel_asset = make_shared<dcp::ReelClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
868 reel_asset->_language = "badlang";
869 write_dcp_with_single_asset (dir, reel_asset);
871 auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
872 BOOST_REQUIRE_EQUAL (notes.size(), 3U);
873 auto i = notes.begin ();
874 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
875 BOOST_REQUIRE (i->note());
876 BOOST_CHECK_EQUAL (*i->note(), "badlang");
878 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
879 BOOST_REQUIRE (i->note());
880 BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
882 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_CPL_METADATA);
886 /* SMPTE DCP with invalid <Language> in the MainSound reel, the CPL additional subtitles languages and
887 * the release territory.
889 BOOST_AUTO_TEST_CASE (verify_various_invalid_languages)
891 boost::filesystem::path const dir("build/test/verify_various_invalid_languages");
892 prepare_directory (dir);
894 auto picture = simple_picture (dir, "foo");
895 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
896 auto reel = make_shared<dcp::Reel>();
897 reel->add (reel_picture);
898 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "frobozz");
899 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
900 reel->add (reel_sound);
901 reel->add (simple_markers());
903 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
905 cpl->_additional_subtitle_languages.push_back("this-is-wrong");
906 cpl->_additional_subtitle_languages.push_back("andso-is-this");
907 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
908 cpl->set_main_sound_sample_rate (48000);
909 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
910 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
911 cpl->set_version_number (1);
912 cpl->_release_territory = "fred-jim";
913 auto dcp = make_shared<dcp::DCP>(dir);
915 dcp->write_xml (dcp::SMPTE);
917 auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
918 BOOST_REQUIRE_EQUAL (notes.size(), 4U);
919 auto i = notes.begin ();
920 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
921 BOOST_REQUIRE (i->note());
922 BOOST_CHECK_EQUAL (*i->note(), "this-is-wrong");
924 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
925 BOOST_REQUIRE (i->note());
926 BOOST_CHECK_EQUAL (*i->note(), "andso-is-this");
928 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
929 BOOST_REQUIRE (i->note());
930 BOOST_CHECK_EQUAL (*i->note(), "fred-jim");
932 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
933 BOOST_REQUIRE (i->note());
934 BOOST_CHECK_EQUAL (*i->note(), "frobozz");
939 vector<dcp::VerificationNote>
940 check_picture_size (int width, int height, int frame_rate, bool three_d)
942 using namespace boost::filesystem;
944 path dcp_path = "build/test/verify_picture_test";
945 remove_all (dcp_path);
946 create_directories (dcp_path);
948 shared_ptr<dcp::PictureAsset> mp;
950 mp = make_shared<dcp::StereoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::SMPTE);
952 mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::SMPTE);
954 auto picture_writer = mp->start_write (dcp_path / "video.mxf", false);
956 auto image = black_image (dcp::Size(width, height));
957 auto j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048);
958 int const length = three_d ? frame_rate * 2 : frame_rate;
959 for (int i = 0; i < length; ++i) {
960 picture_writer->write (j2c.data(), j2c.size());
962 picture_writer->finalize ();
964 auto d = make_shared<dcp::DCP>(dcp_path);
965 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::TRAILER);
966 cpl->set_annotation_text ("A Test DCP");
967 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
968 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
969 cpl->set_main_sound_sample_rate (48000);
970 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
971 cpl->set_main_picture_active_area (dcp::Size(1998, 1080));
972 cpl->set_version_number (1);
974 auto reel = make_shared<dcp::Reel>();
977 reel->add (make_shared<dcp::ReelStereoPictureAsset>(std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp), 0));
979 reel->add (make_shared<dcp::ReelMonoPictureAsset>(std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp), 0));
982 reel->add (simple_markers(frame_rate));
987 d->write_xml (dcp::SMPTE);
989 return dcp::verify ({dcp_path}, &stage, &progress, xsd_test);
995 check_picture_size_ok (int width, int height, int frame_rate, bool three_d)
997 auto notes = check_picture_size(width, height, frame_rate, three_d);
999 BOOST_CHECK_EQUAL (notes.size(), 0U);
1005 check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d)
1007 auto notes = check_picture_size(width, height, frame_rate, three_d);
1008 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1009 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1010 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_SIZE_IN_PIXELS);
1016 check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d)
1018 auto notes = check_picture_size(width, height, frame_rate, three_d);
1019 BOOST_REQUIRE_EQUAL (notes.size(), 2U);
1020 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1021 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K);
1027 check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d)
1029 auto notes = check_picture_size(width, height, frame_rate, three_d);
1030 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1031 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1032 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K);
1036 BOOST_AUTO_TEST_CASE (verify_picture_size)
1038 using namespace boost::filesystem;
1041 check_picture_size_ok (2048, 858, 24, false);
1042 check_picture_size_ok (2048, 858, 25, false);
1043 check_picture_size_ok (2048, 858, 48, false);
1044 check_picture_size_ok (2048, 858, 24, true);
1045 check_picture_size_ok (2048, 858, 25, true);
1046 check_picture_size_ok (2048, 858, 48, true);
1049 check_picture_size_ok (1998, 1080, 24, false);
1050 check_picture_size_ok (1998, 1080, 25, false);
1051 check_picture_size_ok (1998, 1080, 48, false);
1052 check_picture_size_ok (1998, 1080, 24, true);
1053 check_picture_size_ok (1998, 1080, 25, true);
1054 check_picture_size_ok (1998, 1080, 48, true);
1057 check_picture_size_ok (4096, 1716, 24, false);
1060 check_picture_size_ok (3996, 2160, 24, false);
1062 /* Bad frame size */
1063 check_picture_size_bad_frame_size (2050, 858, 24, false);
1064 check_picture_size_bad_frame_size (2048, 658, 25, false);
1065 check_picture_size_bad_frame_size (1920, 1080, 48, true);
1066 check_picture_size_bad_frame_size (4000, 3000, 24, true);
1068 /* Bad 2K frame rate */
1069 check_picture_size_bad_2k_frame_rate (2048, 858, 26, false);
1070 check_picture_size_bad_2k_frame_rate (2048, 858, 31, false);
1071 check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true);
1073 /* Bad 4K frame rate */
1074 check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false);
1075 check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false);
1078 auto notes = check_picture_size(3996, 2160, 24, true);
1079 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1080 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1081 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_4K_3D);
1087 add_test_subtitle (shared_ptr<dcp::SubtitleAsset> asset, int start_frame, int end_frame, float v_position = 0, string text = "Hello")
1090 make_shared<dcp::SubtitleString>(
1098 dcp::Time(start_frame, 24, 24),
1099 dcp::Time(end_frame, 24, 24),
1115 BOOST_AUTO_TEST_CASE (verify_closed_caption_xml_too_large)
1117 boost::filesystem::path const dir("build/test/verify_closed_caption_xml_too_large");
1118 prepare_directory (dir);
1120 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
1121 for (int i = 0; i < 2048; ++i) {
1122 add_test_subtitle (asset, i * 24, i * 24 + 20);
1124 asset->set_language (dcp::LanguageTag("de-DE"));
1125 asset->write (dir / "subs.mxf");
1126 auto reel_asset = make_shared<dcp::ReelClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1127 write_dcp_with_single_asset (dir, reel_asset);
1129 check_verify_result (
1132 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
1133 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES },
1134 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
1135 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA },
1141 shared_ptr<dcp::SMPTESubtitleAsset>
1142 make_large_subtitle_asset (boost::filesystem::path font_file)
1144 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
1145 dcp::ArrayData big_fake_font(1024 * 1024);
1146 big_fake_font.write (font_file);
1147 for (int i = 0; i < 116; ++i) {
1148 asset->add_font (dcp::String::compose("big%1", i), big_fake_font);
1156 verify_timed_text_asset_too_large (string name)
1158 auto const dir = boost::filesystem::path("build/test") / name;
1159 prepare_directory (dir);
1160 auto asset = make_large_subtitle_asset (dir / "font.ttf");
1161 add_test_subtitle (asset, 0, 20);
1162 asset->set_language (dcp::LanguageTag("de-DE"));
1163 asset->write (dir / "subs.mxf");
1165 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1166 write_dcp_with_single_asset (dir, reel_asset);
1168 check_verify_result (
1171 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TIMED_TEXT_ASSET_TOO_LARGE_IN_BYTES },
1172 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES },
1173 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
1174 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
1175 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA },
1180 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
1182 verify_timed_text_asset_too_large<dcp::ReelSubtitleAsset>("verify_subtitle_asset_too_large");
1183 verify_timed_text_asset_too_large<dcp::ReelClosedCaptionAsset>("verify_closed_caption_asset_too_large");
1187 BOOST_AUTO_TEST_CASE (verify_missing_language_tag_in_subtitle_xml)
1189 boost::filesystem::path dir = "build/test/verify_missing_language_tag_in_subtitle_xml";
1190 prepare_directory (dir);
1191 auto dcp = make_simple (dir, 1, 240);
1194 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
1195 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
1196 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
1197 "<ContentTitleText>Content</ContentTitleText>"
1198 "<AnnotationText>Annotation</AnnotationText>"
1199 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
1200 "<ReelNumber>1</ReelNumber>"
1201 "<EditRate>25 1</EditRate>"
1202 "<TimeCodeRate>25</TimeCodeRate>"
1203 "<StartTime>00:00:00:00</StartTime>"
1204 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
1206 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
1207 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
1208 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
1214 auto xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
1215 BOOST_REQUIRE (xml_file);
1216 fwrite (xml.c_str(), xml.size(), 1, xml_file);
1218 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
1219 subs->write (dir / "subs.mxf");
1221 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1222 dcp->cpls().front()->reels().front()->add(reel_subs);
1223 dcp->write_xml (dcp::SMPTE);
1225 check_verify_result (
1228 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_LANGUAGE },
1229 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }
1234 BOOST_AUTO_TEST_CASE (verify_inconsistent_subtitle_languages)
1236 boost::filesystem::path path ("build/test/verify_inconsistent_subtitle_languages");
1237 auto dcp = make_simple (path, 2, 240);
1238 auto cpl = dcp->cpls()[0];
1241 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
1242 subs->set_language (dcp::LanguageTag("de-DE"));
1243 subs->add (simple_subtitle());
1244 subs->write (path / "subs1.mxf");
1245 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1246 cpl->reels()[0]->add(reel_subs);
1250 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
1251 subs->set_language (dcp::LanguageTag("en-US"));
1252 subs->add (simple_subtitle());
1253 subs->write (path / "subs2.mxf");
1254 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1255 cpl->reels()[1]->add(reel_subs);
1258 dcp->write_xml (dcp::SMPTE);
1260 check_verify_result (
1263 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
1264 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::SUBTITLE_LANGUAGES_DIFFER },
1265 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME }
1270 BOOST_AUTO_TEST_CASE (verify_missing_start_time_tag_in_subtitle_xml)
1272 boost::filesystem::path dir = "build/test/verify_missing_start_time_tag_in_subtitle_xml";
1273 prepare_directory (dir);
1274 auto dcp = make_simple (dir, 1, 240);
1277 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
1278 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
1279 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
1280 "<ContentTitleText>Content</ContentTitleText>"
1281 "<AnnotationText>Annotation</AnnotationText>"
1282 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
1283 "<ReelNumber>1</ReelNumber>"
1284 "<Language>de-DE</Language>"
1285 "<EditRate>25 1</EditRate>"
1286 "<TimeCodeRate>25</TimeCodeRate>"
1287 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
1289 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
1290 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
1291 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
1297 auto xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
1298 BOOST_REQUIRE (xml_file);
1299 fwrite (xml.c_str(), xml.size(), 1, xml_file);
1301 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
1302 subs->write (dir / "subs.mxf");
1304 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1305 dcp->cpls().front()->reels().front()->add(reel_subs);
1306 dcp->write_xml (dcp::SMPTE);
1308 check_verify_result (
1311 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
1312 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }
1317 BOOST_AUTO_TEST_CASE (verify_non_zero_start_time_tag_in_subtitle_xml)
1319 boost::filesystem::path dir = "build/test/verify_non_zero_start_time_tag_in_subtitle_xml";
1320 prepare_directory (dir);
1321 auto dcp = make_simple (dir, 1, 240);
1324 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
1325 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
1326 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
1327 "<ContentTitleText>Content</ContentTitleText>"
1328 "<AnnotationText>Annotation</AnnotationText>"
1329 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
1330 "<ReelNumber>1</ReelNumber>"
1331 "<Language>de-DE</Language>"
1332 "<EditRate>25 1</EditRate>"
1333 "<TimeCodeRate>25</TimeCodeRate>"
1334 "<StartTime>00:00:02:00</StartTime>"
1335 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
1337 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
1338 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
1339 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
1345 auto xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
1346 BOOST_REQUIRE (xml_file);
1347 fwrite (xml.c_str(), xml.size(), 1, xml_file);
1349 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
1350 subs->write (dir / "subs.mxf");
1352 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1353 dcp->cpls().front()->reels().front()->add(reel_subs);
1354 dcp->write_xml (dcp::SMPTE);
1356 check_verify_result (
1359 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::SUBTITLE_START_TIME_NON_ZERO },
1360 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }
1368 TestText (int in_, int out_, float v_position_ = 0, string text_ = "Hello")
1371 , v_position(v_position_)
1384 dcp_with_text (boost::filesystem::path dir, vector<TestText> subs)
1386 prepare_directory (dir);
1387 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
1388 asset->set_start_time (dcp::Time());
1389 for (auto i: subs) {
1390 add_test_subtitle (asset, i.in, i.out, i.v_position, i.text);
1392 asset->set_language (dcp::LanguageTag("de-DE"));
1393 asset->write (dir / "subs.mxf");
1395 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1396 write_dcp_with_single_asset (dir, reel_asset);
1400 BOOST_AUTO_TEST_CASE (verify_text_too_early)
1402 auto const dir = boost::filesystem::path("build/test/verify_text_too_early");
1403 /* Just too early */
1404 dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24 - 1, 5 * 24 }});
1405 check_verify_result (
1408 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
1409 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1415 BOOST_AUTO_TEST_CASE (verify_text_not_too_early)
1417 auto const dir = boost::filesystem::path("build/test/verify_text_not_too_early");
1418 /* Just late enough */
1419 dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 5 * 24 }});
1420 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1424 BOOST_AUTO_TEST_CASE (verify_text_early_on_second_reel)
1426 auto const dir = boost::filesystem::path("build/test/verify_text_early_on_second_reel");
1427 prepare_directory (dir);
1429 auto asset1 = make_shared<dcp::SMPTESubtitleAsset>();
1430 asset1->set_start_time (dcp::Time());
1431 /* Just late enough */
1432 add_test_subtitle (asset1, 4 * 24, 5 * 24);
1433 asset1->set_language (dcp::LanguageTag("de-DE"));
1434 asset1->write (dir / "subs1.mxf");
1435 auto reel_asset1 = make_shared<dcp::ReelSubtitleAsset>(asset1, dcp::Fraction(24, 1), 16 * 24, 0);
1436 auto reel1 = make_shared<dcp::Reel>();
1437 reel1->add (reel_asset1);
1438 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 16 * 24, 0);
1439 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
1440 reel1->add (markers1);
1442 auto asset2 = make_shared<dcp::SMPTESubtitleAsset>();
1443 asset2->set_start_time (dcp::Time());
1444 /* This would be too early on first reel but should be OK on the second */
1445 add_test_subtitle (asset2, 0, 4 * 24);
1446 asset2->set_language (dcp::LanguageTag("de-DE"));
1447 asset2->write (dir / "subs2.mxf");
1448 auto reel_asset2 = make_shared<dcp::ReelSubtitleAsset>(asset2, dcp::Fraction(24, 1), 16 * 24, 0);
1449 auto reel2 = make_shared<dcp::Reel>();
1450 reel2->add (reel_asset2);
1451 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 16 * 24, 0);
1452 markers2->set (dcp::Marker::LFOC, dcp::Time(16 * 24 - 1, 24, 24));
1453 reel2->add (markers2);
1455 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
1458 auto dcp = make_shared<dcp::DCP>(dir);
1460 dcp->write_xml (dcp::SMPTE);
1462 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1466 BOOST_AUTO_TEST_CASE (verify_text_too_close)
1468 auto const dir = boost::filesystem::path("build/test/verify_text_too_close");
1469 dcp_with_text<dcp::ReelSubtitleAsset> (
1473 { 5 * 24 + 1, 6 * 24 },
1475 check_verify_result (
1478 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_CLOSE },
1479 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1484 BOOST_AUTO_TEST_CASE (verify_text_not_too_close)
1486 auto const dir = boost::filesystem::path("build/test/verify_text_not_too_close");
1487 dcp_with_text<dcp::ReelSubtitleAsset> (
1491 { 5 * 24 + 16, 8 * 24 },
1493 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1497 BOOST_AUTO_TEST_CASE (verify_text_too_short)
1499 auto const dir = boost::filesystem::path("build/test/verify_text_too_short");
1500 dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 1 }});
1501 check_verify_result (
1504 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_SHORT },
1505 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1510 BOOST_AUTO_TEST_CASE (verify_text_not_too_short)
1512 auto const dir = boost::filesystem::path("build/test/verify_text_not_too_short");
1513 dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 17 }});
1514 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1518 BOOST_AUTO_TEST_CASE (verify_too_many_subtitle_lines1)
1520 auto const dir = boost::filesystem::path ("build/test/verify_too_many_subtitle_lines1");
1521 dcp_with_text<dcp::ReelSubtitleAsset> (
1524 { 96, 200, 0.0, "We" },
1525 { 96, 200, 0.1, "have" },
1526 { 96, 200, 0.2, "four" },
1527 { 96, 200, 0.3, "lines" }
1529 check_verify_result (
1532 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES },
1533 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1538 BOOST_AUTO_TEST_CASE (verify_not_too_many_subtitle_lines1)
1540 auto const dir = boost::filesystem::path ("build/test/verify_not_too_many_subtitle_lines1");
1541 dcp_with_text<dcp::ReelSubtitleAsset> (
1544 { 96, 200, 0.0, "We" },
1545 { 96, 200, 0.1, "have" },
1546 { 96, 200, 0.2, "four" },
1548 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1552 BOOST_AUTO_TEST_CASE (verify_too_many_subtitle_lines2)
1554 auto const dir = boost::filesystem::path ("build/test/verify_too_many_subtitle_lines2");
1555 dcp_with_text<dcp::ReelSubtitleAsset> (
1558 { 96, 300, 0.0, "We" },
1559 { 96, 300, 0.1, "have" },
1560 { 150, 180, 0.2, "four" },
1561 { 150, 180, 0.3, "lines" }
1563 check_verify_result (
1566 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES },
1567 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1572 BOOST_AUTO_TEST_CASE (verify_not_too_many_subtitle_lines2)
1574 auto const dir = boost::filesystem::path ("build/test/verify_not_too_many_subtitle_lines2");
1575 dcp_with_text<dcp::ReelSubtitleAsset> (
1578 { 96, 300, 0.0, "We" },
1579 { 96, 300, 0.1, "have" },
1580 { 150, 180, 0.2, "four" },
1581 { 190, 250, 0.3, "lines" }
1583 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1587 BOOST_AUTO_TEST_CASE (verify_subtitle_lines_too_long1)
1589 auto const dir = boost::filesystem::path ("build/test/verify_subtitle_lines_too_long1");
1590 dcp_with_text<dcp::ReelSubtitleAsset> (
1593 { 96, 300, 0.0, "012345678901234567890123456789012345678901234567890123" }
1595 check_verify_result (
1598 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_LONGER_THAN_RECOMMENDED },
1599 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1604 BOOST_AUTO_TEST_CASE (verify_subtitle_lines_too_long2)
1606 auto const dir = boost::filesystem::path ("build/test/verify_subtitle_lines_too_long2");
1607 dcp_with_text<dcp::ReelSubtitleAsset> (
1610 { 96, 300, 0.0, "012345678901234567890123456789012345678901234567890123456789012345678901234567890" }
1612 check_verify_result (
1615 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_TOO_LONG },
1616 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1621 BOOST_AUTO_TEST_CASE (verify_too_many_closed_caption_lines1)
1623 auto const dir = boost::filesystem::path ("build/test/verify_too_many_closed_caption_lines1");
1624 dcp_with_text<dcp::ReelClosedCaptionAsset> (
1627 { 96, 200, 0.0, "We" },
1628 { 96, 200, 0.1, "have" },
1629 { 96, 200, 0.2, "four" },
1630 { 96, 200, 0.3, "lines" }
1632 check_verify_result (
1635 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES},
1636 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1641 BOOST_AUTO_TEST_CASE (verify_not_too_many_closed_caption_lines1)
1643 auto const dir = boost::filesystem::path ("build/test/verify_not_too_many_closed_caption_lines1");
1644 dcp_with_text<dcp::ReelClosedCaptionAsset> (
1647 { 96, 200, 0.0, "We" },
1648 { 96, 200, 0.1, "have" },
1649 { 96, 200, 0.2, "four" },
1651 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1655 BOOST_AUTO_TEST_CASE (verify_too_many_closed_caption_lines2)
1657 auto const dir = boost::filesystem::path ("build/test/verify_too_many_closed_caption_lines2");
1658 dcp_with_text<dcp::ReelClosedCaptionAsset> (
1661 { 96, 300, 0.0, "We" },
1662 { 96, 300, 0.1, "have" },
1663 { 150, 180, 0.2, "four" },
1664 { 150, 180, 0.3, "lines" }
1666 check_verify_result (
1669 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES},
1670 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1675 BOOST_AUTO_TEST_CASE (verify_not_too_many_closed_caption_lines2)
1677 auto const dir = boost::filesystem::path ("build/test/verify_not_too_many_closed_caption_lines2");
1678 dcp_with_text<dcp::ReelClosedCaptionAsset> (
1681 { 96, 300, 0.0, "We" },
1682 { 96, 300, 0.1, "have" },
1683 { 150, 180, 0.2, "four" },
1684 { 190, 250, 0.3, "lines" }
1686 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1690 BOOST_AUTO_TEST_CASE (verify_closed_caption_lines_too_long1)
1692 auto const dir = boost::filesystem::path ("build/test/verify_closed_caption_lines_too_long1");
1693 dcp_with_text<dcp::ReelClosedCaptionAsset> (
1696 { 96, 300, 0.0, "0123456789012345678901234567890123" }
1698 check_verify_result (
1701 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_LINE_TOO_LONG },
1702 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1707 BOOST_AUTO_TEST_CASE (verify_sound_sampling_rate_must_be_48k)
1709 boost::filesystem::path const dir("build/test/verify_sound_sampling_rate_must_be_48k");
1710 prepare_directory (dir);
1712 auto picture = simple_picture (dir, "foo");
1713 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
1714 auto reel = make_shared<dcp::Reel>();
1715 reel->add (reel_picture);
1716 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000);
1717 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
1718 reel->add (reel_sound);
1719 reel->add (simple_markers());
1720 auto cpl = make_shared<dcp::CPL>("hello", dcp::TRAILER);
1722 auto dcp = make_shared<dcp::DCP>(dir);
1724 dcp->write_xml (dcp::SMPTE);
1726 check_verify_result (
1729 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_SOUND_FRAME_RATE },
1730 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1735 BOOST_AUTO_TEST_CASE (verify_cpl_must_have_annotation_text)
1737 boost::filesystem::path const dir("build/test/verify_cpl_must_have_annotation_text");
1738 auto dcp = make_simple (dir);
1739 dcp->write_xml (dcp::SMPTE);
1740 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
1743 BOOST_REQUIRE (dcp->cpls()[0]->file());
1744 Editor e(dcp->cpls()[0]->file().get());
1745 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "");
1748 check_verify_result (
1751 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_ANNOTATION_TEXT_IN_CPL },
1752 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT }
1757 BOOST_AUTO_TEST_CASE (verify_cpl_annotation_text_should_be_same_as_content_title_text)
1759 boost::filesystem::path const dir("build/test/verify_cpl_annotation_text_should_be_same_as_content_title_text");
1760 auto dcp = make_simple (dir);
1761 dcp->write_xml (dcp::SMPTE);
1762 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
1765 BOOST_REQUIRE (dcp->cpls()[0]->file());
1766 Editor e(dcp->cpls()[0]->file().get());
1767 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "<AnnotationText>A Test DCP 1</AnnotationText>");
1770 check_verify_result (
1773 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::CPL_ANNOTATION_TEXT_DIFFERS_FROM_CONTENT_TITLE_TEXT },
1774 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT }
1779 BOOST_AUTO_TEST_CASE (verify_reel_assets_durations_must_match)
1781 boost::filesystem::path const dir("build/test/verify_reel_assets_durations_must_match");
1782 boost::filesystem::remove_all (dir);
1783 boost::filesystem::create_directories (dir);
1784 shared_ptr<dcp::DCP> dcp (new dcp::DCP(dir));
1785 shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::TRAILER));
1787 shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (dir, "", 24);
1788 shared_ptr<dcp::SoundAsset> ms = simple_sound (dir, "", dcp::MXFMetadata(), "en-US", 25);
1790 auto reel = make_shared<dcp::Reel>(
1791 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
1792 make_shared<dcp::ReelSoundAsset>(ms, 0)
1795 reel->add (simple_markers());
1799 dcp->write_xml (dcp::SMPTE);
1801 check_verify_result (
1804 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISMATCHED_ASSET_DURATION },
1805 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1813 verify_subtitles_must_be_in_all_reels_check (boost::filesystem::path dir, bool add_to_reel1, bool add_to_reel2)
1815 boost::filesystem::remove_all (dir);
1816 boost::filesystem::create_directories (dir);
1817 auto dcp = make_shared<dcp::DCP>(dir);
1818 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::TRAILER);
1820 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
1821 subs->set_language (dcp::LanguageTag("de-DE"));
1822 subs->set_start_time (dcp::Time());
1823 subs->add (simple_subtitle());
1824 subs->write (dir / "subs.mxf");
1825 auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
1827 auto reel1 = make_shared<dcp::Reel>(
1828 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 240), 0),
1829 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0)
1833 reel1->add (make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0));
1836 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 240, 0);
1837 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
1838 reel1->add (markers1);
1842 auto reel2 = make_shared<dcp::Reel>(
1843 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 240), 0),
1844 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0)
1848 reel2->add (make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0));
1851 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 240, 0);
1852 markers2->set (dcp::Marker::LFOC, dcp::Time(239, 24, 24));
1853 reel2->add (markers2);
1858 dcp->write_xml (dcp::SMPTE);
1862 BOOST_AUTO_TEST_CASE (verify_subtitles_must_be_in_all_reels)
1865 boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels1");
1866 verify_subtitles_must_be_in_all_reels_check (dir, true, false);
1867 check_verify_result (
1870 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MAIN_SUBTITLE_NOT_IN_ALL_REELS },
1871 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1877 boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels2");
1878 verify_subtitles_must_be_in_all_reels_check (dir, true, true);
1879 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1883 boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels1");
1884 verify_subtitles_must_be_in_all_reels_check (dir, false, false);
1885 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1892 verify_closed_captions_must_be_in_all_reels_check (boost::filesystem::path dir, int caps_in_reel1, int caps_in_reel2)
1894 boost::filesystem::remove_all (dir);
1895 boost::filesystem::create_directories (dir);
1896 auto dcp = make_shared<dcp::DCP>(dir);
1897 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::TRAILER);
1899 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
1900 subs->set_language (dcp::LanguageTag("de-DE"));
1901 subs->set_start_time (dcp::Time());
1902 subs->add (simple_subtitle());
1903 subs->write (dir / "subs.mxf");
1905 auto reel1 = make_shared<dcp::Reel>(
1906 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 240), 0),
1907 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0)
1910 for (int i = 0; i < caps_in_reel1; ++i) {
1911 reel1->add (make_shared<dcp::ReelClosedCaptionAsset>(subs, dcp::Fraction(24, 1), 240, 0));
1914 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 240, 0);
1915 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
1916 reel1->add (markers1);
1920 auto reel2 = make_shared<dcp::Reel>(
1921 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 240), 0),
1922 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0)
1925 for (int i = 0; i < caps_in_reel2; ++i) {
1926 reel2->add (make_shared<dcp::ReelClosedCaptionAsset>(subs, dcp::Fraction(24, 1), 240, 0));
1929 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 240, 0);
1930 markers2->set (dcp::Marker::LFOC, dcp::Time(239, 24, 24));
1931 reel2->add (markers2);
1936 dcp->write_xml (dcp::SMPTE);
1941 BOOST_AUTO_TEST_CASE (verify_closed_captions_must_be_in_all_reels)
1944 boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels1");
1945 verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4);
1946 check_verify_result (
1949 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_ASSET_COUNTS_DIFFER },
1950 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
1955 boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels2");
1956 verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4);
1957 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1961 boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels3");
1962 verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0);
1963 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
1970 verify_text_entry_point_check (boost::filesystem::path dir, dcp::VerificationNote::Code code, boost::function<void (shared_ptr<T>)> adjust)
1972 boost::filesystem::remove_all (dir);
1973 boost::filesystem::create_directories (dir);
1974 auto dcp = make_shared<dcp::DCP>(dir);
1975 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::TRAILER);
1977 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
1978 subs->set_language (dcp::LanguageTag("de-DE"));
1979 subs->set_start_time (dcp::Time());
1980 subs->add (simple_subtitle());
1981 subs->write (dir / "subs.mxf");
1982 auto reel_text = make_shared<T>(subs, dcp::Fraction(24, 1), 240, 0);
1985 auto reel = make_shared<dcp::Reel>(
1986 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 240), 0),
1987 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0)
1990 reel->add (reel_text);
1992 reel->add (simple_markers(240));
1997 dcp->write_xml (dcp::SMPTE);
1999 check_verify_result (
2002 { dcp::VerificationNote::VERIFY_BV21_ERROR, code },
2003 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
2008 BOOST_AUTO_TEST_CASE (verify_text_entry_point)
2010 verify_text_entry_point_check<dcp::ReelSubtitleAsset> (
2011 "build/test/verify_subtitle_entry_point_must_be_present",
2012 dcp::VerificationNote::MISSING_SUBTITLE_ENTRY_POINT,
2013 [](shared_ptr<dcp::ReelSubtitleAsset> asset) {
2014 asset->unset_entry_point ();
2018 verify_text_entry_point_check<dcp::ReelSubtitleAsset> (
2019 "build/test/verify_subtitle_entry_point_must_be_zero",
2020 dcp::VerificationNote::SUBTITLE_ENTRY_POINT_NON_ZERO,
2021 [](shared_ptr<dcp::ReelSubtitleAsset> asset) {
2022 asset->set_entry_point (4);
2026 verify_text_entry_point_check<dcp::ReelClosedCaptionAsset> (
2027 "build/test/verify_closed_caption_entry_point_must_be_present",
2028 dcp::VerificationNote::MISSING_CLOSED_CAPTION_ENTRY_POINT,
2029 [](shared_ptr<dcp::ReelClosedCaptionAsset> asset) {
2030 asset->unset_entry_point ();
2034 verify_text_entry_point_check<dcp::ReelClosedCaptionAsset> (
2035 "build/test/verify_closed_caption_entry_point_must_be_zero",
2036 dcp::VerificationNote::CLOSED_CAPTION_ENTRY_POINT_NON_ZERO,
2037 [](shared_ptr<dcp::ReelClosedCaptionAsset> asset) {
2038 asset->set_entry_point (9);
2044 BOOST_AUTO_TEST_CASE (verify_assets_must_have_hashes)
2048 boost::filesystem::path const dir("build/test/verify_assets_must_have_hashes");
2049 auto dcp = make_simple (dir);
2050 dcp->write_xml (dcp::SMPTE);
2051 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
2054 BOOST_REQUIRE (dcp->cpls()[0]->file());
2055 Editor e(dcp->cpls()[0]->file().get());
2056 e.replace("<Hash>XGhFVrqZqapOJx5Fh2SLjj48Yjg=</Hash>", "");
2059 check_verify_result (
2062 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2063 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_HASH }
2070 verify_markers_test (
2071 boost::filesystem::path dir,
2072 vector<pair<dcp::Marker, dcp::Time>> markers,
2073 vector<dcp::VerificationNote> test_notes
2076 auto dcp = make_simple (dir);
2077 dcp->cpls()[0]->set_content_kind (dcp::FEATURE);
2078 auto markers_asset = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 24, 0);
2079 for (auto const& i: markers) {
2080 markers_asset->set (i.first, i.second);
2082 dcp->cpls()[0]->reels()[0]->add(markers_asset);
2083 dcp->write_xml (dcp::SMPTE);
2084 check_verify_result ({dir}, test_notes);
2088 BOOST_AUTO_TEST_CASE (verify_markers)
2090 verify_markers_test (
2091 "build/test/verify_markers_all_correct",
2093 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2094 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2095 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
2096 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
2101 verify_markers_test (
2102 "build/test/verify_markers_missing_ffec",
2104 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2105 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
2106 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
2109 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_FFEC_IN_FEATURE }
2112 verify_markers_test (
2113 "build/test/verify_markers_missing_ffmc",
2115 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2116 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
2117 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
2120 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_FFMC_IN_FEATURE }
2123 verify_markers_test (
2124 "build/test/verify_markers_missing_ffoc",
2126 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2127 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2128 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
2131 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_FFOC}
2134 verify_markers_test (
2135 "build/test/verify_markers_missing_lfoc",
2137 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2138 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2139 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) }
2142 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_LFOC }
2145 verify_markers_test (
2146 "build/test/verify_markers_incorrect_ffoc",
2148 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2149 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2150 { dcp::Marker::FFOC, dcp::Time(3, 24, 24) },
2151 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
2154 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::INCORRECT_FFOC }
2157 verify_markers_test (
2158 "build/test/verify_markers_incorrect_lfoc",
2160 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
2161 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
2162 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
2163 { dcp::Marker::LFOC, dcp::Time(18, 24, 24) }
2166 { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::INCORRECT_LFOC }
2171 BOOST_AUTO_TEST_CASE (verify_cpl_metadata_version)
2173 boost::filesystem::path dir = "build/test/verify_cpl_metadata_version";
2174 prepare_directory (dir);
2175 auto dcp = make_simple (dir);
2176 dcp->cpls()[0]->unset_version_number();
2177 dcp->write_xml (dcp::SMPTE);
2178 check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER }});
2182 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata1)
2184 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata1";
2185 auto dcp = make_simple (dir);
2186 dcp->write_xml (dcp::SMPTE);
2188 Editor e (dcp->cpls()[0]->file().get());
2189 e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
2192 check_verify_result (
2195 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2196 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_EXTENSION_METADATA }
2201 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata2)
2203 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata2";
2204 auto dcp = make_simple (dir);
2205 dcp->write_xml (dcp::SMPTE);
2207 Editor e (dcp->cpls()[0]->file().get());
2208 e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
2211 check_verify_result (
2214 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2215 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_EXTENSION_METADATA }
2220 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata3)
2222 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata3";
2223 auto dcp = make_simple (dir);
2224 dcp->write_xml (dcp::SMPTE);
2226 Editor e (dcp->cpls()[0]->file().get());
2227 e.replace ("<meta:Name>A", "<meta:NameX>A");
2228 e.replace ("n</meta:Name>", "n</meta:NameX>");
2231 check_verify_result (
2234 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2235 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2236 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2241 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata4)
2243 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata4";
2244 auto dcp = make_simple (dir);
2245 dcp->write_xml (dcp::SMPTE);
2247 Editor e (dcp->cpls()[0]->file().get());
2248 e.replace ("Application", "Fred");
2251 check_verify_result (
2254 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2255 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Name> property should be 'Application'") },
2260 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata5)
2262 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata5";
2263 auto dcp = make_simple (dir);
2264 dcp->write_xml (dcp::SMPTE);
2266 Editor e (dcp->cpls()[0]->file().get());
2267 e.replace ("DCP Constraints Profile", "Fred");
2270 check_verify_result (
2273 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2274 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'") },
2279 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata6)
2281 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata6";
2282 auto dcp = make_simple (dir);
2283 dcp->write_xml (dcp::SMPTE);
2285 Editor e (dcp->cpls()[0]->file().get());
2286 e.replace ("<meta:Value>", "<meta:ValueX>");
2287 e.replace ("</meta:Value>", "</meta:ValueX>");
2290 check_verify_result (
2293 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2294 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2295 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2300 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata7)
2302 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata7";
2303 auto dcp = make_simple (dir);
2304 dcp->write_xml (dcp::SMPTE);
2306 Editor e (dcp->cpls()[0]->file().get());
2307 e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
2310 check_verify_result (
2313 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2314 { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Value> property should be 'SMPTE-RDD-52:2020-Bv2.1'") },
2319 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata8)
2321 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata8";
2322 auto dcp = make_simple (dir);
2323 dcp->write_xml (dcp::SMPTE);
2325 Editor e (dcp->cpls()[0]->file().get());
2326 e.replace ("<meta:Property>", "<meta:PropertyX>");
2327 e.replace ("</meta:Property>", "</meta:PropertyX>");
2330 check_verify_result (
2333 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2334 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2335 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
2340 BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata9)
2342 boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata9";
2343 auto dcp = make_simple (dir);
2344 dcp->write_xml (dcp::SMPTE);
2346 Editor e (dcp->cpls()[0]->file().get());
2347 e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
2348 e.replace ("</meta:PropertyList>", "</meta:PropertyListX>");
2351 check_verify_result (
2354 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2355 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
2356 { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },