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.
35 #include "compose.hpp"
39 #include "interop_subtitle_asset.h"
40 #include "j2k_transcode.h"
41 #include "mono_picture_asset.h"
42 #include "mono_picture_asset_writer.h"
43 #include "openjpeg_image.h"
44 #include "raw_convert.h"
46 #include "reel_interop_closed_caption_asset.h"
47 #include "reel_interop_subtitle_asset.h"
48 #include "reel_markers_asset.h"
49 #include "reel_mono_picture_asset.h"
50 #include "reel_sound_asset.h"
51 #include "reel_stereo_picture_asset.h"
52 #include "reel_smpte_closed_caption_asset.h"
53 #include "reel_smpte_subtitle_asset.h"
54 #include "smpte_subtitle_asset.h"
55 #include "stereo_picture_asset.h"
56 #include "stream_operators.h"
60 #include "verify_j2k.h"
61 #include <boost/algorithm/string.hpp>
62 #include <boost/random.hpp>
63 #include <boost/test/unit_test.hpp>
71 using std::make_shared;
73 using std::shared_ptr;
76 using boost::optional;
77 using namespace boost::filesystem;
80 static list<pair<string, optional<path>>> stages;
82 static string filename_to_id(boost::filesystem::path path)
84 return path.string().substr(4, path.string().length() - 8);
88 boost::filesystem::path
91 return find_file("test/ref/DCP/dcp_test1", "pkl_").filename();
98 return filename_to_id(dcp_test1_pkl());
102 boost::filesystem::path
105 return find_file("test/ref/DCP/dcp_test1", "cpl_").filename();
112 return filename_to_id(dcp_test1_cpl());
115 static string const dcp_test1_asset_map_id = "017b3de4-6dda-408d-b19b-6711354b0bc3";
119 encryption_test_cpl_id()
121 return filename_to_id(find_file("test/ref/DCP/encryption_test", "cpl_").filename());
126 encryption_test_pkl_id()
128 return filename_to_id(find_file("test/ref/DCP/encryption_test", "pkl_").filename());
132 stage (string s, optional<path> p)
134 stages.push_back (make_pair (s, p));
144 prepare_directory (path path)
146 using namespace boost::filesystem;
148 create_directories (path);
154 find_prefix(path dir, string prefix)
156 auto iter = std::find_if(directory_iterator(dir), directory_iterator(), [prefix](path const& p) {
157 return boost::starts_with(p.filename().string(), prefix);
160 BOOST_REQUIRE(iter != directory_iterator());
169 return find_prefix(dir, "cpl_");
177 return find_prefix(dir, "pkl_");
183 find_asset_map(path dir)
185 return find_prefix(dir, "ASSETMAP");
189 /** Copy dcp_test{reference_number} to build/test/verify_test{verify_test_suffix}
190 * to make a new sacrificial test DCP.
193 setup (int reference_number, string verify_test_suffix)
195 auto const dir = dcp::String::compose("build/test/verify_test%1", verify_test_suffix);
196 prepare_directory (dir);
197 for (auto i: directory_iterator(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number))) {
198 copy_file (i.path(), dir / i.path().filename());
207 write_dcp_with_single_asset (path dir, shared_ptr<dcp::ReelAsset> reel_asset, dcp::Standard standard = dcp::Standard::SMPTE)
209 auto reel = make_shared<dcp::Reel>();
210 reel->add (reel_asset);
211 reel->add (simple_markers());
213 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, standard);
215 auto dcp = make_shared<dcp::DCP>(dir);
217 dcp->set_annotation_text("hello");
224 LIBDCP_DISABLE_WARNINGS
227 dump_notes (vector<dcp::VerificationNote> const & notes)
229 for (auto i: notes) {
230 std::cout << dcp::note_to_string(i) << "\n";
233 LIBDCP_ENABLE_WARNINGS
238 to_string(dcp::VerificationNote const& note)
240 string s = note_to_string(note) + dcp::String::compose(
241 "\n [%1 %2 %3 %4 %5 %6 ",
242 static_cast<int>(note.type()),
243 static_cast<int>(note.code()),
244 note.note().get_value_or("<none>"),
245 note.file().get_value_or("<none>"),
246 note.line().get_value_or(0),
247 note.frame().get_value_or(0)
250 s += dcp::String::compose(
252 note.id().get_value_or("<none>"),
253 note.other_id().get_value_or("<none>"),
254 note.cpl_id().get_value_or("<none>"),
255 note.reference_hash().get_value_or("<none>"),
256 note.calculated_hash().get_value_or("<none>")
265 check_verify_result(vector<dcp::VerificationNote> notes, vector<dcp::VerificationNote> test_notes)
267 std::sort(notes.begin(), notes.end());
268 std::sort(test_notes.begin(), test_notes.end());
270 string message = "\n";
272 vector<dcp::VerificationNote> not_expected;
273 for (auto note: notes) {
274 auto iter = std::find_if(test_notes.begin(), test_notes.end(), [note](dcp::VerificationNote const& n) { return note.type() == n.type() && note.code() == n.code(); });
275 if (iter != test_notes.end() && *iter != note) {
276 message += "Wrong details:\n --seen " + to_string(note) + " --expected " + to_string(*iter) + "\n";
277 } else if (iter == test_notes.end()) {
278 not_expected.push_back(note);
282 vector<dcp::VerificationNote> not_seen;
283 for (auto note: test_notes) {
284 auto iter = std::find_if(notes.begin(), notes.end(), [note](dcp::VerificationNote const& n) { return note.type() == n.type() && note.code() == n.code(); });
285 if (iter == notes.end()) {
286 not_seen.push_back(note);
290 for (auto note: not_expected) {
291 message += "Not expected:\n" + to_string(note) + "\n";
294 for (auto note: not_seen) {
295 message += "Not seen:\n" + to_string(note) + "\n";
298 BOOST_REQUIRE_MESSAGE(notes == test_notes, message);
304 check_verify_result(vector<path> dir, vector<dcp::DecryptedKDM> kdm, vector<dcp::VerificationNote> test_notes)
306 check_verify_result(dcp::verify({dir}, kdm, &stage, &progress, {}, xsd_test).notes, test_notes);
310 /* Copy dcp_test1 to build/test/verify_test{suffix} then edit a file found by the functor 'file',
311 * replacing from with to.
315 replace(string suffix, boost::function<path (string)> file, string from, string to)
317 auto dir = setup (1, suffix);
320 Editor e (file(suffix));
321 e.replace (from, to);
328 add_font(shared_ptr<dcp::SubtitleAsset> asset)
330 dcp::ArrayData fake_font(1024);
331 asset->add_font("font", fake_font);
338 HashCalculator(boost::filesystem::path path)
340 , _old_hash(dcp::make_digest(path, [](int64_t, int64_t) {}))
343 std::string old_hash() const {
347 std::string new_hash() const {
348 return dcp::make_digest(_path, [](int64_t, int64_t) {});
352 boost::filesystem::path _path;
353 std::string _old_hash;
358 dcp::VerificationNote
359 ok(dcp::VerificationNote::Code code, shared_ptr<const dcp::CPL> cpl)
361 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code).set_cpl_id(cpl->id());
366 dcp::VerificationNote
367 ok(dcp::VerificationNote::Code code, string note, shared_ptr<const dcp::CPL> cpl)
369 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, note).set_cpl_id(cpl->id());
374 dcp::VerificationNote
375 ok(dcp::VerificationNote::Code code, boost::filesystem::path path, shared_ptr<const dcp::CPL> cpl)
377 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, path).set_cpl_id(cpl->id());
382 add(vector<dcp::VerificationNote>& notes, vector<dcp::VerificationNote> const& add)
390 BOOST_AUTO_TEST_CASE (verify_no_error)
393 auto dir = setup (1, "no_error");
394 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
396 path const cpl_file = dir / dcp_test1_cpl();
397 path const pkl_file = dir / dcp_test1_pkl();
398 path const assetmap_file = dir / "ASSETMAP.xml";
400 auto st = stages.begin();
401 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
402 BOOST_REQUIRE (st->second);
403 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
405 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
406 BOOST_REQUIRE (st->second);
407 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
409 BOOST_CHECK_EQUAL (st->first, "Checking reel");
410 BOOST_REQUIRE (!st->second);
412 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
413 BOOST_REQUIRE (st->second);
414 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
416 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
417 BOOST_REQUIRE (st->second);
418 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
420 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
421 BOOST_REQUIRE (st->second);
422 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
424 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
425 BOOST_REQUIRE (st->second);
426 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
428 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
429 BOOST_REQUIRE (st->second);
430 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
431 ++st; BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
432 BOOST_REQUIRE (st->second);
433 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
435 BOOST_REQUIRE (st == stages.end());
437 for (auto note: notes) {
438 BOOST_CHECK(note.type() == dcp::VerificationNote::Type::OK);
443 BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash)
445 using namespace boost::filesystem;
447 auto dir = setup (1, "incorrect_picture_sound_hash");
448 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
450 auto video_path = path(dir / "video.mxf");
451 HashCalculator video_calc(video_path);
452 auto mod = fopen(video_path.string().c_str(), "r+b");
454 BOOST_REQUIRE_EQUAL(fseek(mod, -16, SEEK_END), 0);
456 BOOST_REQUIRE(fwrite(&x, sizeof(x), 1, mod) == 1);
459 auto audio_path = path(dir / "audio.mxf");
460 HashCalculator audio_calc(audio_path);
461 mod = fopen(audio_path.string().c_str(), "r+b");
463 BOOST_REQUIRE_EQUAL(fseek(mod, 0, SEEK_END), 0);
464 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
467 dcp::ASDCPErrorSuspender sus;
468 check_verify_result (
472 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
473 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
474 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
475 dcp::VerificationNote(
476 dcp::VerificationNote::Type::OK,
477 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
479 canonical(cpl->file().get())
480 ).set_cpl_id(dcp_test1_cpl_id()),
481 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
482 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
483 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
484 dcp::VerificationNote(
485 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path)
486 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(video_calc.old_hash()).set_calculated_hash(video_calc.new_hash()),
487 dcp::VerificationNote(
488 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path)
489 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(audio_calc.old_hash()).set_calculated_hash(audio_calc.new_hash()),
494 BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes)
496 using namespace boost::filesystem;
498 auto dir = setup (1, "mismatched_picture_sound_hashes");
499 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
501 HashCalculator calc(dir / dcp_test1_cpl());
504 Editor e (dir / dcp_test1_pkl());
505 e.replace ("<Hash>", "<Hash>x");
508 check_verify_result (
512 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
513 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
514 dcp::VerificationNote(
515 dcp::VerificationNote::Type::OK,
516 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
518 canonical(cpl->file().get())
519 ).set_cpl_id(cpl->id()),
520 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
521 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
522 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
523 dcp::VerificationNote(
524 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
525 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash("x" + calc.old_hash()).set_calculated_hash(calc.old_hash()),
526 dcp::VerificationNote(
527 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf")
528 ).set_cpl_id(dcp_test1_cpl_id()),
529 dcp::VerificationNote(
530 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf")
531 ).set_cpl_id(dcp_test1_cpl_id()),
532 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'x3M7YTgvFKXXMEGLkIbV4miC90FE=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 28 },
533 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xskI+5b/9LA/y6h0mcyxysJYanxI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 12 },
534 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xvsVjRV9vhTBPUWfE/TT1o2vdQsI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 20 },
539 BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind)
541 auto dir = setup (1, "failed_read_content_kind");
543 HashCalculator calc(dir / dcp_test1_cpl());
546 Editor e (dir / dcp_test1_cpl());
547 e.replace ("<ContentKind>", "<ContentKind>x");
550 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
552 check_verify_result (
556 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
557 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
558 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
559 dcp::VerificationNote(
560 dcp::VerificationNote::Type::OK,
561 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
563 canonical(cpl->file().get())
564 ).set_cpl_id(cpl->id()),
565 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
566 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
567 dcp::VerificationNote(
568 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
569 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
570 dcp::VerificationNote(
571 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer")
572 ).set_cpl_id(dcp_test1_cpl_id())
579 dcp_test1_cpl_path(string suffix)
581 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_cpl());
587 dcp_test1_pkl_path(string suffix)
589 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_pkl());
595 asset_map (string suffix)
597 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", suffix);
601 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_rate)
603 auto const suffix = "invalid_picture_frame_rate";
605 replace(suffix, &dcp_test1_cpl_path, "<FrameRate>24 1", "<FrameRate>99 1");
607 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
608 auto const cpl_path = find_cpl(dir);
609 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
611 std::vector<dcp::VerificationNote> expected =
613 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
614 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
615 dcp::VerificationNote(
616 dcp::VerificationNote::Type::OK,
617 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
619 canonical(cpl->file().get())
620 ).set_cpl_id(cpl->id()),
621 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
622 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
623 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
624 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
625 dcp::VerificationNote(
626 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
627 ).set_cpl_id(cpl->id()).set_calculated_hash("7n7GQ2TbxQbmHYuAR8ml7XDOep8=").set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI="),
628 dcp::VerificationNote(
629 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, string{"99/1"}
630 ).set_cpl_id(cpl->id())
633 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
636 BOOST_AUTO_TEST_CASE (verify_missing_asset)
638 auto dir = setup (1, "missing_asset");
639 remove (dir / "video.mxf");
641 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
643 check_verify_result (
647 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
648 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
649 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
650 dcp::VerificationNote(
651 dcp::VerificationNote::Type::OK,
652 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
654 canonical(cpl->file().get())
655 ).set_cpl_id(cpl->id()),
656 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
657 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
658 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_ASSET, canonical(dir) / "video.mxf" }
663 BOOST_AUTO_TEST_CASE (verify_empty_asset_path)
665 auto const suffix = "empty_asset_path";
667 replace("empty_asset_path", &asset_map, "<Path>video.mxf</Path>", "<Path></Path>");
669 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
670 auto const cpl_path = find_cpl(dir);
671 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
673 std::vector<dcp::VerificationNote> expected = {
674 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
675 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
676 dcp::VerificationNote(
677 dcp::VerificationNote::Type::OK,
678 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
680 canonical(cpl->file().get())
681 ).set_cpl_id(cpl->id()),
682 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
683 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
684 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
685 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_ASSET_PATH }
688 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
692 BOOST_AUTO_TEST_CASE (verify_mismatched_standard)
694 auto const suffix = "mismatched_standard";
696 replace(suffix, &dcp_test1_cpl_path, "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#");
698 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
699 auto const cpl_path = find_cpl(dir);
700 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
702 std::vector<dcp::VerificationNote> expected = {
703 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
704 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
705 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
706 dcp::VerificationNote(
707 dcp::VerificationNote::Type::OK,
708 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
710 canonical(cpl->file().get())
711 ).set_cpl_id(cpl->id()),
712 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
713 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
714 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
715 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_STANDARD },
716 dcp::VerificationNote(
717 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "invalid character encountered", canonical(cpl_path), 42
718 ).set_cpl_id(cpl->id()),
719 dcp::VerificationNote(
720 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'Id'", canonical(cpl_path), 53
721 ).set_cpl_id(cpl->id()),
722 dcp::VerificationNote(
723 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'EditRate'", canonical(cpl_path), 54
724 ).set_cpl_id(cpl->id()),
725 dcp::VerificationNote(
726 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'IntrinsicDuration'", canonical(cpl_path), 55
727 ).set_cpl_id(cpl->id()),
728 dcp::VerificationNote(
729 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
730 "element 'Id' is not allowed for content model '(Id,AnnotationText?,EditRate,IntrinsicDuration,"
731 "EntryPoint?,Duration?,FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
732 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,MainSoundSampleRate,"
733 "MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,ExtensionMetadataList?,)'",
734 canonical(cpl_path), 149
735 ).set_cpl_id(cpl->id()),
736 dcp::VerificationNote(
737 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
738 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("FZ9E7L/pOuJ6aZfbiaANTv8BFOo=")
741 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
745 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_id)
747 auto const suffix = "invalid_xml_cpl_id";
749 /* There's no MISMATCHED_CPL_HASHES error here because it can't find the correct hash by ID (since the ID is wrong) */
750 replace("invalid_xml_cpl_id", &dcp_test1_cpl_path, "<Id>urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358ab", "<Id>urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358a");
752 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
753 auto const cpl_path = find_cpl(dir);
754 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
756 std::vector<dcp::VerificationNote> expected = {
757 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
758 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
759 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
760 dcp::VerificationNote(
761 dcp::VerificationNote::Type::OK,
762 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
764 canonical(cpl->file().get())
765 ).set_cpl_id(cpl->id()),
766 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
767 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
768 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
769 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
770 dcp::VerificationNote(
771 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
772 "value 'urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358a' does not match regular expression "
773 "facet 'urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'", canonical(cpl_path), 3
774 ).set_cpl_id(cpl->id())
777 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
781 BOOST_AUTO_TEST_CASE (verify_invalid_xml_issue_date)
783 auto const suffix = "invalid_xml_issue_date";
785 replace("invalid_xml_issue_date", &dcp_test1_cpl_path, "<IssueDate>", "<IssueDate>x");
787 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
788 auto const cpl_path = find_cpl(dir);
789 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
791 std::vector<dcp::VerificationNote> expected = {
792 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
793 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
794 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
795 dcp::VerificationNote(
796 dcp::VerificationNote::Type::OK,
797 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
799 canonical(cpl->file().get())
800 ).set_cpl_id(cpl->id()),
801 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
802 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
803 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
804 dcp::VerificationNote(
805 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
806 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("sz3BeIugJ567q3HMnA62JeRw4TE="),
807 dcp::VerificationNote(
808 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
809 "invalid character encountered",
810 canonical(cpl_path), 5
811 ).set_cpl_id(cpl->id()),
814 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
818 BOOST_AUTO_TEST_CASE (verify_invalid_xml_pkl_id)
820 auto const suffix = "invalid_xml_pkl_id";
822 replace("invalid_xml_pkl_id", &dcp_test1_pkl_path, "<Id>urn:uuid:" + dcp_test1_pkl_id().substr(0, 3), "<Id>urn:uuid:x" + dcp_test1_pkl_id().substr(1, 2));
824 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
825 auto const pkl_path = find_pkl(dir);
826 auto const cpl_path = find_cpl(dir);
827 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
829 std::vector<dcp::VerificationNote> expected = {
830 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
831 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
832 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
833 dcp::VerificationNote(
834 dcp::VerificationNote::Type::OK,
835 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
837 canonical(cpl->file().get())
838 ).set_cpl_id(cpl->id()),
839 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
840 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
841 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
842 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
843 dcp::VerificationNote(
844 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
845 "value 'urn:uuid:x199d58b-5ef8-4d49-b270-07e590ccb280' does not match regular "
846 "expression facet 'urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'",
847 canonical(pkl_path), 3
851 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
855 BOOST_AUTO_TEST_CASE (verify_invalid_xml_asset_map_id)
857 auto const suffix = "invalid_xml_asset_map_id";
859 replace("invalid_xml_asset_map_id", &asset_map, "<Id>urn:uuid:" + dcp_test1_asset_map_id.substr(0, 3), "<Id>urn:uuid:x" + dcp_test1_asset_map_id.substr(1, 2));
861 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
862 auto const cpl_path = find_cpl(dir);
863 auto const asset_map_path = find_asset_map(dir);
864 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
866 std::vector<dcp::VerificationNote> expected = {
867 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
868 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
869 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
870 dcp::VerificationNote(
871 dcp::VerificationNote::Type::OK,
872 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
874 canonical(cpl->file().get())
875 ).set_cpl_id(cpl->id()),
876 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
877 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
878 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
879 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
880 dcp::VerificationNote(
881 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
882 "value 'urn:uuid:x17b3de4-6dda-408d-b19b-6711354b0bc3' does not match regular "
883 "expression facet 'urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'",
884 canonical(asset_map_path), 3
888 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
892 BOOST_AUTO_TEST_CASE (verify_invalid_standard)
895 auto dir = setup (3, "verify_invalid_standard");
896 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
898 path const cpl_file = dir / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
899 path const pkl_file = dir / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
900 path const assetmap_file = dir / "ASSETMAP";
901 auto cpl = std::make_shared<dcp::CPL>(cpl_file);
903 auto st = stages.begin();
904 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
905 BOOST_REQUIRE (st->second);
906 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
908 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
909 BOOST_REQUIRE (st->second);
910 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
912 BOOST_CHECK_EQUAL (st->first, "Checking reel");
913 BOOST_REQUIRE (!st->second);
915 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
916 BOOST_REQUIRE (st->second);
917 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
919 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
920 BOOST_REQUIRE (st->second);
921 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
923 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
924 BOOST_REQUIRE (st->second);
925 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
927 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
928 BOOST_REQUIRE (st->second);
929 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
931 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
932 BOOST_REQUIRE (st->second);
933 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
935 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
936 BOOST_REQUIRE (st->second);
937 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
939 BOOST_REQUIRE (st == stages.end());
941 vector<dcp::VerificationNote> expected = {
942 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
943 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
944 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
945 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
946 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
947 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl),
948 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl)
951 for (int j = 0; j < 24; ++j) {
953 dcp::VerificationNote(
954 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
955 ).set_cpl_id(cpl->id())
959 check_verify_result(notes, expected);
962 /* DCP with a short asset */
963 BOOST_AUTO_TEST_CASE (verify_invalid_duration)
965 auto dir = setup (8, "invalid_duration");
969 BOOST_REQUIRE(dcp.cpls().size() == 1);
970 auto cpl = dcp.cpls()[0];
972 vector<dcp::VerificationNote> expected = {
973 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
974 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
975 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
976 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
977 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
978 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
979 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
980 dcp::VerificationNote(
981 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
982 ).set_cpl_id(cpl->id()),
983 dcp::VerificationNote(
984 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
985 ).set_cpl_id(cpl->id()),
986 dcp::VerificationNote(
987 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
988 ).set_cpl_id(cpl->id()),
989 dcp::VerificationNote(
990 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
991 ).set_cpl_id(cpl->id()),
992 dcp::VerificationNote(
993 dcp::VerificationNote::Type::WARNING,
994 dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT,
996 ).set_cpl_id(cpl->id())
999 for (int i = 0; i < 23; ++i) {
1001 dcp::VerificationNote(
1002 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
1003 ).set_cpl_id(cpl->id())
1007 check_verify_result({ dir }, {}, expected);
1012 shared_ptr<dcp::CPL>
1013 dcp_from_frame (dcp::ArrayData const& frame, path dir)
1015 auto asset = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
1016 create_directories (dir);
1017 auto writer = asset->start_write(dir / "pic.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
1018 for (int i = 0; i < 24; ++i) {
1019 writer->write (frame.data(), frame.size());
1021 writer->finalize ();
1023 auto reel_asset = make_shared<dcp::ReelMonoPictureAsset>(asset, 0);
1024 return write_dcp_with_single_asset (dir, reel_asset);
1028 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_size_in_bytes)
1030 int const too_big = 1302083 * 2;
1032 /* Compress a black image */
1033 auto image = black_image ();
1034 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1035 BOOST_REQUIRE (frame.size() < too_big);
1037 /* Place it in a bigger block with some zero padding at the end */
1038 dcp::ArrayData oversized_frame(too_big);
1039 memcpy (oversized_frame.data(), frame.data(), frame.size());
1040 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
1042 path const dir("build/test/verify_invalid_picture_frame_size_in_bytes");
1043 prepare_directory (dir);
1044 auto cpl = dcp_from_frame (oversized_frame, dir);
1046 vector<dcp::VerificationNote> expected = {
1047 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1048 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1049 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1050 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1051 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1052 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1055 for (auto i = 0; i < 24; ++i) {
1057 dcp::VerificationNote(
1058 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1059 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1063 for (auto i = 0; i < 24; ++i) {
1065 dcp::VerificationNote(
1066 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1067 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1072 dcp::VerificationNote(
1073 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1074 ).set_cpl_id(cpl->id())
1077 check_verify_result({ dir }, {}, expected);
1081 BOOST_AUTO_TEST_CASE (verify_nearly_invalid_picture_frame_size_in_bytes)
1083 int const nearly_too_big = 1302083 * 0.98;
1085 /* Compress a black image */
1086 auto image = black_image ();
1087 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1088 BOOST_REQUIRE (frame.size() < nearly_too_big);
1090 /* Place it in a bigger block with some zero padding at the end */
1091 dcp::ArrayData oversized_frame(nearly_too_big);
1092 memcpy (oversized_frame.data(), frame.data(), frame.size());
1093 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
1095 path const dir("build/test/verify_nearly_invalid_picture_frame_size_in_bytes");
1096 prepare_directory (dir);
1097 auto cpl = dcp_from_frame (oversized_frame, dir);
1099 vector<dcp::VerificationNote> expected = {
1100 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1101 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1102 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1103 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1104 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1105 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1108 for (auto i = 0; i < 24; ++i) {
1110 dcp::VerificationNote(
1111 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1112 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1116 for (auto i = 0; i < 24; ++i) {
1118 dcp::VerificationNote(
1119 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1120 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1125 dcp::VerificationNote(
1126 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1127 ).set_cpl_id(cpl->id())
1130 check_verify_result ({ dir }, {}, expected);
1134 BOOST_AUTO_TEST_CASE (verify_valid_picture_frame_size_in_bytes)
1136 /* Compress a black image */
1137 auto image = black_image ();
1138 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1139 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1141 path const dir("build/test/verify_valid_picture_frame_size_in_bytes");
1142 prepare_directory (dir);
1143 auto cpl = dcp_from_frame (frame, dir);
1145 check_verify_result(
1149 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1150 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1151 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1152 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1153 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1154 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1155 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1156 dcp::VerificationNote(dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()).set_cpl_id(cpl->id())
1161 BOOST_AUTO_TEST_CASE (verify_valid_interop_subtitles)
1163 path const dir("build/test/verify_valid_interop_subtitles");
1164 prepare_directory (dir);
1165 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1166 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1167 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1168 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1170 check_verify_result (
1174 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1175 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1176 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1177 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1178 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1179 dcp::VerificationNote(
1180 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1181 ).set_cpl_id(cpl->id())
1186 BOOST_AUTO_TEST_CASE(verify_catch_missing_font_file_with_interop_ccap)
1188 path const dir("build/test/verify_catch_missing_font_file_with_interop_ccap");
1189 prepare_directory(dir);
1190 copy_file("test/data/subs1.xml", dir / "ccap.xml");
1191 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "ccap.xml");
1192 auto reel_asset = make_shared<dcp::ReelInteropClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1193 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1195 check_verify_result (
1199 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1200 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1201 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1202 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1203 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1204 dcp::VerificationNote(
1205 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1206 ).set_cpl_id(cpl->id())
1211 BOOST_AUTO_TEST_CASE (verify_invalid_interop_subtitles)
1213 using namespace boost::filesystem;
1215 path const dir("build/test/verify_invalid_interop_subtitles");
1216 prepare_directory (dir);
1217 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1218 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1219 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1220 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1223 Editor e (dir / "subs.xml");
1224 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
1227 check_verify_result (
1231 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1232 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1233 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1234 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1235 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1236 dcp::VerificationNote(
1237 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 5
1238 ).set_cpl_id(cpl->id()),
1239 dcp::VerificationNote(
1240 dcp::VerificationNote::Type::ERROR,
1241 dcp::VerificationNote::Code::INVALID_XML,
1242 string("element 'Foo' is not allowed for content model '(SubtitleID,MovieTitle,ReelNumber,Language,LoadFont*,Font*,Subtitle*)'"),
1245 ).set_cpl_id(cpl->id()),
1246 dcp::VerificationNote(
1247 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1248 ).set_cpl_id(cpl->id())
1253 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_no_subtitles)
1255 path const dir("build/test/verify_interop_subtitle_asset_with_no_subtitles");
1256 prepare_directory(dir);
1257 copy_file("test/data/subs4.xml", dir / "subs.xml");
1258 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1259 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1260 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1262 check_verify_result (
1266 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1267 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1268 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1269 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1270 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1271 dcp::VerificationNote(
1272 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1273 ).set_cpl_id(cpl->id()),
1274 dcp::VerificationNote(
1275 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1276 ).set_cpl_id(cpl->id())
1282 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_single_space_subtitle)
1284 path const dir("build/test/verify_interop_subtitle_asset_with_single_space_subtitle");
1285 prepare_directory(dir);
1286 copy_file("test/data/subs5.xml", dir / "subs.xml");
1287 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1288 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1289 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1291 check_verify_result (
1295 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1296 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1297 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1298 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1299 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1300 dcp::VerificationNote(
1301 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"Arial"}
1302 ).set_cpl_id(cpl->id())
1308 BOOST_AUTO_TEST_CASE (verify_valid_smpte_subtitles)
1310 path const dir("build/test/verify_valid_smpte_subtitles");
1311 prepare_directory (dir);
1312 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1313 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1314 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1315 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1317 check_verify_result(
1321 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1322 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1323 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1324 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1325 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1326 dcp::VerificationNote(
1327 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1328 ).set_cpl_id(cpl->id()),
1329 dcp::VerificationNote(
1330 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-04-14T13:19:14.000+02:00"}
1331 ).set_cpl_id(cpl->id()),
1332 dcp::VerificationNote(
1333 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1334 ).set_cpl_id(cpl->id()),
1339 BOOST_AUTO_TEST_CASE (verify_invalid_smpte_subtitles)
1341 using namespace boost::filesystem;
1343 path const dir("build/test/verify_invalid_smpte_subtitles");
1344 prepare_directory (dir);
1345 /* This broken_smpte.mxf does not use urn:uuid: for its subtitle ID, which we tolerate (rightly or wrongly) */
1346 copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
1347 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1348 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1349 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1351 check_verify_result (
1355 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1356 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1357 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1358 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1359 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1360 dcp::VerificationNote(
1361 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 2
1362 ).set_cpl_id(cpl->id()),
1363 dcp::VerificationNote(
1364 dcp::VerificationNote::Type::ERROR,
1365 dcp::VerificationNote::Code::INVALID_XML,
1366 string("element 'Foo' is not allowed for content model '(Id,ContentTitleText,AnnotationText?,IssueDate,ReelNumber?,Language?,EditRate,TimeCodeRate,StartTime?,DisplayType?,LoadFont*,SubtitleList)'"),
1369 ).set_cpl_id(cpl->id()),
1370 dcp::VerificationNote(
1371 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
1372 ).set_cpl_id(cpl->id()),
1373 dcp::VerificationNote(
1374 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1375 ).set_cpl_id(cpl->id()),
1376 dcp::VerificationNote(
1377 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2020-05-09T00:29:21.000+02:00"}
1378 ).set_cpl_id(cpl->id()),
1379 dcp::VerificationNote(
1380 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1381 ).set_cpl_id(cpl->id()),
1386 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles)
1388 path const dir("build/test/verify_empty_text_node_in_subtitles");
1389 prepare_directory (dir);
1390 copy_file ("test/data/empty_text.mxf", dir / "subs.mxf");
1391 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1392 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1393 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1395 check_verify_result (
1399 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1400 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1401 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1402 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1403 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1404 dcp::VerificationNote(
1405 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1406 ).set_cpl_id(cpl->id()),
1407 dcp::VerificationNote(
1408 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
1409 ).set_cpl_id(cpl->id()),
1410 dcp::VerificationNote(
1411 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
1412 ).set_cpl_id(cpl->id()),
1413 dcp::VerificationNote(
1414 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1415 ).set_cpl_id(cpl->id()),
1416 dcp::VerificationNote(
1417 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-08-09T18:34:46.000+02:00"}
1418 ).set_cpl_id(cpl->id()),
1419 dcp::VerificationNote(
1420 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1421 ).set_cpl_id(cpl->id())
1426 /** A <Text> node with no content except some <Font> nodes, which themselves do have content */
1427 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_child_nodes)
1429 path const dir("build/test/verify_empty_text_node_in_subtitles_with_child_nodes");
1430 prepare_directory (dir);
1431 copy_file ("test/data/empty_but_with_children.xml", dir / "subs.xml");
1432 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1433 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1434 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1436 check_verify_result (
1440 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1441 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1442 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1443 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1444 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1445 dcp::VerificationNote(
1446 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1447 ).set_cpl_id(cpl->id())
1452 /** A <Text> node with no content except some <Font> nodes, which themselves also have no content */
1453 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_empty_child_nodes)
1455 path const dir("build/test/verify_empty_text_node_in_subtitles_with_empty_child_nodes");
1456 prepare_directory (dir);
1457 copy_file ("test/data/empty_with_empty_children.xml", dir / "subs.xml");
1458 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1459 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1460 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1462 check_verify_result (
1466 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1467 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1468 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1469 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1470 dcp::VerificationNote(
1471 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1472 ).set_cpl_id(cpl->id()),
1473 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1474 dcp::VerificationNote(
1475 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1476 ).set_cpl_id(cpl->id()),
1477 dcp::VerificationNote(
1478 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1479 ).set_cpl_id(cpl->id())
1484 BOOST_AUTO_TEST_CASE (verify_external_asset)
1486 path const ov_dir("build/test/verify_external_asset");
1487 prepare_directory (ov_dir);
1489 auto image = black_image ();
1490 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1491 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1492 dcp_from_frame (frame, ov_dir);
1494 dcp::DCP ov (ov_dir);
1497 path const vf_dir("build/test/verify_external_asset_vf");
1498 prepare_directory (vf_dir);
1500 auto picture = ov.cpls()[0]->reels()[0]->main_picture();
1501 auto cpl = write_dcp_with_single_asset (vf_dir, picture);
1503 check_verify_result (
1507 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1508 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1509 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1510 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1511 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1512 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, picture->asset()->id() },
1513 dcp::VerificationNote(
1514 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1515 ).set_cpl_id(cpl->id())
1520 BOOST_AUTO_TEST_CASE (verify_valid_cpl_metadata)
1522 path const dir("build/test/verify_valid_cpl_metadata");
1523 prepare_directory (dir);
1525 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1526 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1527 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1529 auto reel = make_shared<dcp::Reel>();
1530 reel->add (reel_asset);
1532 reel->add (make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 16 * 24), 0));
1533 reel->add (simple_markers(16 * 24));
1535 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1537 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1538 cpl->set_main_sound_sample_rate (48000);
1539 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1540 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1541 cpl->set_version_number (1);
1545 dcp.set_annotation_text("hello");
1550 /* DCP with invalid CompositionMetadataAsset */
1551 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag)
1553 using namespace boost::filesystem;
1555 path const dir("build/test/verify_invalid_cpl_metadata_bad_tag");
1556 prepare_directory (dir);
1558 auto reel = make_shared<dcp::Reel>();
1559 reel->add (black_picture_asset(dir));
1560 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1562 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1563 cpl->set_main_sound_sample_rate (48000);
1564 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1565 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1566 cpl->set_version_number (1);
1568 reel->add (simple_markers());
1572 dcp.set_annotation_text("hello");
1575 HashCalculator calc(find_cpl(dir));
1578 Editor e (find_cpl(dir));
1579 e.replace ("MainSound", "MainSoundX");
1582 check_verify_result (
1586 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1587 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1588 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1589 dcp::VerificationNote(
1590 dcp::VerificationNote::Type::OK,
1591 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1592 string{"1440x1080"},
1594 ).set_cpl_id(cpl->id()),
1595 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1596 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1597 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1598 dcp::VerificationNote(
1599 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXConfiguration'"), canonical(cpl->file().get()), 50
1600 ).set_cpl_id(cpl->id()),
1601 dcp::VerificationNote(
1602 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXSampleRate'"), canonical(cpl->file().get()), 51
1603 ).set_cpl_id(cpl->id()),
1604 dcp::VerificationNote(
1605 dcp::VerificationNote::Type::ERROR,
1606 dcp::VerificationNote::Code::INVALID_XML,
1607 string("element 'meta:MainSoundXConfiguration' is not allowed for content model "
1608 "'(Id,AnnotationText?,EditRate,IntrinsicDuration,EntryPoint?,Duration?,"
1609 "FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
1610 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,"
1611 "MainSoundSampleRate,MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,"
1612 "ExtensionMetadataList?,)'"),
1613 canonical(cpl->file().get()),
1614 71).set_cpl_id(cpl->id()),
1615 dcp::VerificationNote(
1616 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
1617 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
1622 /* DCP with invalid CompositionMetadataAsset */
1623 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag)
1625 path const dir("build/test/verify_invalid_cpl_metadata_missing_tag");
1626 prepare_directory (dir);
1628 auto reel = make_shared<dcp::Reel>();
1629 reel->add (black_picture_asset(dir));
1630 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1632 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1633 cpl->set_main_sound_sample_rate (48000);
1634 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1635 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1639 dcp.set_annotation_text("hello");
1643 Editor e (find_cpl(dir));
1644 e.replace ("meta:Width", "meta:WidthX");
1647 check_verify_result (
1650 {{ dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::FAILED_READ, string("missing XML tag Width in MainPictureStoredArea") }}
1655 BOOST_AUTO_TEST_CASE (verify_invalid_language1)
1657 path const dir("build/test/verify_invalid_language1");
1658 prepare_directory (dir);
1659 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1660 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1661 asset->_language = "wrong-andbad";
1662 asset->write (dir / "subs.mxf");
1663 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1664 reel_asset->_language = "badlang";
1665 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1667 check_verify_result (
1671 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1672 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1673 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1674 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1675 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1676 dcp::VerificationNote(
1677 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang")
1678 ).set_cpl_id(cpl->id()),
1679 dcp::VerificationNote(
1680 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad")
1681 ).set_cpl_id(cpl->id()),
1682 dcp::VerificationNote(
1683 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1684 ).set_cpl_id(cpl->id())
1689 /* SMPTE DCP with invalid <Language> in the MainClosedCaption reel and also in the XML within the MXF */
1690 BOOST_AUTO_TEST_CASE (verify_invalid_language2)
1692 path const dir("build/test/verify_invalid_language2");
1693 prepare_directory (dir);
1694 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1695 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1696 asset->_language = "wrong-andbad";
1697 asset->write (dir / "subs.mxf");
1698 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1699 reel_asset->_language = "badlang";
1700 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1702 check_verify_result (
1706 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1707 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1708 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1709 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1710 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1711 dcp::VerificationNote(
1712 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang")
1713 ).set_cpl_id(cpl->id()),
1714 dcp::VerificationNote(
1715 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad")
1716 ).set_cpl_id(cpl->id()),
1717 dcp::VerificationNote(
1718 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1719 ).set_cpl_id(cpl->id())
1724 /* SMPTE DCP with invalid <Language> in the MainSound reel, the CPL additional subtitles languages and
1725 * the release territory.
1727 BOOST_AUTO_TEST_CASE (verify_invalid_language3)
1729 path const dir("build/test/verify_invalid_language3");
1730 prepare_directory (dir);
1732 auto picture = simple_picture (dir, "foo");
1733 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
1734 auto reel = make_shared<dcp::Reel>();
1735 reel->add (reel_picture);
1736 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "frobozz");
1737 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
1738 reel->add (reel_sound);
1739 reel->add (simple_markers());
1741 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1743 cpl->_additional_subtitle_languages.push_back("this-is-wrong");
1744 cpl->_additional_subtitle_languages.push_back("andso-is-this");
1745 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1746 cpl->set_main_sound_sample_rate (48000);
1747 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1748 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1749 cpl->set_version_number (1);
1750 cpl->_release_territory = "fred-jim";
1751 auto dcp = make_shared<dcp::DCP>(dir);
1753 dcp->set_annotation_text("hello");
1756 check_verify_result (
1760 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
1761 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1762 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1763 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1764 dcp::VerificationNote(
1765 dcp::VerificationNote::Type::OK,
1766 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1767 string{"1440x1080"},
1769 ).set_cpl_id(cpl->id()),
1770 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1771 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1772 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
1773 dcp::VerificationNote(
1774 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("this-is-wrong")
1775 ).set_cpl_id(cpl->id()),
1776 dcp::VerificationNote(
1777 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("andso-is-this")
1778 ).set_cpl_id(cpl->id()),
1779 dcp::VerificationNote(
1780 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("fred-jim")
1781 ).set_cpl_id(cpl->id()),
1782 dcp::VerificationNote(
1783 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("frobozz")
1784 ).set_cpl_id(cpl->id()),
1790 std::tuple<vector<dcp::VerificationNote>, shared_ptr<dcp::CPL>, boost::filesystem::path>
1791 check_picture_size (int width, int height, int frame_rate, bool three_d)
1793 using namespace boost::filesystem;
1795 path dcp_path = "build/test/verify_picture_test";
1796 prepare_directory (dcp_path);
1798 shared_ptr<dcp::PictureAsset> mp;
1800 mp = make_shared<dcp::StereoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1802 mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1804 auto picture_writer = mp->start_write(dcp_path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
1806 auto image = black_image (dcp::Size(width, height));
1807 auto j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048);
1808 int const length = three_d ? frame_rate * 2 : frame_rate;
1809 for (int i = 0; i < length; ++i) {
1810 picture_writer->write (j2c.data(), j2c.size());
1812 picture_writer->finalize ();
1814 auto d = make_shared<dcp::DCP>(dcp_path);
1815 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1816 cpl->set_annotation_text ("A Test DCP");
1817 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
1818 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1819 cpl->set_main_sound_sample_rate (48000);
1820 cpl->set_main_picture_stored_area(dcp::Size(width, height));
1821 cpl->set_main_picture_active_area(dcp::Size(width, height));
1822 cpl->set_version_number (1);
1824 auto reel = make_shared<dcp::Reel>();
1827 reel->add (make_shared<dcp::ReelStereoPictureAsset>(std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp), 0));
1829 reel->add (make_shared<dcp::ReelMonoPictureAsset>(std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp), 0));
1832 reel->add (simple_markers(frame_rate));
1837 d->set_annotation_text("A Test DCP");
1840 /* It seems that for the Ubuntu 16.04 compiler we can't use an initializer list here */
1841 return std::tuple<vector<dcp::VerificationNote>, shared_ptr<dcp::CPL>, boost::filesystem::path>{ dcp::verify({dcp_path}, {}, &stage, &progress, {}, xsd_test).notes, cpl, dcp_path };
1847 check_picture_size_ok (int width, int height, int frame_rate, bool three_d)
1849 vector<dcp::VerificationNote> notes;
1850 shared_ptr<dcp::CPL> cpl;
1851 boost::filesystem::path dir;
1852 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1854 std::vector<dcp::VerificationNote> expected = {
1855 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1856 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1857 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1858 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1859 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1860 dcp::VerificationNote(
1861 dcp::VerificationNote::Type::OK,
1862 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1863 dcp::String::compose("%1x%2", width, height),
1865 ).set_cpl_id(cpl->id()),
1866 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1867 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl)
1869 check_verify_result(notes, expected);
1875 check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d)
1877 vector<dcp::VerificationNote> notes;
1878 shared_ptr<dcp::CPL> cpl;
1879 boost::filesystem::path dir;
1880 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1882 std::vector<dcp::VerificationNote> expected = {
1883 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1884 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1885 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1886 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1887 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1888 dcp::VerificationNote(
1889 dcp::VerificationNote::Type::OK,
1890 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1891 dcp::String::compose("%1x%2", width, height),
1893 ).set_cpl_id(cpl->id()),
1894 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1895 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1896 dcp::VerificationNote(
1897 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS, dcp::String::compose("%1x%2", width, height), canonical(dir / "video.mxf")
1898 ).set_cpl_id(cpl->id())
1900 check_verify_result(notes, expected);
1906 check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d)
1908 vector<dcp::VerificationNote> notes;
1909 shared_ptr<dcp::CPL> cpl;
1910 boost::filesystem::path dir;
1911 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1913 std::vector<dcp::VerificationNote> expected = {
1914 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1915 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1916 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1917 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1918 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1919 dcp::VerificationNote(
1920 dcp::VerificationNote::Type::OK,
1921 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1922 dcp::String::compose("%1x%2", width, height),
1924 ).set_cpl_id(cpl->id()),
1925 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1926 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1927 dcp::VerificationNote(
1928 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, dcp::String::compose("%1/1", frame_rate * (three_d ? 2 : 1))
1929 ).set_cpl_id(cpl->id()),
1930 dcp::VerificationNote(
1931 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_2K, dcp::String::compose("%1/1", frame_rate), canonical(dir / "video.mxf")
1932 ).set_cpl_id(cpl->id())
1935 check_verify_result(notes, expected);
1941 check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d)
1943 vector<dcp::VerificationNote> notes;
1944 shared_ptr<dcp::CPL> cpl;
1945 boost::filesystem::path dir;
1946 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1948 std::vector<dcp::VerificationNote> expected = {
1949 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1950 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1951 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1952 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1953 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1954 dcp::VerificationNote(
1955 dcp::VerificationNote::Type::OK,
1956 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1957 dcp::String::compose("%1x%2", width, height),
1959 ).set_cpl_id(cpl->id()),
1960 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1961 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1962 dcp::VerificationNote(
1963 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_4K, dcp::String::compose("%1/1", frame_rate), canonical(dir / "video.mxf")
1964 ).set_cpl_id(cpl->id())
1967 check_verify_result(notes, expected);
1971 BOOST_AUTO_TEST_CASE (verify_picture_size)
1973 using namespace boost::filesystem;
1976 check_picture_size_ok (2048, 858, 24, false);
1977 check_picture_size_ok (2048, 858, 25, false);
1978 check_picture_size_ok (2048, 858, 48, false);
1979 check_picture_size_ok (2048, 858, 24, true);
1980 check_picture_size_ok (2048, 858, 25, true);
1981 check_picture_size_ok (2048, 858, 48, true);
1984 check_picture_size_ok (1998, 1080, 24, false);
1985 check_picture_size_ok (1998, 1080, 25, false);
1986 check_picture_size_ok (1998, 1080, 48, false);
1987 check_picture_size_ok (1998, 1080, 24, true);
1988 check_picture_size_ok (1998, 1080, 25, true);
1989 check_picture_size_ok (1998, 1080, 48, true);
1992 check_picture_size_ok (4096, 1716, 24, false);
1995 check_picture_size_ok (3996, 2160, 24, false);
1997 /* Bad frame size */
1998 check_picture_size_bad_frame_size (2050, 858, 24, false);
1999 check_picture_size_bad_frame_size (2048, 658, 25, false);
2000 check_picture_size_bad_frame_size (1920, 1080, 48, true);
2001 check_picture_size_bad_frame_size (4000, 2000, 24, true);
2003 /* Bad 2K frame rate */
2004 check_picture_size_bad_2k_frame_rate (2048, 858, 26, false);
2005 check_picture_size_bad_2k_frame_rate (2048, 858, 31, false);
2006 check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true);
2008 /* Bad 4K frame rate */
2009 check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false);
2010 check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false);
2013 vector<dcp::VerificationNote> notes;
2014 shared_ptr<dcp::CPL> cpl;
2015 boost::filesystem::path dir;
2016 std::tie(notes, cpl, dir) = check_picture_size(3996, 2160, 24, true);
2018 std::vector<dcp::VerificationNote> expected = {
2019 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2020 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2021 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2022 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2023 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2024 dcp::VerificationNote(
2025 dcp::VerificationNote::Type::OK,
2026 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2027 string{"3996x2160"},
2029 ).set_cpl_id(cpl->id()),
2030 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2031 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2032 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D },
2039 add_test_subtitle (shared_ptr<dcp::SubtitleAsset> asset, int start_frame, int end_frame, float v_position = 0, dcp::VAlign v_align = dcp::VAlign::CENTER, string text = "Hello")
2042 std::make_shared<dcp::SubtitleString>(
2050 dcp::Time(start_frame, 24, 24),
2051 dcp::Time(end_frame, 24, 24),
2053 dcp::HAlign::CENTER,
2057 dcp::Direction::LTR,
2064 std::vector<dcp::Ruby>()
2070 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
2072 path const dir("build/test/verify_invalid_closed_caption_xml_size_in_bytes");
2073 prepare_directory (dir);
2075 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2076 for (int i = 0; i < 2048; ++i) {
2077 add_test_subtitle (asset, i * 24, i * 24 + 20);
2080 asset->set_language (dcp::LanguageTag("de-DE"));
2081 asset->write (dir / "subs.mxf");
2082 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
2083 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2085 check_verify_result (
2089 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2090 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2091 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2092 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2093 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2094 dcp::VerificationNote(
2095 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2096 ).set_cpl_id(cpl->id()),
2097 dcp::VerificationNote(
2098 dcp::VerificationNote::Type::BV21_ERROR,
2099 dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES,
2101 canonical(dir / "subs.mxf")
2102 ).set_cpl_id(cpl->id()),
2103 dcp::VerificationNote(
2104 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2105 ).set_cpl_id(cpl->id()),
2106 dcp::VerificationNote(
2107 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2108 ).set_cpl_id(cpl->id())
2114 shared_ptr<dcp::SMPTESubtitleAsset>
2115 make_large_subtitle_asset (path font_file)
2117 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2118 dcp::ArrayData big_fake_font(1024 * 1024);
2119 big_fake_font.write (font_file);
2120 for (int i = 0; i < 116; ++i) {
2121 asset->add_font (dcp::String::compose("big%1", i), big_fake_font);
2129 verify_timed_text_asset_too_large (string name)
2131 auto const dir = path("build/test") / name;
2132 prepare_directory (dir);
2133 auto asset = make_large_subtitle_asset (dir / "font.ttf");
2134 add_test_subtitle (asset, 0, 240);
2135 asset->set_language (dcp::LanguageTag("de-DE"));
2136 asset->write (dir / "subs.mxf");
2138 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), 240, 0);
2139 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2141 check_verify_result (
2145 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2146 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2147 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2148 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2149 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2150 dcp::VerificationNote(
2151 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, string("121698284"), canonical(dir / "subs.mxf")
2152 ).set_cpl_id(cpl->id()),
2153 dcp::VerificationNote(
2154 dcp::VerificationNote::Type::BV21_ERROR,
2155 dcp::VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES,
2156 dcp::raw_convert<string>(121634816),
2157 canonical(dir / "subs.mxf")
2158 ).set_cpl_id(cpl->id()),
2159 dcp::VerificationNote(
2160 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2161 ).set_cpl_id(cpl->id()),
2162 dcp::VerificationNote(
2163 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2164 ).set_cpl_id(cpl->id()),
2165 dcp::VerificationNote(
2166 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2167 ).set_cpl_id(cpl->id())
2172 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
2174 verify_timed_text_asset_too_large<dcp::ReelSMPTESubtitleAsset>("verify_subtitle_asset_too_large");
2175 verify_timed_text_asset_too_large<dcp::ReelSMPTEClosedCaptionAsset>("verify_closed_caption_asset_too_large");
2179 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language)
2181 path dir = "build/test/verify_missing_subtitle_language";
2182 prepare_directory (dir);
2183 auto dcp = make_simple (dir, 1, 106);
2186 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2187 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2188 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2189 "<ContentTitleText>Content</ContentTitleText>"
2190 "<AnnotationText>Annotation</AnnotationText>"
2191 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2192 "<ReelNumber>1</ReelNumber>"
2193 "<EditRate>24 1</EditRate>"
2194 "<TimeCodeRate>24</TimeCodeRate>"
2195 "<StartTime>00:00:00:00</StartTime>"
2196 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2198 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2199 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2200 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2206 dcp::File xml_file(dir / "subs.xml", "w");
2207 BOOST_REQUIRE (xml_file);
2208 xml_file.write(xml.c_str(), xml.size(), 1);
2210 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2211 subs->write (dir / "subs.mxf");
2213 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2214 auto cpl = dcp->cpls()[0];
2215 cpl->reels()[0]->add(reel_subs);
2218 check_verify_result (
2222 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2223 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2224 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2225 dcp::VerificationNote(
2226 dcp::VerificationNote::Type::OK,
2227 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2228 string{"1998x1080"},
2230 ).set_cpl_id(cpl->id()),
2231 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2232 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2233 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2234 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2235 dcp::VerificationNote(
2236 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
2237 ).set_cpl_id(cpl->id()),
2238 dcp::VerificationNote(
2239 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2240 ).set_cpl_id(cpl->id())
2245 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
2247 path path ("build/test/verify_mismatched_subtitle_languages");
2248 auto constexpr reel_length = 192;
2249 auto dcp = make_simple (path, 2, reel_length);
2250 auto cpl = dcp->cpls()[0];
2253 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2254 subs->set_language (dcp::LanguageTag("de-DE"));
2255 subs->add (simple_subtitle());
2257 subs->write (path / "subs1.mxf");
2258 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2259 cpl->reels()[0]->add(reel_subs);
2263 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2264 subs->set_language (dcp::LanguageTag("en-US"));
2265 subs->add (simple_subtitle());
2267 subs->write (path / "subs2.mxf");
2268 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2269 cpl->reels()[1]->add(reel_subs);
2274 check_verify_result (
2278 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2279 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2280 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2281 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2282 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2283 dcp::VerificationNote(
2284 dcp::VerificationNote::Type::OK,
2285 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2286 string{"1998x1080"},
2288 ).set_cpl_id(cpl->id()),
2289 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2290 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2291 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2292 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2293 dcp::VerificationNote(
2294 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2295 ).set_cpl_id(cpl->id()),
2296 dcp::VerificationNote(
2297 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2298 ).set_cpl_id(cpl->id()),
2299 dcp::VerificationNote(
2300 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES
2301 ).set_cpl_id(cpl->id()),
2306 BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
2308 path path ("build/test/verify_multiple_closed_caption_languages_allowed");
2309 auto constexpr reel_length = 192;
2310 auto dcp = make_simple (path, 2, reel_length);
2311 auto cpl = dcp->cpls()[0];
2314 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2315 ccaps->set_language (dcp::LanguageTag("de-DE"));
2316 ccaps->add (simple_subtitle());
2318 ccaps->write (path / "subs1.mxf");
2319 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2320 cpl->reels()[0]->add(reel_ccaps);
2324 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2325 ccaps->set_language (dcp::LanguageTag("en-US"));
2326 ccaps->add (simple_subtitle());
2328 ccaps->write (path / "subs2.mxf");
2329 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2330 cpl->reels()[1]->add(reel_ccaps);
2335 check_verify_result (
2339 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2340 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2341 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2342 dcp::VerificationNote(
2343 dcp::VerificationNote::Type::OK,
2344 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2345 string{"1998x1080"},
2347 ).set_cpl_id(cpl->id()),
2348 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2349 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2350 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2351 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2352 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2353 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2354 dcp::VerificationNote(
2355 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2356 ).set_cpl_id(cpl->id()),
2357 dcp::VerificationNote(
2358 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2359 ).set_cpl_id(cpl->id())
2364 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time)
2366 path dir = "build/test/verify_missing_subtitle_start_time";
2367 prepare_directory (dir);
2368 auto dcp = make_simple (dir, 1, 106);
2371 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2372 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2373 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2374 "<ContentTitleText>Content</ContentTitleText>"
2375 "<AnnotationText>Annotation</AnnotationText>"
2376 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2377 "<ReelNumber>1</ReelNumber>"
2378 "<Language>de-DE</Language>"
2379 "<EditRate>24 1</EditRate>"
2380 "<TimeCodeRate>24</TimeCodeRate>"
2381 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2383 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2384 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2385 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2391 dcp::File xml_file(dir / "subs.xml", "w");
2392 BOOST_REQUIRE (xml_file);
2393 xml_file.write(xml.c_str(), xml.size(), 1);
2395 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2396 subs->write (dir / "subs.mxf");
2398 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2399 auto cpl = dcp->cpls()[0];
2400 cpl->reels()[0]->add(reel_subs);
2403 check_verify_result (
2407 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2408 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2409 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2410 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2411 dcp::VerificationNote(
2412 dcp::VerificationNote::Type::OK,
2413 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2414 string{"1998x1080"},
2416 ).set_cpl_id(cpl->id()),
2417 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2418 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2419 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2420 dcp::VerificationNote(
2421 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2422 ).set_cpl_id(cpl->id()),
2423 dcp::VerificationNote(
2424 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2425 ).set_cpl_id(cpl->id())
2430 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time)
2432 path dir = "build/test/verify_invalid_subtitle_start_time";
2433 prepare_directory (dir);
2434 auto dcp = make_simple (dir, 1, 106);
2437 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2438 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2439 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2440 "<ContentTitleText>Content</ContentTitleText>"
2441 "<AnnotationText>Annotation</AnnotationText>"
2442 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2443 "<ReelNumber>1</ReelNumber>"
2444 "<Language>de-DE</Language>"
2445 "<EditRate>24 1</EditRate>"
2446 "<TimeCodeRate>24</TimeCodeRate>"
2447 "<StartTime>00:00:02:00</StartTime>"
2448 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2450 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2451 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2452 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2458 dcp::File xml_file(dir / "subs.xml", "w");
2459 BOOST_REQUIRE (xml_file);
2460 xml_file.write(xml.c_str(), xml.size(), 1);
2462 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2463 subs->write (dir / "subs.mxf");
2465 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2466 auto cpl = dcp->cpls()[0];
2467 cpl->reels().front()->add(reel_subs);
2470 check_verify_result (
2474 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2475 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2476 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2477 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2478 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2479 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2480 dcp::VerificationNote(
2481 dcp::VerificationNote::Type::OK,
2482 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2483 string{"1998x1080"},
2485 ).set_cpl_id(cpl->id()),
2486 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2487 dcp::VerificationNote(
2488 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2489 ).set_cpl_id(cpl->id()),
2490 dcp::VerificationNote(
2491 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2492 ).set_cpl_id(cpl->id())
2500 TestText (int in_, int out_, float v_position_ = 0, dcp::VAlign v_align_ = dcp::VAlign::CENTER, string text_ = "Hello")
2503 , v_position(v_position_)
2511 dcp::VAlign v_align;
2517 shared_ptr<dcp::CPL>
2518 dcp_with_text(path dir, vector<TestText> subs, optional<dcp::Key> key = boost::none, optional<string> key_id = boost::none)
2520 prepare_directory (dir);
2521 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2522 asset->set_start_time (dcp::Time());
2523 for (auto i: subs) {
2524 add_test_subtitle (asset, i.in, i.out, i.v_position, i.v_align, i.text);
2526 asset->set_language (dcp::LanguageTag("de-DE"));
2527 if (key && key_id) {
2528 asset->set_key(*key);
2529 asset->set_key_id(*key_id);
2532 asset->write (dir / "subs.mxf");
2534 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2535 return write_dcp_with_single_asset (dir, reel_asset);
2540 shared_ptr<dcp::CPL>
2541 dcp_with_text_from_file (path dir, boost::filesystem::path subs_xml)
2543 prepare_directory (dir);
2544 auto asset = make_shared<dcp::SMPTESubtitleAsset>(subs_xml);
2545 asset->set_start_time (dcp::Time());
2546 asset->set_language (dcp::LanguageTag("de-DE"));
2548 auto subs_mxf = dir / "subs.mxf";
2549 asset->write (subs_mxf);
2551 /* The call to write() puts the asset into the DCP correctly but it will have
2552 * XML re-written by our parser. Overwrite the MXF using the given file's verbatim
2555 ASDCP::TimedText::MXFWriter writer;
2556 ASDCP::WriterInfo writer_info;
2557 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
2559 Kumu::hex2bin (asset->id().c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
2560 DCP_ASSERT (c == Kumu::UUID_Length);
2561 ASDCP::TimedText::TimedTextDescriptor descriptor;
2562 descriptor.ContainerDuration = asset->intrinsic_duration();
2563 Kumu::hex2bin (asset->xml_id()->c_str(), descriptor.AssetID, ASDCP::UUIDlen, &c);
2564 DCP_ASSERT (c == Kumu::UUID_Length);
2565 ASDCP::Result_t r = writer.OpenWrite (subs_mxf.string().c_str(), writer_info, descriptor, 16384);
2566 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2567 r = writer.WriteTimedTextResource (dcp::file_to_string(subs_xml));
2568 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2571 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2572 return write_dcp_with_single_asset (dir, reel_asset);
2576 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_first_text_time)
2578 auto const dir = path("build/test/verify_invalid_subtitle_first_text_time");
2579 /* Just too early */
2580 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24 - 1, 5 * 24 }});
2581 check_verify_result (
2585 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2586 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2587 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2588 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2589 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2590 dcp::VerificationNote(
2591 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2592 ).set_cpl_id(cpl->id()),
2593 dcp::VerificationNote(
2594 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2595 ).set_cpl_id(cpl->id())
2601 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time)
2603 auto const dir = path("build/test/verify_valid_subtitle_first_text_time");
2604 /* Just late enough */
2605 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 5 * 24 }});
2606 check_verify_result(
2610 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2611 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2612 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2613 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2614 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2615 dcp::VerificationNote(
2616 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2617 ).set_cpl_id(cpl->id())
2622 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
2624 auto const dir = path("build/test/verify_valid_subtitle_first_text_time_on_second_reel");
2625 prepare_directory (dir);
2627 auto asset1 = make_shared<dcp::SMPTESubtitleAsset>();
2628 asset1->set_start_time (dcp::Time());
2629 /* Just late enough */
2630 add_test_subtitle (asset1, 4 * 24, 5 * 24);
2631 asset1->set_language (dcp::LanguageTag("de-DE"));
2633 asset1->write (dir / "subs1.mxf");
2634 auto reel_asset1 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset1, dcp::Fraction(24, 1), 5 * 24, 0);
2635 auto reel1 = make_shared<dcp::Reel>();
2636 reel1->add (reel_asset1);
2637 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 5 * 24);
2638 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
2639 reel1->add (markers1);
2641 auto asset2 = make_shared<dcp::SMPTESubtitleAsset>();
2642 asset2->set_start_time (dcp::Time());
2644 /* This would be too early on first reel but should be OK on the second */
2645 add_test_subtitle (asset2, 3, 4 * 24);
2646 asset2->set_language (dcp::LanguageTag("de-DE"));
2647 asset2->write (dir / "subs2.mxf");
2648 auto reel_asset2 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset2, dcp::Fraction(24, 1), 4 * 24, 0);
2649 auto reel2 = make_shared<dcp::Reel>();
2650 reel2->add (reel_asset2);
2651 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 4 * 24);
2652 markers2->set (dcp::Marker::LFOC, dcp::Time(4 * 24 - 1, 24, 24));
2653 reel2->add (markers2);
2655 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
2658 auto dcp = make_shared<dcp::DCP>(dir);
2660 dcp->set_annotation_text("hello");
2663 check_verify_result(
2667 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2668 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2669 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2670 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2671 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2672 dcp::VerificationNote(
2673 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2674 ).set_cpl_id(cpl->id())
2679 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_spacing)
2681 auto const dir = path("build/test/verify_invalid_subtitle_spacing");
2682 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2686 { 5 * 24 + 1, 6 * 24 },
2688 check_verify_result (
2692 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2693 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2694 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2695 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2696 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2697 dcp::VerificationNote(
2698 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING
2699 ).set_cpl_id(cpl->id()),
2700 dcp::VerificationNote(
2701 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2702 ).set_cpl_id(cpl->id())
2707 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_spacing)
2709 auto const dir = path("build/test/verify_valid_subtitle_spacing");
2710 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2714 { 5 * 24 + 16, 8 * 24 },
2717 check_verify_result(
2721 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2722 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2723 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2724 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2725 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2726 dcp::VerificationNote(
2727 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2728 ).set_cpl_id(cpl->id())
2733 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_duration)
2735 auto const dir = path("build/test/verify_invalid_subtitle_duration");
2736 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 1 }});
2737 check_verify_result (
2741 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2742 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2743 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2744 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2745 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2746 dcp::VerificationNote(
2747 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION
2748 ).set_cpl_id(cpl->id()),
2749 dcp::VerificationNote(
2750 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2751 ).set_cpl_id(cpl->id())
2756 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_duration)
2758 auto const dir = path("build/test/verify_valid_subtitle_duration");
2759 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 17 }});
2761 check_verify_result(
2765 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2766 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2767 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2768 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2769 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2770 dcp::VerificationNote(
2771 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2772 ).set_cpl_id(cpl->id())
2777 BOOST_AUTO_TEST_CASE (verify_subtitle_overlapping_reel_boundary)
2779 auto const dir = path("build/test/verify_subtitle_overlapping_reel_boundary");
2780 prepare_directory (dir);
2781 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2782 asset->set_start_time (dcp::Time());
2783 add_test_subtitle (asset, 0, 4 * 24);
2785 asset->set_language (dcp::LanguageTag("de-DE"));
2786 asset->write (dir / "subs.mxf");
2788 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 3 * 24, 0);
2789 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2790 check_verify_result (
2794 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2795 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2796 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2797 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2798 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2799 dcp::VerificationNote(
2800 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "72 96", boost::filesystem::canonical(asset->file().get())
2801 ).set_cpl_id(cpl->id()),
2802 dcp::VerificationNote(
2803 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2804 ).set_cpl_id(cpl->id()),
2805 dcp::VerificationNote(
2806 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY
2807 ).set_cpl_id(cpl->id()),
2808 dcp::VerificationNote(
2809 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2810 ).set_cpl_id(cpl->id())
2816 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count1)
2818 auto const dir = path ("build/test/invalid_subtitle_line_count1");
2819 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2822 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2823 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2824 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2825 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
2827 check_verify_result (
2831 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2832 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2833 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2834 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2835 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2836 dcp::VerificationNote(
2837 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2838 ).set_cpl_id(cpl->id()),
2839 dcp::VerificationNote(
2840 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2841 ).set_cpl_id(cpl->id())
2846 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count1)
2848 auto const dir = path ("build/test/verify_valid_subtitle_line_count1");
2849 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2852 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2853 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2854 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2857 check_verify_result(
2861 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2862 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2863 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2864 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2865 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2866 dcp::VerificationNote(
2867 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2868 ).set_cpl_id(cpl->id())
2873 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count2)
2875 auto const dir = path ("build/test/verify_invalid_subtitle_line_count2");
2876 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2879 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2880 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2881 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2882 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
2884 check_verify_result (
2888 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2889 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2890 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2891 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2892 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2893 dcp::VerificationNote(
2894 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2895 ).set_cpl_id(cpl->id()),
2896 dcp::VerificationNote(
2897 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2898 ).set_cpl_id(cpl->id())
2903 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count2)
2905 auto const dir = path ("build/test/verify_valid_subtitle_line_count2");
2906 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2909 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2910 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2911 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2912 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
2915 check_verify_result(
2919 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2920 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2921 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2922 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2923 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2924 dcp::VerificationNote(
2925 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2926 ).set_cpl_id(cpl->id())
2931 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length1)
2933 auto const dir = path ("build/test/verify_invalid_subtitle_line_length1");
2934 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2937 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123" }
2939 check_verify_result (
2943 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2944 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2945 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2946 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2947 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2948 dcp::VerificationNote(
2949 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH
2950 ).set_cpl_id(cpl->id()),
2951 dcp::VerificationNote(
2952 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2953 ).set_cpl_id(cpl->id())
2958 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length2)
2960 auto const dir = path ("build/test/verify_invalid_subtitle_line_length2");
2961 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2964 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123456789012345678901234567890" }
2966 check_verify_result (
2970 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2971 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2972 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2973 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2974 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2975 dcp::VerificationNote(
2976 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH
2977 ).set_cpl_id(cpl->id()),
2978 dcp::VerificationNote(
2979 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2980 ).set_cpl_id(cpl->id())
2985 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1)
2987 auto const dir = path ("build/test/verify_valid_closed_caption_line_count1");
2988 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
2991 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2992 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2993 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2994 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
2996 check_verify_result (
3000 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3001 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3002 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3003 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3004 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3005 dcp::VerificationNote(
3006 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
3007 ).set_cpl_id(cpl->id()),
3008 dcp::VerificationNote(
3009 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3010 ).set_cpl_id(cpl->id())
3015 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2)
3017 auto const dir = path ("build/test/verify_valid_closed_caption_line_count2");
3018 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3021 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
3022 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
3023 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
3026 check_verify_result(
3030 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3031 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3032 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3033 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3034 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3035 dcp::VerificationNote(
3036 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3037 ).set_cpl_id(cpl->id())
3042 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3)
3044 auto const dir = path ("build/test/verify_invalid_closed_caption_line_count3");
3045 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3048 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
3049 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
3050 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
3051 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
3053 check_verify_result (
3057 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3058 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3059 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3060 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3061 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3062 dcp::VerificationNote(
3063 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
3064 ).set_cpl_id(cpl->id()),
3065 dcp::VerificationNote(
3066 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3067 ).set_cpl_id(cpl->id())
3072 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4)
3074 auto const dir = path ("build/test/verify_valid_closed_caption_line_count4");
3075 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3078 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
3079 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
3080 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
3081 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
3084 check_verify_result(
3088 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3089 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3090 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3091 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3092 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3093 dcp::VerificationNote(
3094 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3095 ).set_cpl_id(cpl->id())
3100 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_length)
3102 auto const dir = path ("build/test/verify_valid_closed_caption_line_length");
3103 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3106 { 96, 300, 0.0, dcp::VAlign::CENTER, "01234567890123456789012345678901" }
3109 check_verify_result (
3113 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3114 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3115 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3116 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3117 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3118 dcp::VerificationNote(
3119 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3120 ).set_cpl_id(cpl->id())
3125 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length)
3127 auto const dir = path ("build/test/verify_invalid_closed_caption_line_length");
3128 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3131 { 96, 300, 0.0, dcp::VAlign::CENTER, "0123456789012345678901234567890123" }
3133 check_verify_result (
3137 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3138 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3139 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3140 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3141 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3142 dcp::VerificationNote(
3143 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH
3144 ).set_cpl_id(cpl->id()),
3145 dcp::VerificationNote(
3146 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3147 ).set_cpl_id(cpl->id())
3152 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign1)
3154 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign1");
3155 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3158 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3159 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3160 { 96, 300, 0.2, dcp::VAlign::TOP, "fine" },
3162 check_verify_result (
3166 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3167 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3168 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3169 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3170 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3171 dcp::VerificationNote(
3172 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3173 ).set_cpl_id(cpl->id())
3178 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign2)
3180 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign2");
3181 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3184 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3185 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3186 { 96, 300, 0.2, dcp::VAlign::CENTER, "not fine" },
3188 check_verify_result (
3192 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3193 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3194 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3195 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3196 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3197 dcp::VerificationNote(
3198 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN
3199 ).set_cpl_id(cpl->id()),
3200 dcp::VerificationNote(
3201 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3202 ).set_cpl_id(cpl->id())
3207 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering1)
3209 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering1");
3210 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3213 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3214 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3215 { 96, 300, 0.2, dcp::VAlign::TOP, "fine" },
3218 check_verify_result(
3222 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3223 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3224 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3225 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3226 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3227 dcp::VerificationNote(
3228 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3229 ).set_cpl_id(cpl->id())
3234 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering2)
3236 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering2");
3237 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3240 { 96, 300, 0.2, dcp::VAlign::BOTTOM, "This" },
3241 { 96, 300, 0.1, dcp::VAlign::BOTTOM, "is" },
3242 { 96, 300, 0.0, dcp::VAlign::BOTTOM, "also fine" },
3245 check_verify_result(
3249 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3250 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3251 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3252 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3253 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3254 dcp::VerificationNote(
3255 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3256 ).set_cpl_id(cpl->id())
3261 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering3)
3263 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering3");
3264 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering3.xml");
3265 check_verify_result (
3269 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3270 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3271 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3272 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3273 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3274 dcp::VerificationNote(
3275 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING
3276 ).set_cpl_id(cpl->id()),
3277 dcp::VerificationNote(
3278 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3279 ).set_cpl_id(cpl->id())
3284 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering4)
3286 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering4");
3287 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering4.xml");
3289 check_verify_result(
3293 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3294 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3295 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3296 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3297 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3298 dcp::VerificationNote(
3299 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3300 ).set_cpl_id(cpl->id())
3306 BOOST_AUTO_TEST_CASE (verify_invalid_sound_frame_rate)
3308 path const dir("build/test/verify_invalid_sound_frame_rate");
3309 prepare_directory (dir);
3311 auto picture = simple_picture (dir, "foo");
3312 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
3313 auto reel = make_shared<dcp::Reel>();
3314 reel->add (reel_picture);
3315 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000, boost::none);
3316 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
3317 reel->add (reel_sound);
3318 reel->add (simple_markers());
3319 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3321 auto dcp = make_shared<dcp::DCP>(dir);
3323 dcp->set_annotation_text("hello");
3326 check_verify_result (
3330 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3331 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3332 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3333 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3334 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
3335 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3336 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
3337 dcp::VerificationNote(
3338 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SOUND_FRAME_RATE, string("96000"), canonical(dir / "audiofoo.mxf")
3339 ).set_cpl_id(cpl->id()),
3340 dcp::VerificationNote(
3341 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3342 ).set_cpl_id(cpl->id())
3347 BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text)
3349 path const dir("build/test/verify_missing_cpl_annotation_text");
3350 auto dcp = make_simple (dir);
3353 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3355 auto const cpl = dcp->cpls()[0];
3357 HashCalculator calc(cpl->file().get());
3360 BOOST_REQUIRE (cpl->file());
3361 Editor e(cpl->file().get());
3362 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "");
3365 check_verify_result (
3369 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3370 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3371 dcp::VerificationNote(
3372 dcp::VerificationNote::Type::OK,
3373 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3374 string{"1998x1080"},
3376 ).set_cpl_id(cpl->id()),
3377 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3378 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3379 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3380 dcp::VerificationNote(
3381 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3382 ).set_cpl_id(cpl->id()),
3383 dcp::VerificationNote(
3384 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3385 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
3390 BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text)
3392 path const dir("build/test/verify_mismatched_cpl_annotation_text");
3393 auto dcp = make_simple (dir);
3396 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3397 auto const cpl = dcp->cpls()[0];
3399 HashCalculator calc(cpl->file().get());
3402 BOOST_REQUIRE (cpl->file());
3403 Editor e(cpl->file().get());
3404 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "<AnnotationText>A Test DCP 1</AnnotationText>");
3407 check_verify_result (
3411 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3412 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3413 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3414 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3415 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3416 dcp::VerificationNote(
3417 dcp::VerificationNote::Type::OK,
3418 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3419 string{"1998x1080"},
3421 ).set_cpl_id(cpl->id()),
3422 dcp::VerificationNote(
3423 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3424 ).set_cpl_id(cpl->id()),
3425 dcp::VerificationNote(
3426 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3427 ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()).set_cpl_id(cpl->id())
3432 BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration)
3434 path const dir("build/test/verify_mismatched_asset_duration");
3435 prepare_directory (dir);
3436 shared_ptr<dcp::DCP> dcp (new dcp::DCP(dir));
3437 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3439 shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (dir, "", 24);
3440 shared_ptr<dcp::SoundAsset> ms = simple_sound (dir, "", dcp::MXFMetadata(), "en-US", 25);
3442 auto reel = make_shared<dcp::Reel>(
3443 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
3444 make_shared<dcp::ReelSoundAsset>(ms, 0)
3447 reel->add (simple_markers());
3451 dcp->set_annotation_text("A Test DCP");
3454 check_verify_result (
3458 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3459 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3460 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3461 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3462 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3463 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3464 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3465 dcp::VerificationNote(
3466 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_DURATION
3467 ).set_cpl_id(cpl->id()),
3468 dcp::VerificationNote(
3469 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl->file().get())
3470 ).set_cpl_id(cpl->id())
3477 shared_ptr<dcp::CPL>
3478 verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool add_to_reel2)
3480 prepare_directory (dir);
3481 auto dcp = make_shared<dcp::DCP>(dir);
3482 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3484 auto constexpr reel_length = 192;
3486 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3487 subs->set_language (dcp::LanguageTag("de-DE"));
3488 subs->set_start_time (dcp::Time());
3489 subs->add (simple_subtitle());
3491 subs->write (dir / "subs.mxf");
3492 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
3494 auto reel1 = make_shared<dcp::Reel>(
3495 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3496 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3500 reel1->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3503 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3504 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3505 reel1->add (markers1);
3509 auto reel2 = make_shared<dcp::Reel>(
3510 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3511 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3515 reel2->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3518 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3519 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3520 reel2->add (markers2);
3525 dcp->set_annotation_text("A Test DCP");
3532 BOOST_AUTO_TEST_CASE (verify_missing_main_subtitle_from_some_reels)
3535 path dir ("build/test/missing_main_subtitle_from_some_reels");
3536 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, false);
3537 check_verify_result (
3541 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3542 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3543 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3544 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3545 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3546 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3547 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3548 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3549 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3550 dcp::VerificationNote(
3551 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS
3552 ).set_cpl_id(cpl->id()),
3553 dcp::VerificationNote(
3554 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3555 ).set_cpl_id(cpl->id())
3561 path dir ("build/test/verify_subtitles_must_be_in_all_reels2");
3562 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, true);
3563 check_verify_result(
3567 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3568 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3569 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3570 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3571 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3572 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3573 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3574 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3575 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3576 dcp::VerificationNote(
3577 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3578 ).set_cpl_id(cpl->id())
3583 path dir ("build/test/verify_subtitles_must_be_in_all_reels1");
3584 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, false, false);
3585 check_verify_result(
3589 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3590 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3591 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3592 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3593 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3594 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3595 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3596 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3597 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3598 dcp::VerificationNote(
3599 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3600 ).set_cpl_id(cpl->id())
3607 shared_ptr<dcp::CPL>
3608 verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1, int caps_in_reel2)
3610 prepare_directory (dir);
3611 auto dcp = make_shared<dcp::DCP>(dir);
3612 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3614 auto constexpr reel_length = 192;
3616 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3617 subs->set_language (dcp::LanguageTag("de-DE"));
3618 subs->set_start_time (dcp::Time());
3619 subs->add (simple_subtitle());
3621 subs->write (dir / "subs.mxf");
3623 auto reel1 = make_shared<dcp::Reel>(
3624 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3625 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3628 for (int i = 0; i < caps_in_reel1; ++i) {
3629 reel1->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3632 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3633 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3634 reel1->add (markers1);
3638 auto reel2 = make_shared<dcp::Reel>(
3639 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3640 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3643 for (int i = 0; i < caps_in_reel2; ++i) {
3644 reel2->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3647 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3648 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3649 reel2->add (markers2);
3654 dcp->set_annotation_text("A Test DCP");
3661 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_asset_counts)
3664 path dir ("build/test/mismatched_closed_caption_asset_counts");
3665 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4);
3666 check_verify_result (
3670 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3671 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3672 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3673 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3674 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3675 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3676 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3677 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3678 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3679 dcp::VerificationNote(
3680 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS
3681 ).set_cpl_id(cpl->id()),
3682 dcp::VerificationNote(
3683 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3684 ).set_cpl_id(cpl->id())
3689 path dir ("build/test/verify_closed_captions_must_be_in_all_reels2");
3690 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4);
3691 check_verify_result(
3695 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3696 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3697 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3698 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3699 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3700 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3701 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3702 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3703 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3704 dcp::VerificationNote(
3705 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3706 ).set_cpl_id(cpl->id())
3711 path dir ("build/test/verify_closed_captions_must_be_in_all_reels3");
3712 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0);
3713 check_verify_result(
3717 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3718 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3719 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3720 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3721 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3722 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3723 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3724 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3725 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3726 dcp::VerificationNote(
3727 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3728 ).set_cpl_id(cpl->id())
3736 verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost::function<void (shared_ptr<T>)> adjust)
3738 prepare_directory (dir);
3739 auto dcp = make_shared<dcp::DCP>(dir);
3740 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3742 auto constexpr reel_length = 192;
3744 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3745 subs->set_language (dcp::LanguageTag("de-DE"));
3746 subs->set_start_time (dcp::Time());
3747 subs->add (simple_subtitle());
3749 subs->write (dir / "subs.mxf");
3750 auto reel_text = make_shared<T>(subs, dcp::Fraction(24, 1), reel_length, 0);
3753 auto reel = make_shared<dcp::Reel>(
3754 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
3755 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
3758 reel->add (reel_text);
3760 reel->add (simple_markers(reel_length));
3765 dcp->set_annotation_text("A Test DCP");
3768 check_verify_result (
3772 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3773 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3774 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3775 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3776 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3777 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3778 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3779 dcp::VerificationNote(
3780 dcp::VerificationNote::Type::BV21_ERROR, code, subs->id()
3781 ).set_cpl_id(cpl->id()),
3782 dcp::VerificationNote(
3783 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3784 ).set_cpl_id(cpl->id())
3789 BOOST_AUTO_TEST_CASE (verify_text_entry_point)
3791 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3792 "build/test/verify_subtitle_entry_point_must_be_present",
3793 dcp::VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT,
3794 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3795 asset->unset_entry_point ();
3799 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3800 "build/test/verify_subtitle_entry_point_must_be_zero",
3801 dcp::VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT,
3802 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3803 asset->set_entry_point (4);
3807 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3808 "build/test/verify_closed_caption_entry_point_must_be_present",
3809 dcp::VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT,
3810 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3811 asset->unset_entry_point ();
3815 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3816 "build/test/verify_closed_caption_entry_point_must_be_zero",
3817 dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT,
3818 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3819 asset->set_entry_point (9);
3825 BOOST_AUTO_TEST_CASE (verify_missing_hash)
3829 path const dir("build/test/verify_missing_hash");
3830 auto dcp = make_simple (dir);
3833 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3834 auto const cpl = dcp->cpls()[0];
3835 BOOST_REQUIRE_EQUAL (cpl->reels().size(), 1U);
3836 BOOST_REQUIRE (cpl->reels()[0]->main_picture());
3837 auto asset_id = cpl->reels()[0]->main_picture()->id();
3839 HashCalculator calc(cpl->file().get());
3842 BOOST_REQUIRE (cpl->file());
3843 Editor e(cpl->file().get());
3844 e.delete_first_line_containing("<Hash>");
3847 check_verify_result (
3851 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3852 dcp::VerificationNote(
3853 dcp::VerificationNote::Type::OK,
3854 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3855 string{"1998x1080"},
3857 ).set_cpl_id(cpl->id()),
3858 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3859 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3860 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3861 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3862 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3863 dcp::VerificationNote(
3864 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
3865 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
3866 dcp::VerificationNote(
3867 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id
3868 ).set_cpl_id(cpl->id())
3875 verify_markers_test (
3877 vector<pair<dcp::Marker, dcp::Time>> markers,
3878 vector<dcp::VerificationNote> test_notes
3881 auto dcp = make_simple (dir);
3882 auto cpl = dcp->cpls()[0];
3883 cpl->set_content_kind(dcp::ContentKind::FEATURE);
3884 auto markers_asset = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 24);
3885 for (auto const& i: markers) {
3886 markers_asset->set (i.first, i.second);
3888 cpl->reels()[0]->add(markers_asset);
3891 for (auto& note: test_notes) {
3892 note.set_cpl_id(cpl->id());
3895 test_notes.push_back(ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl));
3896 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl));
3897 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl));
3898 test_notes.push_back(ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl));
3899 test_notes.push_back(
3900 dcp::VerificationNote(
3901 dcp::VerificationNote::Type::OK,
3902 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3903 string{"1998x1080"},
3905 ).set_cpl_id(cpl->id())
3907 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl));
3908 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl));
3909 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl));
3911 check_verify_result({dir}, {}, test_notes);
3915 BOOST_AUTO_TEST_CASE (verify_markers)
3917 verify_markers_test (
3918 "build/test/verify_markers_all_correct",
3920 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3921 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3922 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3923 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3928 verify_markers_test (
3929 "build/test/verify_markers_missing_ffec",
3931 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3932 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3933 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3936 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }
3939 verify_markers_test (
3940 "build/test/verify_markers_missing_ffmc",
3942 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3943 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3944 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3947 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }
3950 verify_markers_test (
3951 "build/test/verify_markers_missing_ffoc",
3953 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3954 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3955 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3958 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC}
3961 verify_markers_test (
3962 "build/test/verify_markers_missing_lfoc",
3964 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3965 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3966 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) }
3969 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }
3972 verify_markers_test (
3973 "build/test/verify_markers_incorrect_ffoc",
3975 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3976 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3977 { dcp::Marker::FFOC, dcp::Time(3, 24, 24) },
3978 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3981 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_FFOC, string("3") }
3984 verify_markers_test (
3985 "build/test/verify_markers_incorrect_lfoc",
3987 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3988 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3989 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3990 { dcp::Marker::LFOC, dcp::Time(18, 24, 24) }
3993 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_LFOC, string("18") }
3998 BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number)
4000 path dir = "build/test/verify_missing_cpl_metadata_version_number";
4001 prepare_directory (dir);
4002 auto dcp = make_simple (dir);
4003 auto cpl = dcp->cpls()[0];
4004 cpl->unset_version_number();
4007 check_verify_result(
4011 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4012 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4013 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4014 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4015 dcp::VerificationNote(
4016 dcp::VerificationNote::Type::OK,
4017 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4018 string{"1998x1080"},
4020 ).set_cpl_id(cpl->id()),
4021 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4022 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4023 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4024 dcp::VerificationNote(
4025 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->file().get()
4026 ).set_cpl_id(cpl->id())
4031 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1)
4033 path dir = "build/test/verify_missing_extension_metadata1";
4034 auto dcp = make_simple (dir);
4037 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
4038 auto cpl = dcp->cpls()[0];
4040 HashCalculator calc(cpl->file().get());
4043 Editor e (cpl->file().get());
4044 e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
4047 check_verify_result (
4051 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4052 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4053 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4054 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4055 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4056 dcp::VerificationNote(
4057 dcp::VerificationNote::Type::OK,
4058 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4059 string{"1998x1080"},
4061 ).set_cpl_id(cpl->id()),
4062 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4063 dcp::VerificationNote(
4064 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4065 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4066 dcp::VerificationNote(
4067 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
4068 ).set_cpl_id(cpl->id())
4073 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2)
4075 path dir = "build/test/verify_missing_extension_metadata2";
4076 auto dcp = make_simple (dir);
4079 auto cpl = dcp->cpls()[0];
4081 HashCalculator calc(cpl->file().get());
4084 Editor e (cpl->file().get());
4085 e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
4088 check_verify_result (
4092 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4093 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4094 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4095 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4096 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4097 dcp::VerificationNote(
4098 dcp::VerificationNote::Type::OK,
4099 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4100 string{"1998x1080"},
4102 ).set_cpl_id(cpl->id()),
4103 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4104 dcp::VerificationNote(
4105 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4106 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4107 dcp::VerificationNote(
4108 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
4109 ).set_cpl_id(cpl->id())
4114 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3)
4116 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata3";
4117 auto dcp = make_simple (dir);
4120 auto const cpl = dcp->cpls()[0];
4122 HashCalculator calc(cpl->file().get());
4125 Editor e (cpl->file().get());
4126 e.replace ("<meta:Name>A", "<meta:NameX>A");
4127 e.replace ("n</meta:Name>", "n</meta:NameX>");
4130 check_verify_result (
4134 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4135 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4136 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4137 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4138 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4139 dcp::VerificationNote(
4140 dcp::VerificationNote::Type::OK,
4141 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4142 string{"1998x1080"},
4144 ).set_cpl_id(cpl->id()),
4145 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4146 dcp::VerificationNote(
4147 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:NameX'"), cpl->file().get(), 70
4148 ).set_cpl_id(cpl->id()),
4149 dcp::VerificationNote(
4150 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:NameX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77).set_cpl_id(cpl->id()),
4151 dcp::VerificationNote(
4152 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4153 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4158 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1)
4160 path dir = "build/test/verify_invalid_extension_metadata1";
4161 auto dcp = make_simple (dir);
4164 auto cpl = dcp->cpls()[0];
4166 HashCalculator calc(cpl->file().get());
4169 Editor e (cpl->file().get());
4170 e.replace ("Application", "Fred");
4173 check_verify_result (
4177 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4178 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4179 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4180 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4181 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4182 dcp::VerificationNote(
4183 dcp::VerificationNote::Type::OK,
4184 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4185 string{"1998x1080"},
4187 ).set_cpl_id(cpl->id()),
4188 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4189 dcp::VerificationNote(
4190 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4191 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4192 dcp::VerificationNote(
4193 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> should be 'Application'"), cpl->file().get()
4194 ).set_cpl_id(cpl->id())
4199 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2)
4201 path dir = "build/test/verify_invalid_extension_metadata2";
4202 auto dcp = make_simple (dir);
4205 auto cpl = dcp->cpls()[0];
4207 HashCalculator calc(cpl->file().get());
4210 Editor e (cpl->file().get());
4211 e.replace ("DCP Constraints Profile", "Fred");
4214 check_verify_result (
4218 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4219 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4220 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4221 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4222 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4223 dcp::VerificationNote(
4224 dcp::VerificationNote::Type::OK,
4225 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4226 string{"1998x1080"},
4228 ).set_cpl_id(cpl->id()),
4229 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4230 dcp::VerificationNote(
4231 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4232 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4233 dcp::VerificationNote(
4234 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'"), cpl->file().get()
4235 ).set_cpl_id(cpl->id())
4240 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6)
4242 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata6";
4243 auto dcp = make_simple (dir);
4246 auto const cpl = dcp->cpls()[0];
4248 HashCalculator calc(cpl->file().get());
4251 Editor e (cpl->file().get());
4252 e.replace ("<meta:Value>", "<meta:ValueX>");
4253 e.replace ("</meta:Value>", "</meta:ValueX>");
4256 check_verify_result (
4260 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4261 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4262 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4263 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4264 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4265 dcp::VerificationNote(
4266 dcp::VerificationNote::Type::OK,
4267 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4268 string{"1998x1080"},
4270 ).set_cpl_id(cpl->id()),
4271 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4272 dcp::VerificationNote(
4273 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:ValueX'"), cpl->file().get(), 74
4274 ).set_cpl_id(cpl->id()),
4275 dcp::VerificationNote(
4276 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:ValueX' is not allowed for content model '(Name,Value)'"), cpl->file().get(), 75
4277 ).set_cpl_id(cpl->id()),
4278 dcp::VerificationNote(
4279 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4280 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
4285 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7)
4287 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata7";
4288 auto dcp = make_simple (dir);
4291 auto const cpl = dcp->cpls()[0];
4293 HashCalculator calc(cpl->file().get());
4296 Editor e (cpl->file().get());
4297 e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
4300 check_verify_result (
4304 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4305 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4306 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4307 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4308 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4309 dcp::VerificationNote(
4310 dcp::VerificationNote::Type::OK,
4311 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4312 string{"1998x1080"},
4314 ).set_cpl_id(cpl->id()),
4315 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4316 dcp::VerificationNote(
4317 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4318 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4319 dcp::VerificationNote(
4320 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Value> property should be 'SMPTE-RDD-52:2020-Bv2.1'"), cpl->file().get()
4321 ).set_cpl_id(cpl->id())
4326 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8)
4328 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata8";
4329 auto dcp = make_simple (dir);
4332 auto const cpl = dcp->cpls()[0];
4334 HashCalculator calc(cpl->file().get());
4337 Editor e (cpl->file().get());
4338 e.replace ("<meta:Property>", "<meta:PropertyX>");
4339 e.replace ("</meta:Property>", "</meta:PropertyX>");
4342 check_verify_result (
4346 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4347 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4348 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4349 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4350 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4351 dcp::VerificationNote(
4352 dcp::VerificationNote::Type::OK,
4353 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4354 string{"1998x1080"},
4356 ).set_cpl_id(cpl->id()),
4357 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4358 dcp::VerificationNote(
4359 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyX'"), cpl->file().get(), 72
4360 ).set_cpl_id(cpl->id()),
4361 dcp::VerificationNote(
4362 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyX' is not allowed for content model '(Property+)'"), cpl->file().get(), 76).set_cpl_id(cpl->id()),
4363 dcp::VerificationNote(
4364 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4365 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4370 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9)
4372 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata9";
4373 auto dcp = make_simple (dir);
4376 auto const cpl = dcp->cpls()[0];
4378 HashCalculator calc(cpl->file().get());
4381 Editor e (cpl->file().get());
4382 e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
4383 e.replace ("</meta:PropertyList>", "</meta:PropertyListX>");
4386 check_verify_result (
4390 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4391 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4392 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4393 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4394 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4395 dcp::VerificationNote(
4396 dcp::VerificationNote::Type::OK,
4397 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4398 string{"1998x1080"},
4400 ).set_cpl_id(cpl->id()),
4401 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4402 dcp::VerificationNote(
4403 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyListX'"), cpl->file().get(), 71
4404 ).set_cpl_id(cpl->id()),
4405 dcp::VerificationNote(
4406 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyListX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77
4407 ).set_cpl_id(cpl->id()),
4408 dcp::VerificationNote(
4409 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4410 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4416 BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content)
4418 path const dir = "build/test/verify_unsigned_cpl_with_encrypted_content";
4419 prepare_directory (dir);
4420 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4421 copy_file (i.path(), dir / i.path().filename());
4424 path const pkl = dir / ( "pkl_" + encryption_test_pkl_id() + ".xml");
4425 path const cpl_path = dir / ( "cpl_" + encryption_test_cpl_id() + ".xml");
4427 HashCalculator calc(cpl_path);
4431 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4434 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4436 check_verify_result (
4440 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4441 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4442 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4443 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4444 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4445 dcp::VerificationNote(
4446 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
4447 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4448 dcp::VerificationNote(
4449 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4450 ).set_cpl_id(cpl->id()),
4451 dcp::VerificationNote(
4452 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4453 ).set_cpl_id(cpl->id()),
4454 dcp::VerificationNote(
4455 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4456 ).set_cpl_id(cpl->id()),
4457 dcp::VerificationNote(
4458 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4459 ).set_cpl_id(cpl->id()),
4460 dcp::VerificationNote(
4461 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4462 ).set_cpl_id(cpl->id()),
4463 dcp::VerificationNote(
4464 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4465 ).set_cpl_id(cpl->id()),
4466 dcp::VerificationNote(
4467 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_path)
4468 ).set_cpl_id(cpl->id())
4473 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_encrypted_content)
4475 path dir = "build/test/unsigned_pkl_with_encrypted_content";
4476 prepare_directory (dir);
4477 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4478 copy_file (i.path(), dir / i.path().filename());
4481 path const cpl_path = dir / ("cpl_" + encryption_test_cpl_id() + ".xml");
4482 path const pkl = dir / ("pkl_" + encryption_test_pkl_id() + ".xml");
4485 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4488 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4490 check_verify_result (
4494 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4495 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4496 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4497 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4498 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4499 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4500 dcp::VerificationNote(
4501 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4502 ).set_cpl_id(cpl->id()),
4503 dcp::VerificationNote(
4504 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4505 ).set_cpl_id(cpl->id()),
4506 dcp::VerificationNote(
4507 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4508 ).set_cpl_id(cpl->id()),
4509 dcp::VerificationNote(
4510 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4511 ).set_cpl_id(cpl->id()),
4512 dcp::VerificationNote(
4513 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4514 ).set_cpl_id(cpl->id()),
4515 dcp::VerificationNote(
4516 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4517 ).set_cpl_id(cpl->id()),
4518 dcp::VerificationNote(
4519 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, encryption_test_pkl_id(), canonical(pkl)
4525 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_unencrypted_content)
4527 path dir = "build/test/verify_unsigned_pkl_with_unencrypted_content";
4528 prepare_directory (dir);
4529 for (auto i: directory_iterator("test/ref/DCP/dcp_test1")) {
4530 copy_file (i.path(), dir / i.path().filename());
4534 Editor e (dir / dcp_test1_pkl());
4535 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4538 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4540 check_verify_result(
4544 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4545 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4546 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4547 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4548 dcp::VerificationNote(
4549 dcp::VerificationNote::Type::OK,
4550 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4551 string{"1998x1080"},
4552 canonical(cpl->file().get())
4553 ).set_cpl_id(cpl->id()),
4554 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4555 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4556 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4561 BOOST_AUTO_TEST_CASE (verify_partially_encrypted)
4563 path dir ("build/test/verify_must_not_be_partially_encrypted");
4564 prepare_directory (dir);
4568 auto signer = make_shared<dcp::CertificateChain>();
4569 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/ca.self-signed.pem")));
4570 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/intermediate.signed.pem")));
4571 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/leaf.signed.pem")));
4572 signer->set_key (dcp::file_to_string("test/ref/crypt/leaf.key"));
4574 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
4578 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction (24, 1), dcp::Standard::SMPTE);
4581 auto writer = mp->start_write(dir / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
4582 dcp::ArrayData j2c ("test/data/flat_red.j2c");
4583 for (int i = 0; i < 24; ++i) {
4584 writer->write (j2c.data(), j2c.size());
4586 writer->finalize ();
4588 auto ms = simple_sound (dir, "", dcp::MXFMetadata(), "de-DE");
4590 auto reel = make_shared<dcp::Reel>(
4591 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
4592 make_shared<dcp::ReelSoundAsset>(ms, 0)
4595 reel->add (simple_markers());
4599 cpl->set_content_version (
4600 {"urn:uri:81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00", "81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00"}
4602 cpl->set_annotation_text ("A Test DCP");
4603 cpl->set_issuer ("OpenDCP 0.0.25");
4604 cpl->set_creator ("OpenDCP 0.0.25");
4605 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
4606 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
4607 cpl->set_main_sound_sample_rate (48000);
4608 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
4609 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
4610 cpl->set_version_number (1);
4614 d.set_issuer("OpenDCP 0.0.25");
4615 d.set_creator("OpenDCP 0.0.25");
4616 d.set_issue_date("2012-07-17T04:45:18+00:00");
4617 d.set_annotation_text("A Test DCP");
4618 d.write_xml(signer);
4620 check_verify_result (
4624 dcp::VerificationNote(
4625 dcp::VerificationNote::Type::OK,
4626 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4627 string{"1440x1080"},
4629 ).set_cpl_id(cpl->id()),
4630 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4631 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4632 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4633 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4634 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4635 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4636 dcp::VerificationNote(
4637 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::PARTIALLY_ENCRYPTED
4638 ).set_cpl_id(cpl->id())
4643 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_2k)
4645 vector<dcp::VerificationNote> notes;
4646 dcp::MonoPictureAsset picture (find_file(private_test / "data" / "JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV", "j2c.mxf"));
4647 auto reader = picture.start_read ();
4648 auto frame = reader->get_frame (0);
4649 verify_j2k(frame, 0, 0, 24, notes);
4650 BOOST_CHECK(notes.empty());
4654 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_4k)
4656 vector<dcp::VerificationNote> notes;
4657 dcp::MonoPictureAsset picture (find_file(private_test / "data" / "sul", "TLR"));
4658 auto reader = picture.start_read ();
4659 auto frame = reader->get_frame (0);
4660 verify_j2k(frame, 0, 0, 24, notes);
4661 BOOST_CHECK(notes.empty());
4665 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp)
4667 boost::filesystem::path dir = "build/test/verify_jpeg2000_codestream_libdcp";
4668 prepare_directory (dir);
4669 auto dcp = make_simple (dir);
4671 vector<dcp::VerificationNote> notes;
4672 dcp::MonoPictureAsset picture (find_file(dir, "video"));
4673 auto reader = picture.start_read ();
4674 auto frame = reader->get_frame (0);
4675 verify_j2k(frame, 0, 0, 24, notes);
4676 BOOST_CHECK(notes.empty());
4680 /** Check that ResourceID and the XML ID being different is spotted */
4681 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id)
4683 boost::filesystem::path const dir = "build/test/verify_mismatched_subtitle_resource_id";
4684 prepare_directory (dir);
4686 ASDCP::WriterInfo writer_info;
4687 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4690 auto mxf_id = dcp::make_uuid ();
4691 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4692 BOOST_REQUIRE (c == Kumu::UUID_Length);
4694 auto resource_id = dcp::make_uuid ();
4695 ASDCP::TimedText::TimedTextDescriptor descriptor;
4696 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4697 DCP_ASSERT (c == Kumu::UUID_Length);
4699 auto xml_id = dcp::make_uuid ();
4700 ASDCP::TimedText::MXFWriter writer;
4701 auto subs_mxf = dir / "subs.mxf";
4702 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4703 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4704 writer.WriteTimedTextResource (dcp::String::compose(
4705 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4706 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4707 "<Id>urn:uuid:%1</Id>"
4708 "<ContentTitleText>Content</ContentTitleText>"
4709 "<AnnotationText>Annotation</AnnotationText>"
4710 "<IssueDate>2018-10-02T12:25:14</IssueDate>"
4711 "<ReelNumber>1</ReelNumber>"
4712 "<Language>en-US</Language>"
4713 "<EditRate>25 1</EditRate>"
4714 "<TimeCodeRate>25</TimeCodeRate>"
4715 "<StartTime>00:00:00:00</StartTime>"
4716 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
4718 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4719 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4720 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4729 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4730 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4732 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4734 check_verify_result (
4738 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4739 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4740 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4741 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4742 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4743 dcp::VerificationNote(
4744 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4745 ).set_cpl_id(cpl->id()),
4746 dcp::VerificationNote(
4747 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID
4748 ).set_cpl_id(cpl->id()),
4749 dcp::VerificationNote(
4750 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4751 ).set_cpl_id(cpl->id()),
4752 dcp::VerificationNote(
4753 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4754 ).set_cpl_id(cpl->id())
4759 /** Check that ResourceID and the MXF ID being the same is spotted */
4760 BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
4762 boost::filesystem::path const dir = "build/test/verify_incorrect_timed_text_id";
4763 prepare_directory (dir);
4765 ASDCP::WriterInfo writer_info;
4766 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4769 auto mxf_id = dcp::make_uuid ();
4770 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4771 BOOST_REQUIRE (c == Kumu::UUID_Length);
4773 auto resource_id = mxf_id;
4774 ASDCP::TimedText::TimedTextDescriptor descriptor;
4775 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4776 DCP_ASSERT (c == Kumu::UUID_Length);
4778 auto xml_id = resource_id;
4779 ASDCP::TimedText::MXFWriter writer;
4780 auto subs_mxf = dir / "subs.mxf";
4781 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4782 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4783 writer.WriteTimedTextResource (dcp::String::compose(
4784 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4785 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4786 "<Id>urn:uuid:%1</Id>"
4787 "<ContentTitleText>Content</ContentTitleText>"
4788 "<AnnotationText>Annotation</AnnotationText>"
4789 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
4790 "<ReelNumber>1</ReelNumber>"
4791 "<Language>en-US</Language>"
4792 "<EditRate>25 1</EditRate>"
4793 "<TimeCodeRate>25</TimeCodeRate>"
4794 "<StartTime>00:00:00:00</StartTime>"
4795 "<LoadFont ID=\"font\">urn:uuid:0ce6e0ba-58b9-4344-8929-4d9c959c2d55</LoadFont>"
4797 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4798 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4799 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4808 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4809 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4811 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4813 check_verify_result (
4817 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4818 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4819 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4820 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4821 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4822 dcp::VerificationNote(
4823 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4824 ).set_cpl_id(cpl->id()),
4825 dcp::VerificationNote(
4826 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID
4827 ).set_cpl_id(cpl->id()),
4828 dcp::VerificationNote(
4829 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4830 ).set_cpl_id(cpl->id()),
4831 dcp::VerificationNote(
4832 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4833 ).set_cpl_id(cpl->id()),
4834 dcp::VerificationNote(
4835 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2018-10-02T12:25:14+02:00"}
4836 ).set_cpl_id(cpl->id())
4841 /** Check a DCP with a 3D asset marked as 2D */
4842 BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod)
4844 auto const path = private_test / "data" / "xm";
4846 auto cpl = std::make_shared<dcp::CPL>(find_prefix(path, "CPL_"));
4849 check_verify_result (
4853 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4854 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4855 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4856 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4857 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4858 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4859 dcp::VerificationNote(
4860 dcp::VerificationNote::Type::WARNING,
4861 dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(path, "j2c"))
4863 dcp::VerificationNote(
4864 dcp::VerificationNote::Type::BV21_ERROR,
4865 dcp::VerificationNote::Code::INVALID_STANDARD
4872 BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers)
4874 path dir = "build/test/verify_unexpected_things_in_main_markers";
4875 prepare_directory (dir);
4876 auto dcp = make_simple (dir, 1, 24);
4879 HashCalculator calc(find_cpl(dir));
4882 Editor e (find_cpl(dir));
4884 " <IntrinsicDuration>24</IntrinsicDuration>",
4885 "<EntryPoint>0</EntryPoint><Duration>24</Duration>"
4889 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4891 check_verify_result (
4895 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4896 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4897 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4898 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4899 dcp::VerificationNote(
4900 dcp::VerificationNote::Type::OK,
4901 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4902 string{"1998x1080"},
4903 canonical(cpl->file().get())
4904 ).set_cpl_id(cpl->id()),
4905 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4906 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4907 dcp::VerificationNote(
4908 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4909 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4910 dcp::VerificationNote(
4911 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_ENTRY_POINT
4912 ).set_cpl_id(cpl->id()),
4913 dcp::VerificationNote(
4914 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_DURATION
4915 ).set_cpl_id(cpl->id())
4920 BOOST_AUTO_TEST_CASE(verify_invalid_content_kind)
4922 path dir = "build/test/verify_invalid_content_kind";
4923 prepare_directory (dir);
4924 auto dcp = make_simple (dir, 1, 24);
4927 HashCalculator calc(find_cpl(dir));
4930 Editor e(find_cpl(dir));
4931 e.replace("trailer", "trip");
4934 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4936 check_verify_result (
4940 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4941 dcp::VerificationNote(
4942 dcp::VerificationNote::Type::OK,
4943 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4944 string{"1998x1080"},
4945 canonical(cpl->file().get())
4946 ).set_cpl_id(cpl->id()),
4947 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4948 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4949 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4950 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4951 dcp::VerificationNote(
4952 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4953 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4954 dcp::VerificationNote(
4955 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip")
4956 ).set_cpl_id(cpl->id()),
4962 BOOST_AUTO_TEST_CASE(verify_valid_content_kind)
4964 path dir = "build/test/verify_valid_content_kind";
4965 prepare_directory (dir);
4966 auto dcp = make_simple (dir, 1, 24);
4969 HashCalculator calc(find_cpl(dir));
4972 Editor e(find_cpl(dir));
4973 e.replace("<ContentKind>trailer</ContentKind>", "<ContentKind scope=\"http://bobs.contents/\">trip</ContentKind>");
4976 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4978 check_verify_result (
4982 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4983 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4984 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4985 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4986 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4987 dcp::VerificationNote(
4988 dcp::VerificationNote::Type::OK,
4989 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4990 string{"1998x1080"},
4991 canonical(cpl->file().get())
4992 ).set_cpl_id(cpl->id()),
4993 dcp::VerificationNote(
4994 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4995 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5000 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1)
5002 path dir = "build/test/verify_invalid_main_picture_active_area_1";
5003 prepare_directory(dir);
5004 auto dcp = make_simple(dir, 1, 24);
5007 auto constexpr area = "<meta:MainPictureActiveArea>";
5009 HashCalculator calc(find_cpl(dir));
5012 Editor e(find_cpl(dir));
5013 e.delete_lines_after(area, 2);
5014 e.insert(area, "<meta:Height>4080</meta:Height>");
5015 e.insert(area, "<meta:Width>1997</meta:Width>");
5018 dcp::PKL pkl(find_pkl(dir));
5019 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5021 check_verify_result(
5025 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5026 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5027 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5028 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5029 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5030 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5031 dcp::VerificationNote(
5032 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5033 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5034 dcp::VerificationNote(
5035 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 1997 is not a multiple of 2", canonical(find_cpl(dir))
5036 ).set_cpl_id(cpl->id()),
5037 dcp::VerificationNote(
5038 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 4080 is bigger than the asset height 1080", canonical(find_cpl(dir))
5039 ).set_cpl_id(cpl->id()),
5044 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2)
5046 path dir = "build/test/verify_invalid_main_picture_active_area_2";
5047 prepare_directory(dir);
5048 auto dcp = make_simple(dir, 1, 24);
5051 auto constexpr area = "<meta:MainPictureActiveArea>";
5053 HashCalculator calc(find_cpl(dir));
5056 Editor e(find_cpl(dir));
5057 e.delete_lines_after(area, 2);
5058 e.insert(area, "<meta:Height>5125</meta:Height>");
5059 e.insert(area, "<meta:Width>9900</meta:Width>");
5062 dcp::PKL pkl(find_pkl(dir));
5063 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5065 check_verify_result(
5069 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5070 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5071 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5072 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5073 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5074 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5075 dcp::VerificationNote(
5076 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5077 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5078 dcp::VerificationNote(
5079 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is not a multiple of 2", canonical(find_cpl(dir))
5080 ).set_cpl_id(cpl->id()),
5081 dcp::VerificationNote(
5082 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 9900 is bigger than the asset width 1998", canonical(find_cpl(dir))
5083 ).set_cpl_id(cpl->id()),
5084 dcp::VerificationNote(
5085 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is bigger than the asset height 1080", canonical(find_cpl(dir))
5086 ).set_cpl_id(cpl->id())
5091 BOOST_AUTO_TEST_CASE(verify_duplicate_pkl_asset_ids)
5095 path dir = "build/test/verify_duplicate_pkl_asset_ids";
5096 prepare_directory(dir);
5097 auto dcp = make_simple(dir, 1, 24);
5101 Editor e(find_pkl(dir));
5102 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358ab");
5105 dcp::PKL pkl(find_pkl(dir));
5106 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5108 check_verify_result(
5112 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5113 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5114 dcp::VerificationNote(
5115 dcp::VerificationNote::Type::OK,
5116 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5117 string{"1998x1080"},
5118 canonical(cpl->file().get())
5119 ).set_cpl_id(cpl->id()),
5120 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5121 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5122 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5123 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl.id(), canonical(find_pkl(dir)) },
5128 BOOST_AUTO_TEST_CASE(verify_duplicate_assetmap_asset_ids)
5132 path dir = "build/test/verify_duplicate_assetmap_asset_ids";
5133 prepare_directory(dir);
5134 auto dcp = make_simple(dir, 1, 24);
5138 Editor e(find_asset_map(dir));
5139 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:97f0f352-5b77-48ee-a558-9df37717f4fa");
5142 dcp::PKL pkl(find_pkl(dir));
5143 dcp::AssetMap asset_map(find_asset_map(dir));
5144 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
5146 check_verify_result(
5150 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5151 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5152 dcp::VerificationNote(
5153 dcp::VerificationNote::Type::OK,
5154 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5155 string{"1998x1080"},
5156 canonical(cpl->file().get())
5157 ).set_cpl_id(cpl->id()),
5158 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5159 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5160 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5161 dcp::VerificationNote(
5162 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map.id(), canonical(find_asset_map(dir))
5164 dcp::VerificationNote(
5165 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, string("5407b210-4441-4e97-8b16-8bdc7c12da54")
5171 BOOST_AUTO_TEST_CASE(verify_mismatched_sound_channel_counts)
5173 boost::filesystem::path const path = "build/test/verify_mismatched_sound_channel_counts";
5175 dcp::MXFMetadata mxf_meta;
5176 mxf_meta.company_name = "OpenDCP";
5177 mxf_meta.product_name = "OpenDCP";
5178 mxf_meta.product_version = "0.0.25";
5180 auto constexpr sample_rate = 48000;
5181 auto constexpr frames = 240;
5183 boost::filesystem::remove_all(path);
5184 boost::filesystem::create_directories(path);
5185 auto dcp = make_shared<dcp::DCP>(path);
5186 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5187 cpl->set_annotation_text("hello");
5188 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R"));
5189 cpl->set_main_sound_sample_rate(sample_rate);
5190 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5191 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5192 cpl->set_version_number(1);
5196 /* Reel with 2 channels of audio */
5198 auto mp = simple_picture(path, "1", frames, {});
5199 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5201 auto reel = make_shared<dcp::Reel>(
5202 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5203 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5206 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5207 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5214 /* Reel with 6 channels of audio */
5216 auto mp = simple_picture(path, "2", frames, {});
5217 auto ms = simple_sound(path, "2", mxf_meta, "en-US", frames, sample_rate, {}, 6);
5219 auto reel = make_shared<dcp::Reel>(
5220 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5221 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5224 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5225 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 0, frames - 1, 24));
5232 dcp->set_annotation_text("hello");
5235 check_verify_result(
5239 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5240 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5241 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5242 dcp::VerificationNote(
5243 dcp::VerificationNote::Type::OK,
5244 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5245 string{"1998x1080"},
5247 ).set_cpl_id(cpl->id()),
5248 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5249 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5250 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5251 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5252 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video2.mxf"), cpl),
5253 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video2.mxf"), cpl),
5254 dcp::VerificationNote(
5255 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, canonical(find_file(path, "audio2"))
5256 ).set_cpl_id(cpl->id())
5261 BOOST_AUTO_TEST_CASE(verify_invalid_main_sound_configuration)
5263 boost::filesystem::path const path = "build/test/verify_invalid_main_sound_configuration";
5265 dcp::MXFMetadata mxf_meta;
5266 mxf_meta.company_name = "OpenDCP";
5267 mxf_meta.product_name = "OpenDCP";
5268 mxf_meta.product_version = "0.0.25";
5270 auto constexpr sample_rate = 48000;
5271 auto constexpr frames = 240;
5273 boost::filesystem::remove_all(path);
5274 boost::filesystem::create_directories(path);
5275 auto dcp = make_shared<dcp::DCP>(path);
5276 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5277 cpl->set_annotation_text("hello");
5278 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5279 cpl->set_main_sound_sample_rate(sample_rate);
5280 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5281 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5282 cpl->set_version_number(1);
5284 auto mp = simple_picture(path, "1", frames, {});
5285 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5287 auto reel = make_shared<dcp::Reel>(
5288 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5289 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5292 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5293 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5294 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 9, 23, 24));
5300 dcp->set_annotation_text("hello");
5303 check_verify_result(
5307 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5308 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5309 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5310 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5311 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5312 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5313 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5314 dcp::VerificationNote(
5315 dcp::VerificationNote::Type::OK,
5316 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5317 string{"1998x1080"},
5319 ).set_cpl_id(cpl->id()),
5320 dcp::VerificationNote(
5321 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_SOUND_CONFIGURATION, std::string{"MainSoundConfiguration has 6 channels but sound assets have 2"}, canonical(find_cpl(path))
5322 ).set_cpl_id(cpl->id())
5327 BOOST_AUTO_TEST_CASE(verify_invalid_tile_part_size)
5329 boost::filesystem::path const path = "build/test/verify_invalid_tile_part_size";
5330 auto constexpr video_frames = 24;
5331 auto constexpr sample_rate = 48000;
5333 boost::filesystem::remove_all(path);
5334 boost::filesystem::create_directories(path);
5336 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
5337 auto picture_writer = mp->start_write(path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
5339 dcp::Size const size(1998, 1080);
5340 auto image = make_shared<dcp::OpenJPEGImage>(size);
5341 boost::random::mt19937 rng(1);
5342 boost::random::uniform_int_distribution<> dist(0, 4095);
5343 for (int c = 0; c < 3; ++c) {
5344 for (int p = 0; p < (1998 * 1080); ++p) {
5345 image->data(c)[p] = dist(rng);
5348 auto j2c = dcp::compress_j2k(image, 750000000, video_frames, false, false);
5349 for (int i = 0; i < 24; ++i) {
5350 picture_writer->write(j2c.data(), j2c.size());
5352 picture_writer->finalize();
5354 auto dcp = make_shared<dcp::DCP>(path);
5355 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5356 cpl->set_content_version(
5357 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11", "content-version-label-text")
5359 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5360 cpl->set_main_sound_sample_rate(sample_rate);
5361 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5362 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5363 cpl->set_version_number(1);
5365 auto ms = simple_sound(path, "", dcp::MXFMetadata(), "en-US", video_frames, sample_rate, {});
5367 auto reel = make_shared<dcp::Reel>(
5368 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5369 make_shared<dcp::ReelSoundAsset>(ms, 0)
5374 dcp->set_annotation_text("A Test DCP");
5377 vector<dcp::VerificationNote> expected = {
5378 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5379 dcp::VerificationNote(
5380 dcp::VerificationNote::Type::OK,
5381 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5382 string{"1998x1080"},
5384 ).set_cpl_id(cpl->id()),
5385 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video.mxf"), cpl),
5386 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5387 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5388 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5389 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5390 dcp::VerificationNote(
5391 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
5392 ).set_cpl_id(cpl->id()),
5393 dcp::VerificationNote(
5394 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
5395 ).set_cpl_id(cpl->id())
5398 for (auto frame = 0; frame < 24; frame++) {
5400 dcp::VerificationNote(
5401 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(path / "video.mxf")
5402 ).set_frame(frame).set_frame_rate(24).set_cpl_id(cpl->id())
5406 int component_sizes[] = {
5412 for (auto frame = 0; frame < 24; frame++) {
5413 for (auto component = 0; component < 3; component++) {
5415 dcp::VerificationNote(
5416 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE
5417 ).set_frame(frame).set_component(component).set_size(component_sizes[component]).set_cpl_id(cpl->id())
5422 check_verify_result({ path }, {}, expected);
5426 BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces)
5428 boost::filesystem::path const dir = "test/ref/DCP/subtitle_namespace_test";
5431 BOOST_REQUIRE(!dcp.cpls().empty());
5432 auto cpl = dcp.cpls()[0];
5434 check_verify_result(
5438 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5439 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5440 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5441 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
5442 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"Dcp_FTR-1_F_XX-XX_MOS_2K_20230407_SMPTE_OV"}, cpl),
5443 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5444 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5445 dcp::VerificationNote(
5446 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
5447 ).set_cpl_id(cpl->id()),
5448 dcp::VerificationNote(
5449 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
5450 ).set_cpl_id(cpl->id()),
5451 dcp::VerificationNote(
5452 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
5453 ).set_cpl_id(cpl->id()),
5454 dcp::VerificationNote(
5455 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(find_file(dir, "sub_"))
5456 ).set_cpl_id(cpl->id()),
5457 dcp::VerificationNote(
5458 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(find_file(dir, "cpl_"))
5459 ).set_cpl_id(cpl->id()),
5460 dcp::VerificationNote(
5461 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, std::string{"315de731-1173-484c-9a35-bdacf5a9d99d"}
5462 ).set_cpl_id(cpl->id()),
5467 BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font)
5469 path const dir("build/test/verify_missing_load_font");
5470 prepare_directory (dir);
5471 copy_file ("test/data/subs1.xml", dir / "subs.xml");
5473 Editor editor(dir / "subs.xml");
5474 editor.delete_first_line_containing("LoadFont");
5476 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
5477 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
5478 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
5480 check_verify_result (
5484 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5485 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5486 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5487 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5488 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
5489 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id("theFontId").set_cpl_id(cpl->id())
5495 BOOST_AUTO_TEST_CASE(verify_missing_load_font)
5497 boost::filesystem::path const dir = "build/test/verify_missing_load_font";
5498 prepare_directory(dir);
5499 auto dcp = make_simple (dir, 1, 202);
5502 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
5503 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
5504 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
5505 "<ContentTitleText>Content</ContentTitleText>"
5506 "<AnnotationText>Annotation</AnnotationText>"
5507 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
5508 "<ReelNumber>1</ReelNumber>"
5509 "<EditRate>24 1</EditRate>"
5510 "<TimeCodeRate>24</TimeCodeRate>"
5511 "<StartTime>00:00:00:00</StartTime>"
5512 "<Language>de-DE</Language>"
5514 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
5515 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:06:00\" TimeOut=\"00:00:08:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
5516 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
5522 dcp::File xml_file(dir / "subs.xml", "w");
5523 BOOST_REQUIRE(xml_file);
5524 xml_file.write(xml.c_str(), xml.size(), 1);
5526 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
5527 subs->write(dir / "subs.mxf");
5529 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 202, 0);
5530 auto cpl = dcp->cpls()[0];
5531 cpl->reels()[0]->add(reel_subs);
5534 check_verify_result (
5538 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5539 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5540 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5541 dcp::VerificationNote(
5542 dcp::VerificationNote::Type::OK,
5543 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5544 string{"1998x1080"},
5546 ).set_cpl_id(cpl->id()),
5547 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5548 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5549 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5550 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5551 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id(reel_subs->id()).set_cpl_id(cpl->id())
5556 BOOST_AUTO_TEST_CASE(verify_spots_wrong_asset)
5558 boost::filesystem::path const dir = "build/test/verify_spots_wrong_asset";
5559 boost::filesystem::remove_all(dir);
5561 auto dcp1 = make_simple(dir / "1");
5563 auto cpl = dcp1->cpls()[0];
5565 auto const asset_1 = dcp::MonoPictureAsset(dir / "1" / "video.mxf").id();
5567 auto dcp2 = make_simple(dir / "2");
5569 auto const asset_2 = dcp::MonoPictureAsset(dir / "2" / "video.mxf").id();
5571 boost::filesystem::remove(dir / "1" / "video.mxf");
5572 boost::filesystem::copy_file(dir / "2" / "video.mxf", dir / "1" / "video.mxf");
5574 check_verify_result(
5578 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5579 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5580 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5581 dcp::VerificationNote(
5582 dcp::VerificationNote::Type::OK,
5583 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5584 string{"1998x1080"},
5586 ).set_cpl_id(cpl->id()),
5587 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5588 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5589 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_MAP_ID).set_id(asset_1).set_other_id(asset_2)
5594 BOOST_AUTO_TEST_CASE(verify_cpl_content_version_label_text_empty)
5596 boost::filesystem::path const dir = "build/test/verify_cpl_content_version_label_text_empty";
5597 boost::filesystem::remove_all(dir);
5599 auto dcp = make_simple(dir);
5600 BOOST_REQUIRE(dcp->cpls().size() == 1);
5601 auto cpl = dcp->cpls()[0];
5602 cpl->set_content_version(dcp::ContentVersion(""));
5605 check_verify_result(
5609 dcp::VerificationNote(
5610 dcp::VerificationNote::Type::OK,
5611 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5612 string{"1998x1080"},
5614 ).set_cpl_id(cpl->id()),
5615 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5616 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5617 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5618 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5619 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5620 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5621 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5622 dcp::VerificationNote(dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get()).set_cpl_id(cpl->id())
5627 /** Check that we don't get any strange errors when verifying encrypted DCPs (DoM #2659) */
5628 BOOST_AUTO_TEST_CASE(verify_encrypted_smpte_dcp)
5630 auto const dir = path("build/test/verify_encrypted_smpte_dcp");
5632 auto key_id = dcp::make_uuid();
5633 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset>(dir, {{ 4 * 24, 5 * 24 }}, key, key_id);
5635 dcp::DecryptedKDM kdm(dcp::LocalTime(), dcp::LocalTime(), "", "", "");
5636 kdm.add_key(dcp::DecryptedKDMKey(string{"MDIK"}, key_id, key, cpl->id(), dcp::Standard::SMPTE));
5638 path const pkl_file = find_file(dir, "pkl_");
5639 path const cpl_file = find_file(dir, "cpl_");
5641 check_verify_result(
5645 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5646 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5647 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5648 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5649 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
5650 dcp::VerificationNote(
5651 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_file)
5652 ).set_cpl_id(cpl->id()),
5653 dcp::VerificationNote(
5654 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_file)
5655 ).set_cpl_id(cpl->id()),
5656 dcp::VerificationNote(
5657 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, filename_to_id(pkl_file.filename()), canonical(pkl_file)