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);
152 /** Copy dcp_test{reference_number} to build/test/verify_test{verify_test_suffix}
153 * to make a new sacrificial test DCP.
156 setup (int reference_number, string verify_test_suffix)
158 auto const dir = dcp::String::compose("build/test/verify_test%1", verify_test_suffix);
159 prepare_directory (dir);
160 for (auto i: directory_iterator(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number))) {
161 copy_file (i.path(), dir / i.path().filename());
170 write_dcp_with_single_asset (path dir, shared_ptr<dcp::ReelAsset> reel_asset, dcp::Standard standard = dcp::Standard::SMPTE)
172 auto reel = make_shared<dcp::Reel>();
173 reel->add (reel_asset);
174 reel->add (simple_markers());
176 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, standard);
178 auto dcp = make_shared<dcp::DCP>(dir);
180 dcp->set_annotation_text("hello");
187 LIBDCP_DISABLE_WARNINGS
190 dump_notes (vector<dcp::VerificationNote> const & notes)
192 for (auto i: notes) {
193 std::cout << dcp::note_to_string(i) << "\n";
196 LIBDCP_ENABLE_WARNINGS
201 to_string(dcp::VerificationNote const& note)
203 string s = note_to_string(note) + dcp::String::compose(
204 "\n [%1 %2 %3 %4 %5 %6 ",
205 static_cast<int>(note.type()),
206 static_cast<int>(note.code()),
207 note.note().get_value_or("<none>"),
208 note.file().get_value_or("<none>"),
209 note.line().get_value_or(0),
210 note.frame().get_value_or(0)
213 s += dcp::String::compose(
215 note.id().get_value_or("<none>"),
216 note.other_id().get_value_or("<none>"),
217 note.cpl_id().get_value_or("<none>"),
218 note.reference_hash().get_value_or("<none>"),
219 note.calculated_hash().get_value_or("<none>")
228 check_verify_result(vector<dcp::VerificationNote> notes, vector<dcp::VerificationNote> test_notes)
230 std::sort(notes.begin(), notes.end());
231 std::sort(test_notes.begin(), test_notes.end());
233 string message = "\n";
235 vector<dcp::VerificationNote> not_expected;
236 for (auto note: notes) {
237 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(); });
238 if (iter != test_notes.end() && *iter != note) {
239 message += "Wrong details:\n --seen " + to_string(note) + " --expected " + to_string(*iter) + "\n";
240 } else if (iter == test_notes.end()) {
241 not_expected.push_back(note);
245 vector<dcp::VerificationNote> not_seen;
246 for (auto note: test_notes) {
247 auto iter = std::find_if(notes.begin(), notes.end(), [note](dcp::VerificationNote const& n) { return note.type() == n.type() && note.code() == n.code(); });
248 if (iter == notes.end()) {
249 not_seen.push_back(note);
253 for (auto note: not_expected) {
254 message += "Not expected:\n" + to_string(note) + "\n";
257 for (auto note: not_seen) {
258 message += "Not seen:\n" + to_string(note) + "\n";
261 BOOST_REQUIRE_MESSAGE(notes == test_notes, message);
267 check_verify_result(vector<path> dir, vector<dcp::DecryptedKDM> kdm, vector<dcp::VerificationNote> test_notes)
269 check_verify_result(dcp::verify({dir}, kdm, &stage, &progress, {}, xsd_test).notes, test_notes);
273 /* Copy dcp_test1 to build/test/verify_test{suffix} then edit a file found by the functor 'file',
274 * replacing from with to. Verify the resulting DCP and check that the results match the given
279 replace(string suffix, boost::function<path (string)> file, string from, string to)
281 auto dir = setup (1, suffix);
284 Editor e (file(suffix));
285 e.replace (from, to);
292 add_font(shared_ptr<dcp::SubtitleAsset> asset)
294 dcp::ArrayData fake_font(1024);
295 asset->add_font("font", fake_font);
302 HashCalculator(boost::filesystem::path path)
304 , _old_hash(dcp::make_digest(path, [](int64_t, int64_t) {}))
307 std::string old_hash() const {
311 std::string new_hash() const {
312 return dcp::make_digest(_path, [](int64_t, int64_t) {});
316 boost::filesystem::path _path;
317 std::string _old_hash;
322 dcp::VerificationNote
323 ok(dcp::VerificationNote::Code code, shared_ptr<const dcp::CPL> cpl)
325 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code).set_cpl_id(cpl->id());
330 dcp::VerificationNote
331 ok(dcp::VerificationNote::Code code, string note, shared_ptr<const dcp::CPL> cpl)
333 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, note).set_cpl_id(cpl->id());
338 dcp::VerificationNote
339 ok(dcp::VerificationNote::Code code, boost::filesystem::path path, shared_ptr<const dcp::CPL> cpl)
341 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, path).set_cpl_id(cpl->id());
346 add(vector<dcp::VerificationNote>& notes, vector<dcp::VerificationNote> const& add)
355 find_prefix(path dir, string prefix)
357 auto iter = std::find_if(directory_iterator(dir), directory_iterator(), [prefix](path const& p) {
358 return boost::starts_with(p.filename().string(), prefix);
361 BOOST_REQUIRE(iter != directory_iterator());
366 path find_cpl (path dir)
368 return find_prefix(dir, "cpl_");
375 return find_prefix(dir, "pkl_");
380 find_asset_map(path dir)
382 return find_prefix(dir, "ASSETMAP");
386 BOOST_AUTO_TEST_CASE (verify_no_error)
389 auto dir = setup (1, "no_error");
390 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
392 path const cpl_file = dir / dcp_test1_cpl();
393 path const pkl_file = dir / dcp_test1_pkl();
394 path const assetmap_file = dir / "ASSETMAP.xml";
396 auto st = stages.begin();
397 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
398 BOOST_REQUIRE (st->second);
399 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
401 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
402 BOOST_REQUIRE (st->second);
403 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
405 BOOST_CHECK_EQUAL (st->first, "Checking reel");
406 BOOST_REQUIRE (!st->second);
408 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
409 BOOST_REQUIRE (st->second);
410 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
412 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
413 BOOST_REQUIRE (st->second);
414 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
416 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
417 BOOST_REQUIRE (st->second);
418 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
420 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
421 BOOST_REQUIRE (st->second);
422 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
424 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
425 BOOST_REQUIRE (st->second);
426 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
427 ++st; BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
428 BOOST_REQUIRE (st->second);
429 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
431 BOOST_REQUIRE (st == stages.end());
433 for (auto note: notes) {
434 BOOST_CHECK(note.type() == dcp::VerificationNote::Type::OK);
439 BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash)
441 using namespace boost::filesystem;
443 auto dir = setup (1, "incorrect_picture_sound_hash");
444 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
446 auto video_path = path(dir / "video.mxf");
447 HashCalculator video_calc(video_path);
448 auto mod = fopen(video_path.string().c_str(), "r+b");
450 BOOST_REQUIRE_EQUAL(fseek(mod, -16, SEEK_END), 0);
452 BOOST_REQUIRE(fwrite(&x, sizeof(x), 1, mod) == 1);
455 auto audio_path = path(dir / "audio.mxf");
456 HashCalculator audio_calc(audio_path);
457 mod = fopen(audio_path.string().c_str(), "r+b");
459 BOOST_REQUIRE_EQUAL(fseek(mod, 0, SEEK_END), 0);
460 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
463 dcp::ASDCPErrorSuspender sus;
464 check_verify_result (
468 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
469 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
470 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
471 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
472 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
473 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
474 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
475 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
476 dcp::VerificationNote(
477 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path)
478 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(video_calc.old_hash()).set_calculated_hash(video_calc.new_hash()),
479 dcp::VerificationNote(
480 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path)
481 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(audio_calc.old_hash()).set_calculated_hash(audio_calc.new_hash()),
486 BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes)
488 using namespace boost::filesystem;
490 auto dir = setup (1, "mismatched_picture_sound_hashes");
491 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
493 HashCalculator calc(dir / dcp_test1_cpl());
496 Editor e (dir / dcp_test1_pkl());
497 e.replace ("<Hash>", "<Hash>x");
500 check_verify_result (
504 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
505 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
506 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
507 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
508 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
509 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
510 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
511 dcp::VerificationNote(
512 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
513 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash("x" + calc.old_hash()).set_calculated_hash(calc.old_hash()),
514 dcp::VerificationNote(
515 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf")
516 ).set_cpl_id(dcp_test1_cpl_id()),
517 dcp::VerificationNote(
518 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf")
519 ).set_cpl_id(dcp_test1_cpl_id()),
520 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'x3M7YTgvFKXXMEGLkIbV4miC90FE=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 28 },
521 { 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 },
522 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xvsVjRV9vhTBPUWfE/TT1o2vdQsI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 20 },
527 BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind)
529 auto dir = setup (1, "failed_read_content_kind");
531 HashCalculator calc(dir / dcp_test1_cpl());
534 Editor e (dir / dcp_test1_cpl());
535 e.replace ("<ContentKind>", "<ContentKind>x");
538 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
540 check_verify_result (
544 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
545 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
546 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
547 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
548 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
549 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
550 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
551 dcp::VerificationNote(
552 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
553 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
554 dcp::VerificationNote(
555 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer")
556 ).set_cpl_id(dcp_test1_cpl_id())
563 dcp_test1_cpl_path(string suffix)
565 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_cpl());
571 dcp_test1_pkl_path(string suffix)
573 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_pkl());
579 asset_map (string suffix)
581 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", suffix);
585 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_rate)
587 auto const suffix = "invalid_picture_frame_rate";
589 replace(suffix, &dcp_test1_cpl_path, "<FrameRate>24 1", "<FrameRate>99 1");
591 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
592 auto const cpl_path = find_cpl(dir);
593 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
595 std::vector<dcp::VerificationNote> expected =
597 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
598 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
599 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
600 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
601 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
602 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
603 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
604 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
605 dcp::VerificationNote(
606 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
607 ).set_cpl_id(cpl->id()).set_calculated_hash("7n7GQ2TbxQbmHYuAR8ml7XDOep8=").set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI="),
608 dcp::VerificationNote(
609 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, string{"99/1"}
610 ).set_cpl_id(cpl->id())
613 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
617 BOOST_AUTO_TEST_CASE (verify_missing_asset)
619 auto dir = setup (1, "missing_asset");
620 remove (dir / "video.mxf");
622 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
624 check_verify_result (
628 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
629 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
630 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
631 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
632 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
633 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
634 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
635 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_ASSET, canonical(dir) / "video.mxf" }
640 BOOST_AUTO_TEST_CASE (verify_empty_asset_path)
642 auto const suffix = "empty_asset_path";
644 replace("empty_asset_path", &asset_map, "<Path>video.mxf</Path>", "<Path></Path>");
646 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
647 auto const cpl_path = find_cpl(dir);
648 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
650 std::vector<dcp::VerificationNote> expected = {
651 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
652 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
653 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
654 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
655 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
656 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
657 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
658 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_ASSET_PATH }
661 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
665 BOOST_AUTO_TEST_CASE (verify_mismatched_standard)
667 auto const suffix = "mismatched_standard";
669 replace(suffix, &dcp_test1_cpl_path, "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#");
671 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
672 auto const cpl_path = find_cpl(dir);
673 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
675 std::vector<dcp::VerificationNote> expected = {
676 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
677 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
678 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
679 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
680 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
681 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
682 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
683 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
684 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_STANDARD },
685 dcp::VerificationNote(
686 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "invalid character encountered", canonical(cpl_path), 42
687 ).set_cpl_id(cpl->id()),
688 dcp::VerificationNote(
689 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'Id'", canonical(cpl_path), 53
690 ).set_cpl_id(cpl->id()),
691 dcp::VerificationNote(
692 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'EditRate'", canonical(cpl_path), 54
693 ).set_cpl_id(cpl->id()),
694 dcp::VerificationNote(
695 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'IntrinsicDuration'", canonical(cpl_path), 55
696 ).set_cpl_id(cpl->id()),
697 dcp::VerificationNote(
698 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
699 "element 'Id' is not allowed for content model '(Id,AnnotationText?,EditRate,IntrinsicDuration,"
700 "EntryPoint?,Duration?,FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
701 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,MainSoundSampleRate,"
702 "MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,ExtensionMetadataList?,)'",
703 canonical(cpl_path), 149
704 ).set_cpl_id(cpl->id()),
705 dcp::VerificationNote(
706 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
707 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("FZ9E7L/pOuJ6aZfbiaANTv8BFOo=")
710 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
714 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_id)
716 auto const suffix = "invalid_xml_cpl_id";
718 /* There's no MISMATCHED_CPL_HASHES error here because it can't find the correct hash by ID (since the ID is wrong) */
719 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");
721 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
722 auto const cpl_path = find_cpl(dir);
723 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
725 std::vector<dcp::VerificationNote> expected = {
726 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
727 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
728 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
729 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
730 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
731 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
732 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
733 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
734 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
735 dcp::VerificationNote(
736 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
737 "value 'urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358a' does not match regular expression "
738 "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
739 ).set_cpl_id(cpl->id())
742 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
745 BOOST_AUTO_TEST_CASE (verify_invalid_xml_issue_date)
747 auto const suffix = "invalid_xml_issue_date";
749 replace("invalid_xml_issue_date", &dcp_test1_cpl_path, "<IssueDate>", "<IssueDate>x");
751 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
752 auto const cpl_path = find_cpl(dir);
753 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
755 std::vector<dcp::VerificationNote> expected = {
756 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
757 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
758 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
759 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
760 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
761 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
762 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
763 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
764 dcp::VerificationNote(
765 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
766 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("sz3BeIugJ567q3HMnA62JeRw4TE="),
767 dcp::VerificationNote(
768 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
769 "invalid character encountered",
770 canonical(cpl_path), 5
771 ).set_cpl_id(cpl->id()),
774 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
778 BOOST_AUTO_TEST_CASE (verify_invalid_xml_pkl_id)
780 auto const suffix = "invalid_xml_pkl_id";
782 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));
784 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
785 auto const pkl_path = find_pkl(dir);
786 auto const cpl_path = find_cpl(dir);
787 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
789 std::vector<dcp::VerificationNote> expected = {
790 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
791 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
792 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
793 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
794 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
795 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
796 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
797 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
798 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
799 dcp::VerificationNote(
800 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
801 "value 'urn:uuid:x199d58b-5ef8-4d49-b270-07e590ccb280' does not match regular "
802 "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}'",
803 canonical(pkl_path), 3
807 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
811 BOOST_AUTO_TEST_CASE (verify_invalid_xml_asset_map_id)
813 auto const suffix = "invalid_xml_asset_map_id";
815 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));
817 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
818 auto const cpl_path = find_cpl(dir);
819 auto const asset_map_path = find_asset_map(dir);
820 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
822 std::vector<dcp::VerificationNote> expected = {
823 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
824 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
825 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
826 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
827 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
828 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
829 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
830 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
831 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
832 dcp::VerificationNote(
833 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
834 "value 'urn:uuid:x17b3de4-6dda-408d-b19b-6711354b0bc3' does not match regular "
835 "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}'",
836 canonical(asset_map_path), 3
840 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
844 BOOST_AUTO_TEST_CASE (verify_invalid_standard)
847 auto dir = setup (3, "verify_invalid_standard");
848 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
850 path const cpl_file = dir / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
851 path const pkl_file = dir / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
852 path const assetmap_file = dir / "ASSETMAP";
853 auto cpl = std::make_shared<dcp::CPL>(cpl_file);
855 auto st = stages.begin();
856 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
857 BOOST_REQUIRE (st->second);
858 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
860 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
861 BOOST_REQUIRE (st->second);
862 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
864 BOOST_CHECK_EQUAL (st->first, "Checking reel");
865 BOOST_REQUIRE (!st->second);
867 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
868 BOOST_REQUIRE (st->second);
869 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
871 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
872 BOOST_REQUIRE (st->second);
873 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
875 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
876 BOOST_REQUIRE (st->second);
877 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
879 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
880 BOOST_REQUIRE (st->second);
881 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
883 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
884 BOOST_REQUIRE (st->second);
885 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
887 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
888 BOOST_REQUIRE (st->second);
889 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
891 BOOST_REQUIRE (st == stages.end());
893 vector<dcp::VerificationNote> expected = {
894 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
895 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
896 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
897 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
898 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
899 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
900 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl),
901 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl)
904 for (int j = 0; j < 24; ++j) {
906 dcp::VerificationNote(
907 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
908 ).set_cpl_id(cpl->id())
912 check_verify_result(notes, expected);
915 /* DCP with a short asset */
916 BOOST_AUTO_TEST_CASE (verify_invalid_duration)
918 auto dir = setup (8, "invalid_duration");
922 BOOST_REQUIRE(dcp.cpls().size() == 1);
923 auto cpl = dcp.cpls()[0];
925 vector<dcp::VerificationNote> expected = {
926 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
927 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
928 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
929 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
930 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
931 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
932 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
933 dcp::VerificationNote(
934 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
935 ).set_cpl_id(cpl->id()),
936 dcp::VerificationNote(
937 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
938 ).set_cpl_id(cpl->id()),
939 dcp::VerificationNote(
940 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
941 ).set_cpl_id(cpl->id()),
942 dcp::VerificationNote(
943 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
944 ).set_cpl_id(cpl->id()),
945 dcp::VerificationNote(
946 dcp::VerificationNote::Type::WARNING,
947 dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT,
949 ).set_cpl_id(cpl->id())
952 for (int i = 0; i < 23; ++i) {
954 dcp::VerificationNote(
955 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
956 ).set_cpl_id(cpl->id())
960 check_verify_result({ dir }, {}, expected);
966 dcp_from_frame (dcp::ArrayData const& frame, path dir)
968 auto asset = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
969 create_directories (dir);
970 auto writer = asset->start_write(dir / "pic.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
971 for (int i = 0; i < 24; ++i) {
972 writer->write (frame.data(), frame.size());
976 auto reel_asset = make_shared<dcp::ReelMonoPictureAsset>(asset, 0);
977 return write_dcp_with_single_asset (dir, reel_asset);
981 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_size_in_bytes)
983 int const too_big = 1302083 * 2;
985 /* Compress a black image */
986 auto image = black_image ();
987 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
988 BOOST_REQUIRE (frame.size() < too_big);
990 /* Place it in a bigger block with some zero padding at the end */
991 dcp::ArrayData oversized_frame(too_big);
992 memcpy (oversized_frame.data(), frame.data(), frame.size());
993 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
995 path const dir("build/test/verify_invalid_picture_frame_size_in_bytes");
996 prepare_directory (dir);
997 auto cpl = dcp_from_frame (oversized_frame, dir);
999 vector<dcp::VerificationNote> expected = {
1000 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1001 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1002 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1003 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1004 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1005 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1006 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1009 for (auto i = 0; i < 24; ++i) {
1011 dcp::VerificationNote(
1012 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1013 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1017 for (auto i = 0; i < 24; ++i) {
1019 dcp::VerificationNote(
1020 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1021 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1026 dcp::VerificationNote(
1027 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1028 ).set_cpl_id(cpl->id())
1031 check_verify_result({ dir }, {}, expected);
1035 BOOST_AUTO_TEST_CASE (verify_nearly_invalid_picture_frame_size_in_bytes)
1037 int const nearly_too_big = 1302083 * 0.98;
1039 /* Compress a black image */
1040 auto image = black_image ();
1041 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1042 BOOST_REQUIRE (frame.size() < nearly_too_big);
1044 /* Place it in a bigger block with some zero padding at the end */
1045 dcp::ArrayData oversized_frame(nearly_too_big);
1046 memcpy (oversized_frame.data(), frame.data(), frame.size());
1047 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
1049 path const dir("build/test/verify_nearly_invalid_picture_frame_size_in_bytes");
1050 prepare_directory (dir);
1051 auto cpl = dcp_from_frame (oversized_frame, dir);
1053 vector<dcp::VerificationNote> expected = {
1054 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1055 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1056 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1057 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1058 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1059 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1060 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1063 for (auto i = 0; i < 24; ++i) {
1065 dcp::VerificationNote(
1066 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1067 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1071 for (auto i = 0; i < 24; ++i) {
1073 dcp::VerificationNote(
1074 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1075 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1080 dcp::VerificationNote(
1081 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1082 ).set_cpl_id(cpl->id())
1085 check_verify_result ({ dir }, {}, expected);
1089 BOOST_AUTO_TEST_CASE (verify_valid_picture_frame_size_in_bytes)
1091 /* Compress a black image */
1092 auto image = black_image ();
1093 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1094 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1096 path const dir("build/test/verify_valid_picture_frame_size_in_bytes");
1097 prepare_directory (dir);
1098 auto cpl = dcp_from_frame (frame, dir);
1100 check_verify_result(
1104 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1105 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1106 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1107 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1108 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1109 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1110 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1111 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1112 dcp::VerificationNote(dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()).set_cpl_id(cpl->id())
1117 BOOST_AUTO_TEST_CASE (verify_valid_interop_subtitles)
1119 path const dir("build/test/verify_valid_interop_subtitles");
1120 prepare_directory (dir);
1121 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1122 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1123 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1124 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1126 check_verify_result (
1130 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1131 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1132 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1133 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1134 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1135 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1136 dcp::VerificationNote(
1137 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1138 ).set_cpl_id(cpl->id())
1143 BOOST_AUTO_TEST_CASE(verify_catch_missing_font_file_with_interop_ccap)
1145 path const dir("build/test/verify_catch_missing_font_file_with_interop_ccap");
1146 prepare_directory(dir);
1147 copy_file("test/data/subs1.xml", dir / "ccap.xml");
1148 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "ccap.xml");
1149 auto reel_asset = make_shared<dcp::ReelInteropClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1150 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1152 check_verify_result (
1156 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1157 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1158 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1159 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1160 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1161 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1162 dcp::VerificationNote(
1163 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1164 ).set_cpl_id(cpl->id())
1169 BOOST_AUTO_TEST_CASE (verify_invalid_interop_subtitles)
1171 using namespace boost::filesystem;
1173 path const dir("build/test/verify_invalid_interop_subtitles");
1174 prepare_directory (dir);
1175 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1176 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1177 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1178 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1181 Editor e (dir / "subs.xml");
1182 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
1185 check_verify_result (
1189 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1190 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1191 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1192 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1193 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1194 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1195 dcp::VerificationNote(
1196 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 5
1197 ).set_cpl_id(cpl->id()),
1198 dcp::VerificationNote(
1199 dcp::VerificationNote::Type::ERROR,
1200 dcp::VerificationNote::Code::INVALID_XML,
1201 string("element 'Foo' is not allowed for content model '(SubtitleID,MovieTitle,ReelNumber,Language,LoadFont*,Font*,Subtitle*)'"),
1204 ).set_cpl_id(cpl->id()),
1205 dcp::VerificationNote(
1206 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1207 ).set_cpl_id(cpl->id())
1212 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_no_subtitles)
1214 path const dir("build/test/verify_interop_subtitle_asset_with_no_subtitles");
1215 prepare_directory(dir);
1216 copy_file("test/data/subs4.xml", dir / "subs.xml");
1217 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1218 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1219 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1221 check_verify_result (
1225 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1226 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1227 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1228 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1229 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1230 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1231 dcp::VerificationNote(
1232 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1233 ).set_cpl_id(cpl->id()),
1234 dcp::VerificationNote(
1235 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1236 ).set_cpl_id(cpl->id())
1242 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_single_space_subtitle)
1244 path const dir("build/test/verify_interop_subtitle_asset_with_single_space_subtitle");
1245 prepare_directory(dir);
1246 copy_file("test/data/subs5.xml", dir / "subs.xml");
1247 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1248 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1249 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1251 check_verify_result (
1255 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1256 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1257 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1258 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1259 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1260 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1261 dcp::VerificationNote(
1262 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"Arial"}
1263 ).set_cpl_id(cpl->id())
1269 BOOST_AUTO_TEST_CASE (verify_valid_smpte_subtitles)
1271 path const dir("build/test/verify_valid_smpte_subtitles");
1272 prepare_directory (dir);
1273 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1274 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1275 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1276 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1278 check_verify_result(
1282 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1283 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1284 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1285 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1286 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1287 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1288 dcp::VerificationNote(
1289 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1290 ).set_cpl_id(cpl->id()),
1291 dcp::VerificationNote(
1292 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-04-14T13:19:14.000+02:00"}
1293 ).set_cpl_id(cpl->id()),
1294 dcp::VerificationNote(
1295 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1296 ).set_cpl_id(cpl->id()),
1301 BOOST_AUTO_TEST_CASE (verify_invalid_smpte_subtitles)
1303 using namespace boost::filesystem;
1305 path const dir("build/test/verify_invalid_smpte_subtitles");
1306 prepare_directory (dir);
1307 /* This broken_smpte.mxf does not use urn:uuid: for its subtitle ID, which we tolerate (rightly or wrongly) */
1308 copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
1309 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1310 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1311 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1313 check_verify_result (
1317 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1318 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1319 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1320 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1321 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1322 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1323 dcp::VerificationNote(
1324 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 2
1325 ).set_cpl_id(cpl->id()),
1326 dcp::VerificationNote(
1327 dcp::VerificationNote::Type::ERROR,
1328 dcp::VerificationNote::Code::INVALID_XML,
1329 string("element 'Foo' is not allowed for content model '(Id,ContentTitleText,AnnotationText?,IssueDate,ReelNumber?,Language?,EditRate,TimeCodeRate,StartTime?,DisplayType?,LoadFont*,SubtitleList)'"),
1332 ).set_cpl_id(cpl->id()),
1333 dcp::VerificationNote(
1334 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
1335 ).set_cpl_id(cpl->id()),
1336 dcp::VerificationNote(
1337 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1338 ).set_cpl_id(cpl->id()),
1339 dcp::VerificationNote(
1340 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2020-05-09T00:29:21.000+02:00"}
1341 ).set_cpl_id(cpl->id()),
1342 dcp::VerificationNote(
1343 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1344 ).set_cpl_id(cpl->id()),
1349 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles)
1351 path const dir("build/test/verify_empty_text_node_in_subtitles");
1352 prepare_directory (dir);
1353 copy_file ("test/data/empty_text.mxf", dir / "subs.mxf");
1354 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1355 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1356 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1358 check_verify_result (
1362 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1363 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1364 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1365 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1366 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1367 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1368 dcp::VerificationNote(
1369 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1370 ).set_cpl_id(cpl->id()),
1371 dcp::VerificationNote(
1372 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
1373 ).set_cpl_id(cpl->id()),
1374 dcp::VerificationNote(
1375 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
1376 ).set_cpl_id(cpl->id()),
1377 dcp::VerificationNote(
1378 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1379 ).set_cpl_id(cpl->id()),
1380 dcp::VerificationNote(
1381 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-08-09T18:34:46.000+02:00"}
1382 ).set_cpl_id(cpl->id()),
1383 dcp::VerificationNote(
1384 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1385 ).set_cpl_id(cpl->id())
1390 /** A <Text> node with no content except some <Font> nodes, which themselves do have content */
1391 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_child_nodes)
1393 path const dir("build/test/verify_empty_text_node_in_subtitles_with_child_nodes");
1394 prepare_directory (dir);
1395 copy_file ("test/data/empty_but_with_children.xml", dir / "subs.xml");
1396 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1397 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1398 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1400 check_verify_result (
1404 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1405 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1406 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1407 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1408 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1409 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1410 dcp::VerificationNote(
1411 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1412 ).set_cpl_id(cpl->id())
1417 /** A <Text> node with no content except some <Font> nodes, which themselves also have no content */
1418 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_empty_child_nodes)
1420 path const dir("build/test/verify_empty_text_node_in_subtitles_with_empty_child_nodes");
1421 prepare_directory (dir);
1422 copy_file ("test/data/empty_with_empty_children.xml", dir / "subs.xml");
1423 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1424 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1425 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1427 check_verify_result (
1431 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1432 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1433 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1434 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1435 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1436 dcp::VerificationNote(
1437 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1438 ).set_cpl_id(cpl->id()),
1439 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1440 dcp::VerificationNote(
1441 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1442 ).set_cpl_id(cpl->id()),
1443 dcp::VerificationNote(
1444 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1445 ).set_cpl_id(cpl->id())
1450 BOOST_AUTO_TEST_CASE (verify_external_asset)
1452 path const ov_dir("build/test/verify_external_asset");
1453 prepare_directory (ov_dir);
1455 auto image = black_image ();
1456 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1457 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1458 dcp_from_frame (frame, ov_dir);
1460 dcp::DCP ov (ov_dir);
1463 path const vf_dir("build/test/verify_external_asset_vf");
1464 prepare_directory (vf_dir);
1466 auto picture = ov.cpls()[0]->reels()[0]->main_picture();
1467 auto cpl = write_dcp_with_single_asset (vf_dir, picture);
1469 check_verify_result (
1473 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1474 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1475 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1476 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1477 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1478 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1479 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, picture->asset()->id() },
1480 dcp::VerificationNote(
1481 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1482 ).set_cpl_id(cpl->id())
1487 BOOST_AUTO_TEST_CASE (verify_valid_cpl_metadata)
1489 path const dir("build/test/verify_valid_cpl_metadata");
1490 prepare_directory (dir);
1492 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1493 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1494 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1496 auto reel = make_shared<dcp::Reel>();
1497 reel->add (reel_asset);
1499 reel->add (make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 16 * 24), 0));
1500 reel->add (simple_markers(16 * 24));
1502 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1504 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1505 cpl->set_main_sound_sample_rate (48000);
1506 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1507 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1508 cpl->set_version_number (1);
1512 dcp.set_annotation_text("hello");
1517 /* DCP with invalid CompositionMetadataAsset */
1518 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag)
1520 using namespace boost::filesystem;
1522 path const dir("build/test/verify_invalid_cpl_metadata_bad_tag");
1523 prepare_directory (dir);
1525 auto reel = make_shared<dcp::Reel>();
1526 reel->add (black_picture_asset(dir));
1527 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1529 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1530 cpl->set_main_sound_sample_rate (48000);
1531 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1532 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1533 cpl->set_version_number (1);
1535 reel->add (simple_markers());
1539 dcp.set_annotation_text("hello");
1542 HashCalculator calc(find_cpl(dir));
1545 Editor e (find_cpl(dir));
1546 e.replace ("MainSound", "MainSoundX");
1549 check_verify_result (
1553 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1554 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1555 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1556 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1557 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1558 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1559 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1440x1080"}, cpl),
1560 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1561 dcp::VerificationNote(
1562 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXConfiguration'"), canonical(cpl->file().get()), 50
1563 ).set_cpl_id(cpl->id()),
1564 dcp::VerificationNote(
1565 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXSampleRate'"), canonical(cpl->file().get()), 51
1566 ).set_cpl_id(cpl->id()),
1567 dcp::VerificationNote(
1568 dcp::VerificationNote::Type::ERROR,
1569 dcp::VerificationNote::Code::INVALID_XML,
1570 string("element 'meta:MainSoundXConfiguration' is not allowed for content model "
1571 "'(Id,AnnotationText?,EditRate,IntrinsicDuration,EntryPoint?,Duration?,"
1572 "FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
1573 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,"
1574 "MainSoundSampleRate,MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,"
1575 "ExtensionMetadataList?,)'"),
1576 canonical(cpl->file().get()),
1577 71).set_cpl_id(cpl->id()),
1578 dcp::VerificationNote(
1579 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
1580 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
1585 /* DCP with invalid CompositionMetadataAsset */
1586 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag)
1588 path const dir("build/test/verify_invalid_cpl_metadata_missing_tag");
1589 prepare_directory (dir);
1591 auto reel = make_shared<dcp::Reel>();
1592 reel->add (black_picture_asset(dir));
1593 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1595 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1596 cpl->set_main_sound_sample_rate (48000);
1597 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1598 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1602 dcp.set_annotation_text("hello");
1606 Editor e (find_cpl(dir));
1607 e.replace ("meta:Width", "meta:WidthX");
1610 check_verify_result (
1613 {{ dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::FAILED_READ, string("missing XML tag Width in MainPictureStoredArea") }}
1618 BOOST_AUTO_TEST_CASE (verify_invalid_language1)
1620 path const dir("build/test/verify_invalid_language1");
1621 prepare_directory (dir);
1622 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1623 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1624 asset->_language = "wrong-andbad";
1625 asset->write (dir / "subs.mxf");
1626 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1627 reel_asset->_language = "badlang";
1628 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1630 check_verify_result (
1634 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1635 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1636 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1637 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1638 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1639 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1640 dcp::VerificationNote(
1641 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang")
1642 ).set_cpl_id(cpl->id()),
1643 dcp::VerificationNote(
1644 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad")
1645 ).set_cpl_id(cpl->id()),
1646 dcp::VerificationNote(
1647 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1648 ).set_cpl_id(cpl->id())
1653 /* SMPTE DCP with invalid <Language> in the MainClosedCaption reel and also in the XML within the MXF */
1654 BOOST_AUTO_TEST_CASE (verify_invalid_language2)
1656 path const dir("build/test/verify_invalid_language2");
1657 prepare_directory (dir);
1658 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1659 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1660 asset->_language = "wrong-andbad";
1661 asset->write (dir / "subs.mxf");
1662 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1663 reel_asset->_language = "badlang";
1664 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1666 check_verify_result (
1670 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1671 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1672 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1673 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1674 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, 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 MainSound reel, the CPL additional subtitles languages and
1690 * the release territory.
1692 BOOST_AUTO_TEST_CASE (verify_invalid_language3)
1694 path const dir("build/test/verify_invalid_language3");
1695 prepare_directory (dir);
1697 auto picture = simple_picture (dir, "foo");
1698 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
1699 auto reel = make_shared<dcp::Reel>();
1700 reel->add (reel_picture);
1701 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "frobozz");
1702 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
1703 reel->add (reel_sound);
1704 reel->add (simple_markers());
1706 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1708 cpl->_additional_subtitle_languages.push_back("this-is-wrong");
1709 cpl->_additional_subtitle_languages.push_back("andso-is-this");
1710 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1711 cpl->set_main_sound_sample_rate (48000);
1712 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1713 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1714 cpl->set_version_number (1);
1715 cpl->_release_territory = "fred-jim";
1716 auto dcp = make_shared<dcp::DCP>(dir);
1718 dcp->set_annotation_text("hello");
1721 check_verify_result (
1725 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
1726 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1727 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1728 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1729 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1730 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1731 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1732 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1440x1080"}, cpl),
1733 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
1734 dcp::VerificationNote(
1735 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("this-is-wrong")
1736 ).set_cpl_id(cpl->id()),
1737 dcp::VerificationNote(
1738 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("andso-is-this")
1739 ).set_cpl_id(cpl->id()),
1740 dcp::VerificationNote(
1741 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("fred-jim")
1742 ).set_cpl_id(cpl->id()),
1743 dcp::VerificationNote(
1744 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("frobozz")
1745 ).set_cpl_id(cpl->id()),
1751 std::tuple<vector<dcp::VerificationNote>, shared_ptr<dcp::CPL>, boost::filesystem::path>
1752 check_picture_size (int width, int height, int frame_rate, bool three_d)
1754 using namespace boost::filesystem;
1756 path dcp_path = "build/test/verify_picture_test";
1757 prepare_directory (dcp_path);
1759 shared_ptr<dcp::PictureAsset> mp;
1761 mp = make_shared<dcp::StereoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1763 mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1765 auto picture_writer = mp->start_write(dcp_path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
1767 auto image = black_image (dcp::Size(width, height));
1768 auto j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048);
1769 int const length = three_d ? frame_rate * 2 : frame_rate;
1770 for (int i = 0; i < length; ++i) {
1771 picture_writer->write (j2c.data(), j2c.size());
1773 picture_writer->finalize ();
1775 auto d = make_shared<dcp::DCP>(dcp_path);
1776 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1777 cpl->set_annotation_text ("A Test DCP");
1778 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
1779 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1780 cpl->set_main_sound_sample_rate (48000);
1781 cpl->set_main_picture_stored_area(dcp::Size(width, height));
1782 cpl->set_main_picture_active_area(dcp::Size(width, height));
1783 cpl->set_version_number (1);
1785 auto reel = make_shared<dcp::Reel>();
1788 reel->add (make_shared<dcp::ReelStereoPictureAsset>(std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp), 0));
1790 reel->add (make_shared<dcp::ReelMonoPictureAsset>(std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp), 0));
1793 reel->add (simple_markers(frame_rate));
1798 d->set_annotation_text("A Test DCP");
1801 return { dcp::verify({dcp_path}, {}, &stage, &progress, {}, xsd_test).notes, cpl, dcp_path };
1807 check_picture_size_ok (int width, int height, int frame_rate, bool three_d)
1809 vector<dcp::VerificationNote> notes;
1810 shared_ptr<dcp::CPL> cpl;
1811 boost::filesystem::path dir;
1812 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1814 std::vector<dcp::VerificationNote> expected = {
1815 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1816 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1817 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1818 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1819 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1820 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1821 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, dcp::String::compose("%1x%2", width, height), cpl),
1822 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1823 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl)
1825 check_verify_result(notes, expected);
1831 check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d)
1833 vector<dcp::VerificationNote> notes;
1834 shared_ptr<dcp::CPL> cpl;
1835 boost::filesystem::path dir;
1836 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1838 std::vector<dcp::VerificationNote> expected = {
1839 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1840 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1841 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1842 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1843 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1844 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1845 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, dcp::String::compose("%1x%2", width, height), cpl),
1846 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1847 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1848 dcp::VerificationNote(
1849 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS, dcp::String::compose("%1x%2", width, height), canonical(dir / "video.mxf")
1850 ).set_cpl_id(cpl->id())
1852 check_verify_result(notes, expected);
1858 check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d)
1860 vector<dcp::VerificationNote> notes;
1861 shared_ptr<dcp::CPL> cpl;
1862 boost::filesystem::path dir;
1863 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1865 std::vector<dcp::VerificationNote> expected = {
1866 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1867 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1868 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1869 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1870 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1871 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1872 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, dcp::String::compose("%1x%2", width, height), cpl),
1873 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1874 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1875 dcp::VerificationNote(
1876 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, dcp::String::compose("%1/1", frame_rate * (three_d ? 2 : 1))
1877 ).set_cpl_id(cpl->id()),
1878 dcp::VerificationNote(
1879 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")
1880 ).set_cpl_id(cpl->id())
1883 check_verify_result(notes, expected);
1889 check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d)
1891 vector<dcp::VerificationNote> notes;
1892 shared_ptr<dcp::CPL> cpl;
1893 boost::filesystem::path dir;
1894 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1896 std::vector<dcp::VerificationNote> expected = {
1897 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1898 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1899 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1900 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1901 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1902 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1903 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, dcp::String::compose("%1x%2", width, height), cpl),
1904 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1905 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1906 dcp::VerificationNote(
1907 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")
1908 ).set_cpl_id(cpl->id())
1911 check_verify_result(notes, expected);
1915 BOOST_AUTO_TEST_CASE (verify_picture_size)
1917 using namespace boost::filesystem;
1920 check_picture_size_ok (2048, 858, 24, false);
1921 check_picture_size_ok (2048, 858, 25, false);
1922 check_picture_size_ok (2048, 858, 48, false);
1923 check_picture_size_ok (2048, 858, 24, true);
1924 check_picture_size_ok (2048, 858, 25, true);
1925 check_picture_size_ok (2048, 858, 48, true);
1928 check_picture_size_ok (1998, 1080, 24, false);
1929 check_picture_size_ok (1998, 1080, 25, false);
1930 check_picture_size_ok (1998, 1080, 48, false);
1931 check_picture_size_ok (1998, 1080, 24, true);
1932 check_picture_size_ok (1998, 1080, 25, true);
1933 check_picture_size_ok (1998, 1080, 48, true);
1936 check_picture_size_ok (4096, 1716, 24, false);
1939 check_picture_size_ok (3996, 2160, 24, false);
1941 /* Bad frame size */
1942 check_picture_size_bad_frame_size (2050, 858, 24, false);
1943 check_picture_size_bad_frame_size (2048, 658, 25, false);
1944 check_picture_size_bad_frame_size (1920, 1080, 48, true);
1945 check_picture_size_bad_frame_size (4000, 2000, 24, true);
1947 /* Bad 2K frame rate */
1948 check_picture_size_bad_2k_frame_rate (2048, 858, 26, false);
1949 check_picture_size_bad_2k_frame_rate (2048, 858, 31, false);
1950 check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true);
1952 /* Bad 4K frame rate */
1953 check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false);
1954 check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false);
1957 vector<dcp::VerificationNote> notes;
1958 shared_ptr<dcp::CPL> cpl;
1959 boost::filesystem::path dir;
1960 std::tie(notes, cpl, dir) = check_picture_size(3996, 2160, 24, true);
1962 std::vector<dcp::VerificationNote> expected = {
1963 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1964 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1965 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1966 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1967 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1968 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1969 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, dcp::String::compose("%1x%2", 3996, 2160), cpl),
1970 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1971 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1972 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D },
1979 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")
1982 std::make_shared<dcp::SubtitleString>(
1990 dcp::Time(start_frame, 24, 24),
1991 dcp::Time(end_frame, 24, 24),
1993 dcp::HAlign::CENTER,
1997 dcp::Direction::LTR,
2004 std::vector<dcp::Ruby>()
2010 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
2012 path const dir("build/test/verify_invalid_closed_caption_xml_size_in_bytes");
2013 prepare_directory (dir);
2015 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2016 for (int i = 0; i < 2048; ++i) {
2017 add_test_subtitle (asset, i * 24, i * 24 + 20);
2020 asset->set_language (dcp::LanguageTag("de-DE"));
2021 asset->write (dir / "subs.mxf");
2022 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
2023 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2025 check_verify_result (
2029 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2030 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2031 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2032 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2033 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2034 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2035 dcp::VerificationNote(
2036 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2037 ).set_cpl_id(cpl->id()),
2038 dcp::VerificationNote(
2039 dcp::VerificationNote::Type::BV21_ERROR,
2040 dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES,
2042 canonical(dir / "subs.mxf")
2043 ).set_cpl_id(cpl->id()),
2044 dcp::VerificationNote(
2045 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2046 ).set_cpl_id(cpl->id()),
2047 dcp::VerificationNote(
2048 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2049 ).set_cpl_id(cpl->id())
2055 shared_ptr<dcp::SMPTESubtitleAsset>
2056 make_large_subtitle_asset (path font_file)
2058 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2059 dcp::ArrayData big_fake_font(1024 * 1024);
2060 big_fake_font.write (font_file);
2061 for (int i = 0; i < 116; ++i) {
2062 asset->add_font (dcp::String::compose("big%1", i), big_fake_font);
2070 verify_timed_text_asset_too_large (string name)
2072 auto const dir = path("build/test") / name;
2073 prepare_directory (dir);
2074 auto asset = make_large_subtitle_asset (dir / "font.ttf");
2075 add_test_subtitle (asset, 0, 240);
2076 asset->set_language (dcp::LanguageTag("de-DE"));
2077 asset->write (dir / "subs.mxf");
2079 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), 240, 0);
2080 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2082 check_verify_result (
2086 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2087 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2088 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2089 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2090 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2091 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2092 dcp::VerificationNote(
2093 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, dcp::raw_convert<string>(121698284), canonical(dir / "subs.mxf")
2094 ).set_cpl_id(cpl->id()),
2095 dcp::VerificationNote(
2096 dcp::VerificationNote::Type::BV21_ERROR,
2097 dcp::VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES,
2098 dcp::raw_convert<string>(121634816),
2099 canonical(dir / "subs.mxf")
2100 ).set_cpl_id(cpl->id()),
2101 dcp::VerificationNote(
2102 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2103 ).set_cpl_id(cpl->id()),
2104 dcp::VerificationNote(
2105 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2106 ).set_cpl_id(cpl->id()),
2107 dcp::VerificationNote(
2108 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2109 ).set_cpl_id(cpl->id())
2114 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
2116 verify_timed_text_asset_too_large<dcp::ReelSMPTESubtitleAsset>("verify_subtitle_asset_too_large");
2117 verify_timed_text_asset_too_large<dcp::ReelSMPTEClosedCaptionAsset>("verify_closed_caption_asset_too_large");
2121 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language)
2123 path dir = "build/test/verify_missing_subtitle_language";
2124 prepare_directory (dir);
2125 auto dcp = make_simple (dir, 1, 106);
2128 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2129 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2130 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2131 "<ContentTitleText>Content</ContentTitleText>"
2132 "<AnnotationText>Annotation</AnnotationText>"
2133 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2134 "<ReelNumber>1</ReelNumber>"
2135 "<EditRate>24 1</EditRate>"
2136 "<TimeCodeRate>24</TimeCodeRate>"
2137 "<StartTime>00:00:00:00</StartTime>"
2138 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2140 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2141 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2142 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2148 dcp::File xml_file(dir / "subs.xml", "w");
2149 BOOST_REQUIRE (xml_file);
2150 xml_file.write(xml.c_str(), xml.size(), 1);
2152 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2153 subs->write (dir / "subs.mxf");
2155 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2156 auto cpl = dcp->cpls()[0];
2157 cpl->reels()[0]->add(reel_subs);
2160 check_verify_result (
2164 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2165 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2166 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2167 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2168 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2169 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2170 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
2171 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2172 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2173 dcp::VerificationNote(
2174 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
2175 ).set_cpl_id(cpl->id()),
2176 dcp::VerificationNote(
2177 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2178 ).set_cpl_id(cpl->id())
2183 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
2185 path path ("build/test/verify_mismatched_subtitle_languages");
2186 auto constexpr reel_length = 192;
2187 auto dcp = make_simple (path, 2, reel_length);
2188 auto cpl = dcp->cpls()[0];
2191 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2192 subs->set_language (dcp::LanguageTag("de-DE"));
2193 subs->add (simple_subtitle());
2195 subs->write (path / "subs1.mxf");
2196 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2197 cpl->reels()[0]->add(reel_subs);
2201 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2202 subs->set_language (dcp::LanguageTag("en-US"));
2203 subs->add (simple_subtitle());
2205 subs->write (path / "subs2.mxf");
2206 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2207 cpl->reels()[1]->add(reel_subs);
2212 check_verify_result (
2216 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2217 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2218 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2219 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2220 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2221 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2222 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2223 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2224 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
2225 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2226 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2227 dcp::VerificationNote(
2228 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2229 ).set_cpl_id(cpl->id()),
2230 dcp::VerificationNote(
2231 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2232 ).set_cpl_id(cpl->id()),
2233 dcp::VerificationNote(
2234 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES
2235 ).set_cpl_id(cpl->id()),
2240 BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
2242 path path ("build/test/verify_multiple_closed_caption_languages_allowed");
2243 auto constexpr reel_length = 192;
2244 auto dcp = make_simple (path, 2, reel_length);
2245 auto cpl = dcp->cpls()[0];
2248 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2249 ccaps->set_language (dcp::LanguageTag("de-DE"));
2250 ccaps->add (simple_subtitle());
2252 ccaps->write (path / "subs1.mxf");
2253 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2254 cpl->reels()[0]->add(reel_ccaps);
2258 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2259 ccaps->set_language (dcp::LanguageTag("en-US"));
2260 ccaps->add (simple_subtitle());
2262 ccaps->write (path / "subs2.mxf");
2263 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2264 cpl->reels()[1]->add(reel_ccaps);
2269 check_verify_result (
2273 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2274 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2275 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2276 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2277 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2278 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2279 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
2280 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2281 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2282 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2283 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2284 dcp::VerificationNote(
2285 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2286 ).set_cpl_id(cpl->id()),
2287 dcp::VerificationNote(
2288 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2289 ).set_cpl_id(cpl->id())
2294 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time)
2296 path dir = "build/test/verify_missing_subtitle_start_time";
2297 prepare_directory (dir);
2298 auto dcp = make_simple (dir, 1, 106);
2301 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2302 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2303 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2304 "<ContentTitleText>Content</ContentTitleText>"
2305 "<AnnotationText>Annotation</AnnotationText>"
2306 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2307 "<ReelNumber>1</ReelNumber>"
2308 "<Language>de-DE</Language>"
2309 "<EditRate>24 1</EditRate>"
2310 "<TimeCodeRate>24</TimeCodeRate>"
2311 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2313 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2314 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2315 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2321 dcp::File xml_file(dir / "subs.xml", "w");
2322 BOOST_REQUIRE (xml_file);
2323 xml_file.write(xml.c_str(), xml.size(), 1);
2325 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2326 subs->write (dir / "subs.mxf");
2328 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2329 auto cpl = dcp->cpls()[0];
2330 cpl->reels()[0]->add(reel_subs);
2333 check_verify_result (
2337 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2338 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2339 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2340 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2341 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2342 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2343 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2344 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
2345 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2346 dcp::VerificationNote(
2347 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2348 ).set_cpl_id(cpl->id()),
2349 dcp::VerificationNote(
2350 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2351 ).set_cpl_id(cpl->id())
2356 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time)
2358 path dir = "build/test/verify_invalid_subtitle_start_time";
2359 prepare_directory (dir);
2360 auto dcp = make_simple (dir, 1, 106);
2363 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2364 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2365 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2366 "<ContentTitleText>Content</ContentTitleText>"
2367 "<AnnotationText>Annotation</AnnotationText>"
2368 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2369 "<ReelNumber>1</ReelNumber>"
2370 "<Language>de-DE</Language>"
2371 "<EditRate>24 1</EditRate>"
2372 "<TimeCodeRate>24</TimeCodeRate>"
2373 "<StartTime>00:00:02:00</StartTime>"
2374 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2376 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2377 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2378 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2384 dcp::File xml_file(dir / "subs.xml", "w");
2385 BOOST_REQUIRE (xml_file);
2386 xml_file.write(xml.c_str(), xml.size(), 1);
2388 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2389 subs->write (dir / "subs.mxf");
2391 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2392 auto cpl = dcp->cpls()[0];
2393 cpl->reels().front()->add(reel_subs);
2396 check_verify_result (
2400 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2401 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2402 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2403 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2404 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2405 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2406 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2407 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
2408 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2409 dcp::VerificationNote(
2410 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2411 ).set_cpl_id(cpl->id()),
2412 dcp::VerificationNote(
2413 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2414 ).set_cpl_id(cpl->id())
2422 TestText (int in_, int out_, float v_position_ = 0, dcp::VAlign v_align_ = dcp::VAlign::CENTER, string text_ = "Hello")
2425 , v_position(v_position_)
2433 dcp::VAlign v_align;
2439 shared_ptr<dcp::CPL>
2440 dcp_with_text(path dir, vector<TestText> subs, optional<dcp::Key> key = boost::none, optional<string> key_id = boost::none)
2442 prepare_directory (dir);
2443 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2444 asset->set_start_time (dcp::Time());
2445 for (auto i: subs) {
2446 add_test_subtitle (asset, i.in, i.out, i.v_position, i.v_align, i.text);
2448 asset->set_language (dcp::LanguageTag("de-DE"));
2449 if (key && key_id) {
2450 asset->set_key(*key);
2451 asset->set_key_id(*key_id);
2454 asset->write (dir / "subs.mxf");
2456 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2457 return write_dcp_with_single_asset (dir, reel_asset);
2462 shared_ptr<dcp::CPL>
2463 dcp_with_text_from_file (path dir, boost::filesystem::path subs_xml)
2465 prepare_directory (dir);
2466 auto asset = make_shared<dcp::SMPTESubtitleAsset>(subs_xml);
2467 asset->set_start_time (dcp::Time());
2468 asset->set_language (dcp::LanguageTag("de-DE"));
2470 auto subs_mxf = dir / "subs.mxf";
2471 asset->write (subs_mxf);
2473 /* The call to write() puts the asset into the DCP correctly but it will have
2474 * XML re-written by our parser. Overwrite the MXF using the given file's verbatim
2477 ASDCP::TimedText::MXFWriter writer;
2478 ASDCP::WriterInfo writer_info;
2479 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
2481 Kumu::hex2bin (asset->id().c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
2482 DCP_ASSERT (c == Kumu::UUID_Length);
2483 ASDCP::TimedText::TimedTextDescriptor descriptor;
2484 descriptor.ContainerDuration = asset->intrinsic_duration();
2485 Kumu::hex2bin (asset->xml_id()->c_str(), descriptor.AssetID, ASDCP::UUIDlen, &c);
2486 DCP_ASSERT (c == Kumu::UUID_Length);
2487 ASDCP::Result_t r = writer.OpenWrite (subs_mxf.string().c_str(), writer_info, descriptor, 16384);
2488 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2489 r = writer.WriteTimedTextResource (dcp::file_to_string(subs_xml));
2490 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2493 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2494 return write_dcp_with_single_asset (dir, reel_asset);
2498 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_first_text_time)
2500 auto const dir = path("build/test/verify_invalid_subtitle_first_text_time");
2501 /* Just too early */
2502 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24 - 1, 5 * 24 }});
2503 check_verify_result (
2507 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2508 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2509 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2510 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2511 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2512 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2513 dcp::VerificationNote(
2514 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2515 ).set_cpl_id(cpl->id()),
2516 dcp::VerificationNote(
2517 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2518 ).set_cpl_id(cpl->id())
2524 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time)
2526 auto const dir = path("build/test/verify_valid_subtitle_first_text_time");
2527 /* Just late enough */
2528 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 5 * 24 }});
2529 check_verify_result(
2533 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2534 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2535 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2536 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2537 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2538 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2539 dcp::VerificationNote(
2540 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2541 ).set_cpl_id(cpl->id())
2546 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
2548 auto const dir = path("build/test/verify_valid_subtitle_first_text_time_on_second_reel");
2549 prepare_directory (dir);
2551 auto asset1 = make_shared<dcp::SMPTESubtitleAsset>();
2552 asset1->set_start_time (dcp::Time());
2553 /* Just late enough */
2554 add_test_subtitle (asset1, 4 * 24, 5 * 24);
2555 asset1->set_language (dcp::LanguageTag("de-DE"));
2557 asset1->write (dir / "subs1.mxf");
2558 auto reel_asset1 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset1, dcp::Fraction(24, 1), 5 * 24, 0);
2559 auto reel1 = make_shared<dcp::Reel>();
2560 reel1->add (reel_asset1);
2561 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 5 * 24);
2562 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
2563 reel1->add (markers1);
2565 auto asset2 = make_shared<dcp::SMPTESubtitleAsset>();
2566 asset2->set_start_time (dcp::Time());
2568 /* This would be too early on first reel but should be OK on the second */
2569 add_test_subtitle (asset2, 3, 4 * 24);
2570 asset2->set_language (dcp::LanguageTag("de-DE"));
2571 asset2->write (dir / "subs2.mxf");
2572 auto reel_asset2 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset2, dcp::Fraction(24, 1), 4 * 24, 0);
2573 auto reel2 = make_shared<dcp::Reel>();
2574 reel2->add (reel_asset2);
2575 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 4 * 24);
2576 markers2->set (dcp::Marker::LFOC, dcp::Time(4 * 24 - 1, 24, 24));
2577 reel2->add (markers2);
2579 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
2582 auto dcp = make_shared<dcp::DCP>(dir);
2584 dcp->set_annotation_text("hello");
2587 check_verify_result(
2591 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2592 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2593 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2594 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2595 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2596 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2597 dcp::VerificationNote(
2598 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2599 ).set_cpl_id(cpl->id())
2604 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_spacing)
2606 auto const dir = path("build/test/verify_invalid_subtitle_spacing");
2607 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2611 { 5 * 24 + 1, 6 * 24 },
2613 check_verify_result (
2617 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2618 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2619 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2620 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2621 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2622 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2623 dcp::VerificationNote(
2624 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING
2625 ).set_cpl_id(cpl->id()),
2626 dcp::VerificationNote(
2627 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2628 ).set_cpl_id(cpl->id())
2633 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_spacing)
2635 auto const dir = path("build/test/verify_valid_subtitle_spacing");
2636 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2640 { 5 * 24 + 16, 8 * 24 },
2643 check_verify_result(
2647 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2648 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2649 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2650 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2651 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2652 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2653 dcp::VerificationNote(
2654 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2655 ).set_cpl_id(cpl->id())
2660 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_duration)
2662 auto const dir = path("build/test/verify_invalid_subtitle_duration");
2663 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 1 }});
2664 check_verify_result (
2668 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2669 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2670 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2671 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2672 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2673 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2674 dcp::VerificationNote(
2675 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION
2676 ).set_cpl_id(cpl->id()),
2677 dcp::VerificationNote(
2678 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2679 ).set_cpl_id(cpl->id())
2684 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_duration)
2686 auto const dir = path("build/test/verify_valid_subtitle_duration");
2687 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 17 }});
2689 check_verify_result(
2693 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2694 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2695 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2696 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2697 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2698 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2699 dcp::VerificationNote(
2700 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2701 ).set_cpl_id(cpl->id())
2706 BOOST_AUTO_TEST_CASE (verify_subtitle_overlapping_reel_boundary)
2708 auto const dir = path("build/test/verify_subtitle_overlapping_reel_boundary");
2709 prepare_directory (dir);
2710 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2711 asset->set_start_time (dcp::Time());
2712 add_test_subtitle (asset, 0, 4 * 24);
2714 asset->set_language (dcp::LanguageTag("de-DE"));
2715 asset->write (dir / "subs.mxf");
2717 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 3 * 24, 0);
2718 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2719 check_verify_result (
2723 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2724 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2725 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2726 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2727 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2728 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2729 dcp::VerificationNote(
2730 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "72 96", boost::filesystem::canonical(asset->file().get())
2731 ).set_cpl_id(cpl->id()),
2732 dcp::VerificationNote(
2733 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2734 ).set_cpl_id(cpl->id()),
2735 dcp::VerificationNote(
2736 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY
2737 ).set_cpl_id(cpl->id()),
2738 dcp::VerificationNote(
2739 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2740 ).set_cpl_id(cpl->id())
2746 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count1)
2748 auto const dir = path ("build/test/invalid_subtitle_line_count1");
2749 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2752 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2753 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2754 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2755 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
2757 check_verify_result (
2761 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2762 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2763 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2764 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2765 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2766 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2767 dcp::VerificationNote(
2768 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2769 ).set_cpl_id(cpl->id()),
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_valid_subtitle_line_count1)
2779 auto const dir = path ("build/test/verify_valid_subtitle_line_count1");
2780 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2783 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2784 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2785 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2788 check_verify_result(
2792 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2793 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2794 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2795 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2796 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2797 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2798 dcp::VerificationNote(
2799 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2800 ).set_cpl_id(cpl->id())
2805 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count2)
2807 auto const dir = path ("build/test/verify_invalid_subtitle_line_count2");
2808 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2811 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2812 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2813 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2814 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
2816 check_verify_result (
2820 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2821 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2822 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2823 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2824 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2825 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2826 dcp::VerificationNote(
2827 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2828 ).set_cpl_id(cpl->id()),
2829 dcp::VerificationNote(
2830 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2831 ).set_cpl_id(cpl->id())
2836 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count2)
2838 auto const dir = path ("build/test/verify_valid_subtitle_line_count2");
2839 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2842 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2843 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2844 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2845 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
2848 check_verify_result(
2852 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2853 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2854 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2855 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2856 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2857 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2858 dcp::VerificationNote(
2859 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2860 ).set_cpl_id(cpl->id())
2865 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length1)
2867 auto const dir = path ("build/test/verify_invalid_subtitle_line_length1");
2868 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2871 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123" }
2873 check_verify_result (
2877 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2878 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2879 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2880 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2881 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2882 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2883 dcp::VerificationNote(
2884 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH
2885 ).set_cpl_id(cpl->id()),
2886 dcp::VerificationNote(
2887 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2888 ).set_cpl_id(cpl->id())
2893 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length2)
2895 auto const dir = path ("build/test/verify_invalid_subtitle_line_length2");
2896 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2899 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123456789012345678901234567890" }
2901 check_verify_result (
2905 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2906 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2907 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2908 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2909 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2910 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2911 dcp::VerificationNote(
2912 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH
2913 ).set_cpl_id(cpl->id()),
2914 dcp::VerificationNote(
2915 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2916 ).set_cpl_id(cpl->id())
2921 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1)
2923 auto const dir = path ("build/test/verify_valid_closed_caption_line_count1");
2924 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
2927 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2928 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2929 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2930 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
2932 check_verify_result (
2936 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2937 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2938 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2939 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2940 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2941 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2942 dcp::VerificationNote(
2943 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
2944 ).set_cpl_id(cpl->id()),
2945 dcp::VerificationNote(
2946 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2947 ).set_cpl_id(cpl->id())
2952 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2)
2954 auto const dir = path ("build/test/verify_valid_closed_caption_line_count2");
2955 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
2958 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2959 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2960 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2963 check_verify_result(
2967 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2968 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2969 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2970 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2971 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2972 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2973 dcp::VerificationNote(
2974 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2975 ).set_cpl_id(cpl->id())
2980 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3)
2982 auto const dir = path ("build/test/verify_invalid_closed_caption_line_count3");
2983 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
2986 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2987 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2988 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2989 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
2991 check_verify_result (
2995 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2996 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2997 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2998 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2999 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3000 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3001 dcp::VerificationNote(
3002 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
3003 ).set_cpl_id(cpl->id()),
3004 dcp::VerificationNote(
3005 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3006 ).set_cpl_id(cpl->id())
3011 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4)
3013 auto const dir = path ("build/test/verify_valid_closed_caption_line_count4");
3014 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3017 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
3018 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
3019 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
3020 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
3023 check_verify_result(
3027 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3028 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3029 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3030 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3031 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3032 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3033 dcp::VerificationNote(
3034 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3035 ).set_cpl_id(cpl->id())
3040 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_length)
3042 auto const dir = path ("build/test/verify_valid_closed_caption_line_length");
3043 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3046 { 96, 300, 0.0, dcp::VAlign::CENTER, "01234567890123456789012345678901" }
3049 check_verify_result (
3053 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3054 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3055 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3056 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3057 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3058 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3059 dcp::VerificationNote(
3060 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3061 ).set_cpl_id(cpl->id())
3066 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length)
3068 auto const dir = path ("build/test/verify_invalid_closed_caption_line_length");
3069 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3072 { 96, 300, 0.0, dcp::VAlign::CENTER, "0123456789012345678901234567890123" }
3074 check_verify_result (
3078 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3079 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3080 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3081 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3082 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3083 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3084 dcp::VerificationNote(
3085 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH
3086 ).set_cpl_id(cpl->id()),
3087 dcp::VerificationNote(
3088 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3089 ).set_cpl_id(cpl->id())
3094 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign1)
3096 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign1");
3097 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3100 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3101 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3102 { 96, 300, 0.2, dcp::VAlign::TOP, "fine" },
3104 check_verify_result (
3108 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3109 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3110 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3111 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3112 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3113 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3114 dcp::VerificationNote(
3115 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3116 ).set_cpl_id(cpl->id())
3121 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign2)
3123 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign2");
3124 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3127 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3128 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3129 { 96, 300, 0.2, dcp::VAlign::CENTER, "not fine" },
3131 check_verify_result (
3135 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3136 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3137 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3138 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3139 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3140 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3141 dcp::VerificationNote(
3142 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN
3143 ).set_cpl_id(cpl->id()),
3144 dcp::VerificationNote(
3145 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3146 ).set_cpl_id(cpl->id())
3151 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering1)
3153 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering1");
3154 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3157 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3158 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3159 { 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 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3172 dcp::VerificationNote(
3173 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3174 ).set_cpl_id(cpl->id())
3179 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering2)
3181 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering2");
3182 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3185 { 96, 300, 0.2, dcp::VAlign::BOTTOM, "This" },
3186 { 96, 300, 0.1, dcp::VAlign::BOTTOM, "is" },
3187 { 96, 300, 0.0, dcp::VAlign::BOTTOM, "also fine" },
3190 check_verify_result(
3194 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3195 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3196 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3197 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3198 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3199 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
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_ordering3)
3209 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering3");
3210 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering3.xml");
3211 check_verify_result (
3215 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3216 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3217 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3218 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3219 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3220 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3221 dcp::VerificationNote(
3222 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING
3223 ).set_cpl_id(cpl->id()),
3224 dcp::VerificationNote(
3225 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3226 ).set_cpl_id(cpl->id())
3231 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering4)
3233 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering4");
3234 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering4.xml");
3236 check_verify_result(
3240 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3241 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3242 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3243 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3244 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3245 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3246 dcp::VerificationNote(
3247 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3248 ).set_cpl_id(cpl->id())
3254 BOOST_AUTO_TEST_CASE (verify_invalid_sound_frame_rate)
3256 path const dir("build/test/verify_invalid_sound_frame_rate");
3257 prepare_directory (dir);
3259 auto picture = simple_picture (dir, "foo");
3260 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
3261 auto reel = make_shared<dcp::Reel>();
3262 reel->add (reel_picture);
3263 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000, boost::none);
3264 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
3265 reel->add (reel_sound);
3266 reel->add (simple_markers());
3267 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3269 auto dcp = make_shared<dcp::DCP>(dir);
3271 dcp->set_annotation_text("hello");
3274 check_verify_result (
3278 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3279 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3280 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3281 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3282 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3283 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
3284 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3285 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
3286 dcp::VerificationNote(
3287 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SOUND_FRAME_RATE, string("96000"), canonical(dir / "audiofoo.mxf")
3288 ).set_cpl_id(cpl->id()),
3289 dcp::VerificationNote(
3290 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3291 ).set_cpl_id(cpl->id())
3296 BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text)
3298 path const dir("build/test/verify_missing_cpl_annotation_text");
3299 auto dcp = make_simple (dir);
3302 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3304 auto const cpl = dcp->cpls()[0];
3306 HashCalculator calc(cpl->file().get());
3309 BOOST_REQUIRE (cpl->file());
3310 Editor e(cpl->file().get());
3311 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "");
3314 check_verify_result (
3318 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3319 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3320 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3321 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3322 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
3323 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3324 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3325 dcp::VerificationNote(
3326 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3327 ).set_cpl_id(cpl->id()),
3328 dcp::VerificationNote(
3329 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3330 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
3335 BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text)
3337 path const dir("build/test/verify_mismatched_cpl_annotation_text");
3338 auto dcp = make_simple (dir);
3341 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3342 auto const cpl = dcp->cpls()[0];
3344 HashCalculator calc(cpl->file().get());
3347 BOOST_REQUIRE (cpl->file());
3348 Editor e(cpl->file().get());
3349 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "<AnnotationText>A Test DCP 1</AnnotationText>");
3352 check_verify_result (
3356 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3357 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3358 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3359 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3360 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3361 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3362 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
3363 dcp::VerificationNote(
3364 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3365 ).set_cpl_id(cpl->id()),
3366 dcp::VerificationNote(
3367 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3368 ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()).set_cpl_id(cpl->id())
3373 BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration)
3375 path const dir("build/test/verify_mismatched_asset_duration");
3376 prepare_directory (dir);
3377 shared_ptr<dcp::DCP> dcp (new dcp::DCP(dir));
3378 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3380 shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (dir, "", 24);
3381 shared_ptr<dcp::SoundAsset> ms = simple_sound (dir, "", dcp::MXFMetadata(), "en-US", 25);
3383 auto reel = make_shared<dcp::Reel>(
3384 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
3385 make_shared<dcp::ReelSoundAsset>(ms, 0)
3388 reel->add (simple_markers());
3392 dcp->set_annotation_text("A Test DCP");
3395 check_verify_result (
3399 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3400 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3401 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3402 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3403 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3404 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3405 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3406 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3407 dcp::VerificationNote(
3408 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_DURATION
3409 ).set_cpl_id(cpl->id()),
3410 dcp::VerificationNote(
3411 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl->file().get())
3412 ).set_cpl_id(cpl->id())
3419 shared_ptr<dcp::CPL>
3420 verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool add_to_reel2)
3422 prepare_directory (dir);
3423 auto dcp = make_shared<dcp::DCP>(dir);
3424 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3426 auto constexpr reel_length = 192;
3428 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3429 subs->set_language (dcp::LanguageTag("de-DE"));
3430 subs->set_start_time (dcp::Time());
3431 subs->add (simple_subtitle());
3433 subs->write (dir / "subs.mxf");
3434 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
3436 auto reel1 = make_shared<dcp::Reel>(
3437 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3438 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3442 reel1->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3445 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3446 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3447 reel1->add (markers1);
3451 auto reel2 = make_shared<dcp::Reel>(
3452 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3453 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3457 reel2->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3460 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3461 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3462 reel2->add (markers2);
3467 dcp->set_annotation_text("A Test DCP");
3474 BOOST_AUTO_TEST_CASE (verify_missing_main_subtitle_from_some_reels)
3477 path dir ("build/test/missing_main_subtitle_from_some_reels");
3478 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, false);
3479 check_verify_result (
3483 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3484 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3485 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3486 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3487 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3488 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3489 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3490 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3491 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3492 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3493 dcp::VerificationNote(
3494 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS
3495 ).set_cpl_id(cpl->id()),
3496 dcp::VerificationNote(
3497 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3498 ).set_cpl_id(cpl->id())
3504 path dir ("build/test/verify_subtitles_must_be_in_all_reels2");
3505 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, true);
3506 check_verify_result(
3510 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3511 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3512 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3513 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3514 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3515 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3516 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3517 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3518 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3519 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3520 dcp::VerificationNote(
3521 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3522 ).set_cpl_id(cpl->id())
3527 path dir ("build/test/verify_subtitles_must_be_in_all_reels1");
3528 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, false, false);
3529 check_verify_result(
3533 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3534 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3535 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3536 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3537 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3538 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3539 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3540 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3541 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3542 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3543 dcp::VerificationNote(
3544 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3545 ).set_cpl_id(cpl->id())
3552 shared_ptr<dcp::CPL>
3553 verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1, int caps_in_reel2)
3555 prepare_directory (dir);
3556 auto dcp = make_shared<dcp::DCP>(dir);
3557 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3559 auto constexpr reel_length = 192;
3561 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3562 subs->set_language (dcp::LanguageTag("de-DE"));
3563 subs->set_start_time (dcp::Time());
3564 subs->add (simple_subtitle());
3566 subs->write (dir / "subs.mxf");
3568 auto reel1 = make_shared<dcp::Reel>(
3569 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3570 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3573 for (int i = 0; i < caps_in_reel1; ++i) {
3574 reel1->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3577 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3578 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3579 reel1->add (markers1);
3583 auto reel2 = make_shared<dcp::Reel>(
3584 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3585 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3588 for (int i = 0; i < caps_in_reel2; ++i) {
3589 reel2->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3592 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3593 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3594 reel2->add (markers2);
3599 dcp->set_annotation_text("A Test DCP");
3606 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_asset_counts)
3609 path dir ("build/test/mismatched_closed_caption_asset_counts");
3610 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4);
3611 check_verify_result (
3615 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3616 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3617 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3618 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3619 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3620 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3621 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3622 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3623 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3624 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3625 dcp::VerificationNote(
3626 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS
3627 ).set_cpl_id(cpl->id()),
3628 dcp::VerificationNote(
3629 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3630 ).set_cpl_id(cpl->id())
3635 path dir ("build/test/verify_closed_captions_must_be_in_all_reels2");
3636 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4);
3637 check_verify_result(
3641 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3642 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3643 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3644 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3645 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3646 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3647 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3648 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3649 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3650 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3651 dcp::VerificationNote(
3652 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3653 ).set_cpl_id(cpl->id())
3658 path dir ("build/test/verify_closed_captions_must_be_in_all_reels3");
3659 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0);
3660 check_verify_result(
3664 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3665 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3666 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3667 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3668 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3669 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3670 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3671 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3672 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3673 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3674 dcp::VerificationNote(
3675 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3676 ).set_cpl_id(cpl->id())
3684 verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost::function<void (shared_ptr<T>)> adjust)
3686 prepare_directory (dir);
3687 auto dcp = make_shared<dcp::DCP>(dir);
3688 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3690 auto constexpr reel_length = 192;
3692 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3693 subs->set_language (dcp::LanguageTag("de-DE"));
3694 subs->set_start_time (dcp::Time());
3695 subs->add (simple_subtitle());
3697 subs->write (dir / "subs.mxf");
3698 auto reel_text = make_shared<T>(subs, dcp::Fraction(24, 1), reel_length, 0);
3701 auto reel = make_shared<dcp::Reel>(
3702 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
3703 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
3706 reel->add (reel_text);
3708 reel->add (simple_markers(reel_length));
3713 dcp->set_annotation_text("A Test DCP");
3716 check_verify_result (
3720 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3721 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3722 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3723 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3724 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3725 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3726 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3727 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3728 dcp::VerificationNote(
3729 dcp::VerificationNote::Type::BV21_ERROR, code, subs->id()
3730 ).set_cpl_id(cpl->id()),
3731 dcp::VerificationNote(
3732 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3733 ).set_cpl_id(cpl->id())
3738 BOOST_AUTO_TEST_CASE (verify_text_entry_point)
3740 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3741 "build/test/verify_subtitle_entry_point_must_be_present",
3742 dcp::VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT,
3743 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3744 asset->unset_entry_point ();
3748 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3749 "build/test/verify_subtitle_entry_point_must_be_zero",
3750 dcp::VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT,
3751 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3752 asset->set_entry_point (4);
3756 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3757 "build/test/verify_closed_caption_entry_point_must_be_present",
3758 dcp::VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT,
3759 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3760 asset->unset_entry_point ();
3764 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3765 "build/test/verify_closed_caption_entry_point_must_be_zero",
3766 dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT,
3767 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3768 asset->set_entry_point (9);
3774 BOOST_AUTO_TEST_CASE (verify_missing_hash)
3778 path const dir("build/test/verify_missing_hash");
3779 auto dcp = make_simple (dir);
3782 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3783 auto const cpl = dcp->cpls()[0];
3784 BOOST_REQUIRE_EQUAL (cpl->reels().size(), 1U);
3785 BOOST_REQUIRE (cpl->reels()[0]->main_picture());
3786 auto asset_id = cpl->reels()[0]->main_picture()->id();
3788 HashCalculator calc(cpl->file().get());
3791 BOOST_REQUIRE (cpl->file());
3792 Editor e(cpl->file().get());
3793 e.delete_first_line_containing("<Hash>");
3796 check_verify_result (
3800 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3801 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3802 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3803 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
3804 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3805 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3806 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3807 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3808 dcp::VerificationNote(
3809 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
3810 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
3811 dcp::VerificationNote(
3812 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id
3813 ).set_cpl_id(cpl->id())
3820 verify_markers_test (
3822 vector<pair<dcp::Marker, dcp::Time>> markers,
3823 vector<dcp::VerificationNote> test_notes
3826 auto dcp = make_simple (dir);
3827 auto cpl = dcp->cpls()[0];
3828 cpl->set_content_kind(dcp::ContentKind::FEATURE);
3829 auto markers_asset = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 24);
3830 for (auto const& i: markers) {
3831 markers_asset->set (i.first, i.second);
3833 cpl->reels()[0]->add(markers_asset);
3836 for (auto& note: test_notes) {
3837 note.set_cpl_id(cpl->id());
3840 test_notes.push_back(ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl));
3841 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl));
3842 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl));
3843 test_notes.push_back(ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl));
3844 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl));
3845 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl));
3846 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl));
3847 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl));
3848 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl));
3850 check_verify_result({dir}, {}, test_notes);
3854 BOOST_AUTO_TEST_CASE (verify_markers)
3856 verify_markers_test (
3857 "build/test/verify_markers_all_correct",
3859 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3860 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3861 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3862 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3867 verify_markers_test (
3868 "build/test/verify_markers_missing_ffec",
3870 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3871 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3872 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3875 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }
3878 verify_markers_test (
3879 "build/test/verify_markers_missing_ffmc",
3881 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3882 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3883 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3886 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }
3889 verify_markers_test (
3890 "build/test/verify_markers_missing_ffoc",
3892 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3893 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3894 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3897 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC}
3900 verify_markers_test (
3901 "build/test/verify_markers_missing_lfoc",
3903 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3904 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3905 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) }
3908 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }
3911 verify_markers_test (
3912 "build/test/verify_markers_incorrect_ffoc",
3914 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3915 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3916 { dcp::Marker::FFOC, dcp::Time(3, 24, 24) },
3917 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
3920 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_FFOC, string("3") }
3923 verify_markers_test (
3924 "build/test/verify_markers_incorrect_lfoc",
3926 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
3927 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
3928 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
3929 { dcp::Marker::LFOC, dcp::Time(18, 24, 24) }
3932 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_LFOC, string("18") }
3937 BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number)
3939 path dir = "build/test/verify_missing_cpl_metadata_version_number";
3940 prepare_directory (dir);
3941 auto dcp = make_simple (dir);
3942 auto cpl = dcp->cpls()[0];
3943 cpl->unset_version_number();
3946 check_verify_result(
3950 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3951 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3952 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3953 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3954 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3955 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3956 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3957 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
3958 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3959 dcp::VerificationNote(
3960 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->file().get()
3961 ).set_cpl_id(cpl->id())
3966 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1)
3968 path dir = "build/test/verify_missing_extension_metadata1";
3969 auto dcp = make_simple (dir);
3972 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3973 auto cpl = dcp->cpls()[0];
3975 HashCalculator calc(cpl->file().get());
3978 Editor e (cpl->file().get());
3979 e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
3982 check_verify_result (
3986 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3987 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3988 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3989 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3990 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3991 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3992 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3993 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
3994 dcp::VerificationNote(
3995 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
3996 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
3997 dcp::VerificationNote(
3998 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
3999 ).set_cpl_id(cpl->id())
4004 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2)
4006 path dir = "build/test/verify_missing_extension_metadata2";
4007 auto dcp = make_simple (dir);
4010 auto cpl = dcp->cpls()[0];
4012 HashCalculator calc(cpl->file().get());
4015 Editor e (cpl->file().get());
4016 e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
4019 check_verify_result (
4023 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4024 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4025 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4026 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4027 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4028 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4029 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4030 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4031 dcp::VerificationNote(
4032 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4033 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4034 dcp::VerificationNote(
4035 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
4036 ).set_cpl_id(cpl->id())
4041 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3)
4043 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata3";
4044 auto dcp = make_simple (dir);
4047 auto const cpl = dcp->cpls()[0];
4049 HashCalculator calc(cpl->file().get());
4052 Editor e (cpl->file().get());
4053 e.replace ("<meta:Name>A", "<meta:NameX>A");
4054 e.replace ("n</meta:Name>", "n</meta:NameX>");
4057 check_verify_result (
4061 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4062 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4063 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4064 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4065 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4066 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4067 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4068 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4069 dcp::VerificationNote(
4070 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:NameX'"), cpl->file().get(), 70
4071 ).set_cpl_id(cpl->id()),
4072 dcp::VerificationNote(
4073 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()),
4074 dcp::VerificationNote(
4075 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4076 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4081 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1)
4083 path dir = "build/test/verify_invalid_extension_metadata1";
4084 auto dcp = make_simple (dir);
4087 auto cpl = dcp->cpls()[0];
4089 HashCalculator calc(cpl->file().get());
4092 Editor e (cpl->file().get());
4093 e.replace ("Application", "Fred");
4096 check_verify_result (
4100 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4101 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4102 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4103 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4104 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4105 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4106 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4107 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4108 dcp::VerificationNote(
4109 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4110 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4111 dcp::VerificationNote(
4112 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> should be 'Application'"), cpl->file().get()
4113 ).set_cpl_id(cpl->id())
4118 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2)
4120 path dir = "build/test/verify_invalid_extension_metadata2";
4121 auto dcp = make_simple (dir);
4124 auto cpl = dcp->cpls()[0];
4126 HashCalculator calc(cpl->file().get());
4129 Editor e (cpl->file().get());
4130 e.replace ("DCP Constraints Profile", "Fred");
4133 check_verify_result (
4137 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4138 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4139 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4140 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4141 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4142 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4143 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4144 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4145 dcp::VerificationNote(
4146 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4147 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4148 dcp::VerificationNote(
4149 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'"), cpl->file().get()
4150 ).set_cpl_id(cpl->id())
4155 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6)
4157 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata6";
4158 auto dcp = make_simple (dir);
4161 auto const cpl = dcp->cpls()[0];
4163 HashCalculator calc(cpl->file().get());
4166 Editor e (cpl->file().get());
4167 e.replace ("<meta:Value>", "<meta:ValueX>");
4168 e.replace ("</meta:Value>", "</meta:ValueX>");
4171 check_verify_result (
4175 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4176 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4177 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4178 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4179 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4180 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4181 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4182 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4183 dcp::VerificationNote(
4184 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:ValueX'"), cpl->file().get(), 74
4185 ).set_cpl_id(cpl->id()),
4186 dcp::VerificationNote(
4187 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
4188 ).set_cpl_id(cpl->id()),
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())
4196 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7)
4198 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata7";
4199 auto dcp = make_simple (dir);
4202 auto const cpl = dcp->cpls()[0];
4204 HashCalculator calc(cpl->file().get());
4207 Editor e (cpl->file().get());
4208 e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
4211 check_verify_result (
4215 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4216 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4217 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4218 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4219 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4220 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4221 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4222 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4223 dcp::VerificationNote(
4224 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4225 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4226 dcp::VerificationNote(
4227 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()
4228 ).set_cpl_id(cpl->id())
4233 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8)
4235 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata8";
4236 auto dcp = make_simple (dir);
4239 auto const cpl = dcp->cpls()[0];
4241 HashCalculator calc(cpl->file().get());
4244 Editor e (cpl->file().get());
4245 e.replace ("<meta:Property>", "<meta:PropertyX>");
4246 e.replace ("</meta:Property>", "</meta:PropertyX>");
4249 check_verify_result (
4253 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4254 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4255 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4256 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4257 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4258 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4259 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4260 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4261 dcp::VerificationNote(
4262 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyX'"), cpl->file().get(), 72
4263 ).set_cpl_id(cpl->id()),
4264 dcp::VerificationNote(
4265 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()),
4266 dcp::VerificationNote(
4267 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4268 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4273 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9)
4275 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata9";
4276 auto dcp = make_simple (dir);
4279 auto const cpl = dcp->cpls()[0];
4281 HashCalculator calc(cpl->file().get());
4284 Editor e (cpl->file().get());
4285 e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
4286 e.replace ("</meta:PropertyList>", "</meta:PropertyListX>");
4289 check_verify_result (
4293 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4294 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4295 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4296 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4297 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4298 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4299 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4300 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4301 dcp::VerificationNote(
4302 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyListX'"), cpl->file().get(), 71
4303 ).set_cpl_id(cpl->id()),
4304 dcp::VerificationNote(
4305 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
4306 ).set_cpl_id(cpl->id()),
4307 dcp::VerificationNote(
4308 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4309 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4315 BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content)
4317 path const dir = "build/test/verify_unsigned_cpl_with_encrypted_content";
4318 prepare_directory (dir);
4319 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4320 copy_file (i.path(), dir / i.path().filename());
4323 path const pkl = dir / ( "pkl_" + encryption_test_pkl_id() + ".xml");
4324 path const cpl_path = dir / ( "cpl_" + encryption_test_cpl_id() + ".xml");
4326 HashCalculator calc(cpl_path);
4330 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4333 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4335 check_verify_result (
4339 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4340 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4341 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4342 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4343 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4344 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4345 dcp::VerificationNote(
4346 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
4347 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4348 dcp::VerificationNote(
4349 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4350 ).set_cpl_id(cpl->id()),
4351 dcp::VerificationNote(
4352 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4353 ).set_cpl_id(cpl->id()),
4354 dcp::VerificationNote(
4355 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4356 ).set_cpl_id(cpl->id()),
4357 dcp::VerificationNote(
4358 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4359 ).set_cpl_id(cpl->id()),
4360 dcp::VerificationNote(
4361 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4362 ).set_cpl_id(cpl->id()),
4363 dcp::VerificationNote(
4364 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4365 ).set_cpl_id(cpl->id()),
4366 dcp::VerificationNote(
4367 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_path)
4368 ).set_cpl_id(cpl->id())
4373 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_encrypted_content)
4375 path dir = "build/test/unsigned_pkl_with_encrypted_content";
4376 prepare_directory (dir);
4377 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4378 copy_file (i.path(), dir / i.path().filename());
4381 path const cpl_path = dir / ("cpl_" + encryption_test_cpl_id() + ".xml");
4382 path const pkl = dir / ("pkl_" + encryption_test_pkl_id() + ".xml");
4385 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4388 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4390 check_verify_result (
4394 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4395 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4396 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4397 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4398 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4399 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4400 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4401 dcp::VerificationNote(
4402 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4403 ).set_cpl_id(cpl->id()),
4404 dcp::VerificationNote(
4405 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4406 ).set_cpl_id(cpl->id()),
4407 dcp::VerificationNote(
4408 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4409 ).set_cpl_id(cpl->id()),
4410 dcp::VerificationNote(
4411 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4412 ).set_cpl_id(cpl->id()),
4413 dcp::VerificationNote(
4414 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4415 ).set_cpl_id(cpl->id()),
4416 dcp::VerificationNote(
4417 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4418 ).set_cpl_id(cpl->id()),
4419 dcp::VerificationNote(
4420 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, encryption_test_pkl_id(), canonical(pkl)
4426 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_unencrypted_content)
4428 path dir = "build/test/verify_unsigned_pkl_with_unencrypted_content";
4429 prepare_directory (dir);
4430 for (auto i: directory_iterator("test/ref/DCP/dcp_test1")) {
4431 copy_file (i.path(), dir / i.path().filename());
4435 Editor e (dir / dcp_test1_pkl());
4436 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4439 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4441 check_verify_result(
4445 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4446 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4447 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4448 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4449 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4450 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4451 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4452 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4453 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4458 BOOST_AUTO_TEST_CASE (verify_partially_encrypted)
4460 path dir ("build/test/verify_must_not_be_partially_encrypted");
4461 prepare_directory (dir);
4465 auto signer = make_shared<dcp::CertificateChain>();
4466 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/ca.self-signed.pem")));
4467 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/intermediate.signed.pem")));
4468 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/leaf.signed.pem")));
4469 signer->set_key (dcp::file_to_string("test/ref/crypt/leaf.key"));
4471 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
4475 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction (24, 1), dcp::Standard::SMPTE);
4478 auto writer = mp->start_write(dir / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
4479 dcp::ArrayData j2c ("test/data/flat_red.j2c");
4480 for (int i = 0; i < 24; ++i) {
4481 writer->write (j2c.data(), j2c.size());
4483 writer->finalize ();
4485 auto ms = simple_sound (dir, "", dcp::MXFMetadata(), "de-DE");
4487 auto reel = make_shared<dcp::Reel>(
4488 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
4489 make_shared<dcp::ReelSoundAsset>(ms, 0)
4492 reel->add (simple_markers());
4496 cpl->set_content_version (
4497 {"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"}
4499 cpl->set_annotation_text ("A Test DCP");
4500 cpl->set_issuer ("OpenDCP 0.0.25");
4501 cpl->set_creator ("OpenDCP 0.0.25");
4502 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
4503 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
4504 cpl->set_main_sound_sample_rate (48000);
4505 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
4506 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
4507 cpl->set_version_number (1);
4511 d.set_issuer("OpenDCP 0.0.25");
4512 d.set_creator("OpenDCP 0.0.25");
4513 d.set_issue_date("2012-07-17T04:45:18+00:00");
4514 d.set_annotation_text("A Test DCP");
4515 d.write_xml(signer);
4517 check_verify_result (
4521 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4522 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4523 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4524 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1440x1080"}, cpl),
4525 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4526 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4527 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4528 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4529 dcp::VerificationNote(
4530 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::PARTIALLY_ENCRYPTED
4531 ).set_cpl_id(cpl->id())
4536 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_2k)
4538 vector<dcp::VerificationNote> notes;
4539 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"));
4540 auto reader = picture.start_read ();
4541 auto frame = reader->get_frame (0);
4542 verify_j2k(frame, 0, 0, 24, notes);
4543 BOOST_CHECK(notes.empty());
4547 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_4k)
4549 vector<dcp::VerificationNote> notes;
4550 dcp::MonoPictureAsset picture (find_file(private_test / "data" / "sul", "TLR"));
4551 auto reader = picture.start_read ();
4552 auto frame = reader->get_frame (0);
4553 verify_j2k(frame, 0, 0, 24, notes);
4554 BOOST_CHECK(notes.empty());
4558 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp)
4560 boost::filesystem::path dir = "build/test/verify_jpeg2000_codestream_libdcp";
4561 prepare_directory (dir);
4562 auto dcp = make_simple (dir);
4564 vector<dcp::VerificationNote> notes;
4565 dcp::MonoPictureAsset picture (find_file(dir, "video"));
4566 auto reader = picture.start_read ();
4567 auto frame = reader->get_frame (0);
4568 verify_j2k(frame, 0, 0, 24, notes);
4569 BOOST_CHECK(notes.empty());
4573 /** Check that ResourceID and the XML ID being different is spotted */
4574 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id)
4576 boost::filesystem::path const dir = "build/test/verify_mismatched_subtitle_resource_id";
4577 prepare_directory (dir);
4579 ASDCP::WriterInfo writer_info;
4580 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4583 auto mxf_id = dcp::make_uuid ();
4584 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4585 BOOST_REQUIRE (c == Kumu::UUID_Length);
4587 auto resource_id = dcp::make_uuid ();
4588 ASDCP::TimedText::TimedTextDescriptor descriptor;
4589 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4590 DCP_ASSERT (c == Kumu::UUID_Length);
4592 auto xml_id = dcp::make_uuid ();
4593 ASDCP::TimedText::MXFWriter writer;
4594 auto subs_mxf = dir / "subs.mxf";
4595 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4596 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4597 writer.WriteTimedTextResource (dcp::String::compose(
4598 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4599 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4600 "<Id>urn:uuid:%1</Id>"
4601 "<ContentTitleText>Content</ContentTitleText>"
4602 "<AnnotationText>Annotation</AnnotationText>"
4603 "<IssueDate>2018-10-02T12:25:14</IssueDate>"
4604 "<ReelNumber>1</ReelNumber>"
4605 "<Language>en-US</Language>"
4606 "<EditRate>25 1</EditRate>"
4607 "<TimeCodeRate>25</TimeCodeRate>"
4608 "<StartTime>00:00:00:00</StartTime>"
4609 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
4611 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4612 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4613 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4622 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4623 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4625 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4627 check_verify_result (
4631 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4632 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4633 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4634 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4635 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4636 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4637 dcp::VerificationNote(
4638 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4639 ).set_cpl_id(cpl->id()),
4640 dcp::VerificationNote(
4641 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID
4642 ).set_cpl_id(cpl->id()),
4643 dcp::VerificationNote(
4644 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4645 ).set_cpl_id(cpl->id()),
4646 dcp::VerificationNote(
4647 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4648 ).set_cpl_id(cpl->id())
4653 /** Check that ResourceID and the MXF ID being the same is spotted */
4654 BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
4656 boost::filesystem::path const dir = "build/test/verify_incorrect_timed_text_id";
4657 prepare_directory (dir);
4659 ASDCP::WriterInfo writer_info;
4660 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4663 auto mxf_id = dcp::make_uuid ();
4664 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4665 BOOST_REQUIRE (c == Kumu::UUID_Length);
4667 auto resource_id = mxf_id;
4668 ASDCP::TimedText::TimedTextDescriptor descriptor;
4669 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4670 DCP_ASSERT (c == Kumu::UUID_Length);
4672 auto xml_id = resource_id;
4673 ASDCP::TimedText::MXFWriter writer;
4674 auto subs_mxf = dir / "subs.mxf";
4675 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4676 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4677 writer.WriteTimedTextResource (dcp::String::compose(
4678 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4679 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4680 "<Id>urn:uuid:%1</Id>"
4681 "<ContentTitleText>Content</ContentTitleText>"
4682 "<AnnotationText>Annotation</AnnotationText>"
4683 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
4684 "<ReelNumber>1</ReelNumber>"
4685 "<Language>en-US</Language>"
4686 "<EditRate>25 1</EditRate>"
4687 "<TimeCodeRate>25</TimeCodeRate>"
4688 "<StartTime>00:00:00:00</StartTime>"
4689 "<LoadFont ID=\"font\">urn:uuid:0ce6e0ba-58b9-4344-8929-4d9c959c2d55</LoadFont>"
4691 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4692 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4693 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4702 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4703 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4705 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4707 check_verify_result (
4711 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4712 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4713 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4714 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4715 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4716 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4717 dcp::VerificationNote(
4718 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4719 ).set_cpl_id(cpl->id()),
4720 dcp::VerificationNote(
4721 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID
4722 ).set_cpl_id(cpl->id()),
4723 dcp::VerificationNote(
4724 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4725 ).set_cpl_id(cpl->id()),
4726 dcp::VerificationNote(
4727 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4728 ).set_cpl_id(cpl->id()),
4729 dcp::VerificationNote(
4730 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2018-10-02T12:25:14+02:00"}
4731 ).set_cpl_id(cpl->id())
4736 /** Check a DCP with a 3D asset marked as 2D */
4737 BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod)
4739 auto const path = private_test / "data" / "xm";
4741 auto cpl = std::make_shared<dcp::CPL>(find_prefix(path, "CPL_"));
4744 check_verify_result (
4748 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4749 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4750 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4751 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4752 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4753 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4754 dcp::VerificationNote(
4755 dcp::VerificationNote::Type::WARNING,
4756 dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(path, "j2c"))
4758 dcp::VerificationNote(
4759 dcp::VerificationNote::Type::BV21_ERROR,
4760 dcp::VerificationNote::Code::INVALID_STANDARD
4767 BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers)
4769 path dir = "build/test/verify_unexpected_things_in_main_markers";
4770 prepare_directory (dir);
4771 auto dcp = make_simple (dir, 1, 24);
4774 HashCalculator calc(find_cpl(dir));
4777 Editor e (find_cpl(dir));
4779 " <IntrinsicDuration>24</IntrinsicDuration>",
4780 "<EntryPoint>0</EntryPoint><Duration>24</Duration>"
4784 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4786 check_verify_result (
4790 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4791 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4792 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4793 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4794 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4795 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4796 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4797 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4798 dcp::VerificationNote(
4799 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4800 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4801 dcp::VerificationNote(
4802 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_ENTRY_POINT
4803 ).set_cpl_id(cpl->id()),
4804 dcp::VerificationNote(
4805 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_DURATION
4806 ).set_cpl_id(cpl->id())
4811 BOOST_AUTO_TEST_CASE(verify_invalid_content_kind)
4813 path dir = "build/test/verify_invalid_content_kind";
4814 prepare_directory (dir);
4815 auto dcp = make_simple (dir, 1, 24);
4818 HashCalculator calc(find_cpl(dir));
4821 Editor e(find_cpl(dir));
4822 e.replace("trailer", "trip");
4825 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4827 check_verify_result (
4831 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4832 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4833 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4834 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4835 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4836 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4837 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4838 dcp::VerificationNote(
4839 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4840 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4841 dcp::VerificationNote(
4842 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip")
4843 ).set_cpl_id(cpl->id()),
4849 BOOST_AUTO_TEST_CASE(verify_valid_content_kind)
4851 path dir = "build/test/verify_valid_content_kind";
4852 prepare_directory (dir);
4853 auto dcp = make_simple (dir, 1, 24);
4856 HashCalculator calc(find_cpl(dir));
4859 Editor e(find_cpl(dir));
4860 e.replace("<ContentKind>trailer</ContentKind>", "<ContentKind scope=\"http://bobs.contents/\">trip</ContentKind>");
4863 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4865 check_verify_result (
4869 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4870 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4871 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4872 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4873 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4874 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4875 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
4876 dcp::VerificationNote(
4877 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4878 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4883 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1)
4885 path dir = "build/test/verify_invalid_main_picture_active_area_1";
4886 prepare_directory(dir);
4887 auto dcp = make_simple(dir, 1, 24);
4890 auto constexpr area = "<meta:MainPictureActiveArea>";
4892 HashCalculator calc(find_cpl(dir));
4895 Editor e(find_cpl(dir));
4896 e.delete_lines_after(area, 2);
4897 e.insert(area, "<meta:Height>4080</meta:Height>");
4898 e.insert(area, "<meta:Width>1997</meta:Width>");
4901 dcp::PKL pkl(find_pkl(dir));
4902 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4904 check_verify_result(
4908 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4909 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4910 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4911 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4912 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4913 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4914 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4915 dcp::VerificationNote(
4916 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4917 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4918 dcp::VerificationNote(
4919 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 1997 is not a multiple of 2", canonical(find_cpl(dir))
4920 ).set_cpl_id(cpl->id()),
4921 dcp::VerificationNote(
4922 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))
4923 ).set_cpl_id(cpl->id()),
4928 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2)
4930 path dir = "build/test/verify_invalid_main_picture_active_area_2";
4931 prepare_directory(dir);
4932 auto dcp = make_simple(dir, 1, 24);
4935 auto constexpr area = "<meta:MainPictureActiveArea>";
4937 HashCalculator calc(find_cpl(dir));
4940 Editor e(find_cpl(dir));
4941 e.delete_lines_after(area, 2);
4942 e.insert(area, "<meta:Height>5125</meta:Height>");
4943 e.insert(area, "<meta:Width>9900</meta:Width>");
4946 dcp::PKL pkl(find_pkl(dir));
4947 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4949 check_verify_result(
4953 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4954 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4955 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4956 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4957 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4958 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4959 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4960 dcp::VerificationNote(
4961 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
4962 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4963 dcp::VerificationNote(
4964 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is not a multiple of 2", canonical(find_cpl(dir))
4965 ).set_cpl_id(cpl->id()),
4966 dcp::VerificationNote(
4967 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))
4968 ).set_cpl_id(cpl->id()),
4969 dcp::VerificationNote(
4970 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))
4971 ).set_cpl_id(cpl->id())
4976 BOOST_AUTO_TEST_CASE(verify_duplicate_pkl_asset_ids)
4980 path dir = "build/test/verify_duplicate_pkl_asset_ids";
4981 prepare_directory(dir);
4982 auto dcp = make_simple(dir, 1, 24);
4986 Editor e(find_pkl(dir));
4987 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358ab");
4990 dcp::PKL pkl(find_pkl(dir));
4991 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
4993 check_verify_result(
4997 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4998 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4999 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5000 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5001 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5002 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5003 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5004 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl.id(), canonical(find_pkl(dir)) },
5009 BOOST_AUTO_TEST_CASE(verify_duplicate_assetmap_asset_ids)
5013 path dir = "build/test/verify_duplicate_assetmap_asset_ids";
5014 prepare_directory(dir);
5015 auto dcp = make_simple(dir, 1, 24);
5019 Editor e(find_asset_map(dir));
5020 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:97f0f352-5b77-48ee-a558-9df37717f4fa");
5023 dcp::PKL pkl(find_pkl(dir));
5024 dcp::AssetMap asset_map(find_asset_map(dir));
5025 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
5027 check_verify_result(
5031 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5032 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5033 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5034 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5035 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5036 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5037 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5038 dcp::VerificationNote(
5039 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map.id(), canonical(find_asset_map(dir))
5041 dcp::VerificationNote(
5042 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, string("5407b210-4441-4e97-8b16-8bdc7c12da54")
5048 BOOST_AUTO_TEST_CASE(verify_mismatched_sound_channel_counts)
5050 boost::filesystem::path const path = "build/test/verify_mismatched_sound_channel_counts";
5052 dcp::MXFMetadata mxf_meta;
5053 mxf_meta.company_name = "OpenDCP";
5054 mxf_meta.product_name = "OpenDCP";
5055 mxf_meta.product_version = "0.0.25";
5057 auto constexpr sample_rate = 48000;
5058 auto constexpr frames = 240;
5060 boost::filesystem::remove_all(path);
5061 boost::filesystem::create_directories(path);
5062 auto dcp = make_shared<dcp::DCP>(path);
5063 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5064 cpl->set_annotation_text("hello");
5065 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R"));
5066 cpl->set_main_sound_sample_rate(sample_rate);
5067 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5068 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5069 cpl->set_version_number(1);
5073 /* Reel with 2 channels of audio */
5075 auto mp = simple_picture(path, "1", frames, {});
5076 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5078 auto reel = make_shared<dcp::Reel>(
5079 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5080 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5083 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5084 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5091 /* Reel with 6 channels of audio */
5093 auto mp = simple_picture(path, "2", frames, {});
5094 auto ms = simple_sound(path, "2", mxf_meta, "en-US", frames, sample_rate, {}, 6);
5096 auto reel = make_shared<dcp::Reel>(
5097 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5098 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5101 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5102 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 0, frames - 1, 24));
5109 dcp->set_annotation_text("hello");
5112 check_verify_result(
5116 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5117 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5118 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5119 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5120 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5121 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5122 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5123 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5124 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video2.mxf"), cpl),
5125 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video2.mxf"), cpl),
5126 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5127 dcp::VerificationNote(
5128 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, canonical(find_file(path, "audio2"))
5129 ).set_cpl_id(cpl->id())
5134 BOOST_AUTO_TEST_CASE(verify_invalid_main_sound_configuration)
5136 boost::filesystem::path const path = "build/test/verify_invalid_main_sound_configuration";
5138 dcp::MXFMetadata mxf_meta;
5139 mxf_meta.company_name = "OpenDCP";
5140 mxf_meta.product_name = "OpenDCP";
5141 mxf_meta.product_version = "0.0.25";
5143 auto constexpr sample_rate = 48000;
5144 auto constexpr frames = 240;
5146 boost::filesystem::remove_all(path);
5147 boost::filesystem::create_directories(path);
5148 auto dcp = make_shared<dcp::DCP>(path);
5149 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5150 cpl->set_annotation_text("hello");
5151 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5152 cpl->set_main_sound_sample_rate(sample_rate);
5153 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5154 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5155 cpl->set_version_number(1);
5157 auto mp = simple_picture(path, "1", frames, {});
5158 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5160 auto reel = make_shared<dcp::Reel>(
5161 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5162 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5165 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5166 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5167 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 9, 23, 24));
5173 dcp->set_annotation_text("hello");
5176 check_verify_result(
5180 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5181 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5182 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5183 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5184 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5185 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5186 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5187 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5188 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5189 dcp::VerificationNote(
5190 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))
5191 ).set_cpl_id(cpl->id())
5196 BOOST_AUTO_TEST_CASE(verify_invalid_tile_part_size)
5198 boost::filesystem::path const path = "build/test/verify_invalid_tile_part_size";
5199 auto constexpr video_frames = 24;
5200 auto constexpr sample_rate = 48000;
5202 boost::filesystem::remove_all(path);
5203 boost::filesystem::create_directories(path);
5205 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
5206 auto picture_writer = mp->start_write(path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
5208 dcp::Size const size(1998, 1080);
5209 auto image = make_shared<dcp::OpenJPEGImage>(size);
5210 boost::random::mt19937 rng(1);
5211 boost::random::uniform_int_distribution<> dist(0, 4095);
5212 for (int c = 0; c < 3; ++c) {
5213 for (int p = 0; p < (1998 * 1080); ++p) {
5214 image->data(c)[p] = dist(rng);
5217 auto j2c = dcp::compress_j2k(image, 750000000, video_frames, false, false);
5218 for (int i = 0; i < 24; ++i) {
5219 picture_writer->write(j2c.data(), j2c.size());
5221 picture_writer->finalize();
5223 auto dcp = make_shared<dcp::DCP>(path);
5224 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5225 cpl->set_content_version(
5226 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11", "content-version-label-text")
5228 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5229 cpl->set_main_sound_sample_rate(sample_rate);
5230 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5231 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5232 cpl->set_version_number(1);
5234 auto ms = simple_sound(path, "", dcp::MXFMetadata(), "en-US", video_frames, sample_rate, {});
5236 auto reel = make_shared<dcp::Reel>(
5237 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5238 make_shared<dcp::ReelSoundAsset>(ms, 0)
5243 dcp->set_annotation_text("A Test DCP");
5246 vector<dcp::VerificationNote> expected = {
5247 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5248 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5249 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video.mxf"), cpl),
5250 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5251 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5252 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5253 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5254 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5255 dcp::VerificationNote(
5256 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
5257 ).set_cpl_id(cpl->id()),
5258 dcp::VerificationNote(
5259 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
5260 ).set_cpl_id(cpl->id())
5263 for (auto frame = 0; frame < 24; frame++) {
5265 dcp::VerificationNote(
5266 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(path / "video.mxf")
5267 ).set_frame(frame).set_frame_rate(24).set_cpl_id(cpl->id())
5271 int component_sizes[] = {
5277 for (auto frame = 0; frame < 24; frame++) {
5278 for (auto component = 0; component < 3; component++) {
5280 dcp::VerificationNote(
5281 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE
5282 ).set_frame(frame).set_component(component).set_size(component_sizes[component]).set_cpl_id(cpl->id())
5287 check_verify_result({ path }, {}, expected);
5291 BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces)
5293 boost::filesystem::path const dir = "test/ref/DCP/subtitle_namespace_test";
5296 BOOST_REQUIRE(!dcp.cpls().empty());
5297 auto cpl = dcp.cpls()[0];
5299 check_verify_result(
5303 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5304 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5305 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5306 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
5307 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"Dcp_FTR-1_F_XX-XX_MOS_2K_20230407_SMPTE_OV"}, cpl),
5308 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5309 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5310 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5311 dcp::VerificationNote(
5312 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
5313 ).set_cpl_id(cpl->id()),
5314 dcp::VerificationNote(
5315 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
5316 ).set_cpl_id(cpl->id()),
5317 dcp::VerificationNote(
5318 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
5319 ).set_cpl_id(cpl->id()),
5320 dcp::VerificationNote(
5321 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(find_file(dir, "sub_"))
5322 ).set_cpl_id(cpl->id()),
5323 dcp::VerificationNote(
5324 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(find_file(dir, "cpl_"))
5325 ).set_cpl_id(cpl->id()),
5326 dcp::VerificationNote(
5327 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, std::string{"315de731-1173-484c-9a35-bdacf5a9d99d"}
5328 ).set_cpl_id(cpl->id()),
5333 BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font)
5335 path const dir("build/test/verify_missing_load_font");
5336 prepare_directory (dir);
5337 copy_file ("test/data/subs1.xml", dir / "subs.xml");
5339 Editor editor(dir / "subs.xml");
5340 editor.delete_first_line_containing("LoadFont");
5342 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
5343 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
5344 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
5346 check_verify_result (
5350 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5351 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5352 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5353 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5354 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5355 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
5356 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id("theFontId").set_cpl_id(cpl->id())
5362 BOOST_AUTO_TEST_CASE(verify_missing_load_font)
5364 boost::filesystem::path const dir = "build/test/verify_missing_load_font";
5365 prepare_directory(dir);
5366 auto dcp = make_simple (dir, 1, 202);
5369 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
5370 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
5371 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
5372 "<ContentTitleText>Content</ContentTitleText>"
5373 "<AnnotationText>Annotation</AnnotationText>"
5374 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
5375 "<ReelNumber>1</ReelNumber>"
5376 "<EditRate>24 1</EditRate>"
5377 "<TimeCodeRate>24</TimeCodeRate>"
5378 "<StartTime>00:00:00:00</StartTime>"
5379 "<Language>de-DE</Language>"
5381 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
5382 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:06:00\" TimeOut=\"00:00:08:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
5383 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
5389 dcp::File xml_file(dir / "subs.xml", "w");
5390 BOOST_REQUIRE(xml_file);
5391 xml_file.write(xml.c_str(), xml.size(), 1);
5393 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
5394 subs->write(dir / "subs.mxf");
5396 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 202, 0);
5397 auto cpl = dcp->cpls()[0];
5398 cpl->reels()[0]->add(reel_subs);
5401 check_verify_result (
5405 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5406 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5407 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5408 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5409 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5410 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5411 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5412 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5413 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5414 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id(reel_subs->id()).set_cpl_id(cpl->id())
5419 BOOST_AUTO_TEST_CASE(verify_spots_wrong_asset)
5421 boost::filesystem::path const dir = "build/test/verify_spots_wrong_asset";
5422 boost::filesystem::remove_all(dir);
5424 auto dcp1 = make_simple(dir / "1");
5426 auto cpl = dcp1->cpls()[0];
5428 auto const asset_1 = dcp::MonoPictureAsset(dir / "1" / "video.mxf").id();
5430 auto dcp2 = make_simple(dir / "2");
5432 auto const asset_2 = dcp::MonoPictureAsset(dir / "2" / "video.mxf").id();
5434 boost::filesystem::remove(dir / "1" / "video.mxf");
5435 boost::filesystem::copy_file(dir / "2" / "video.mxf", dir / "1" / "video.mxf");
5437 check_verify_result(
5441 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5442 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5443 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5444 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5445 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5446 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5447 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5448 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_MAP_ID).set_id(asset_1).set_other_id(asset_2)
5453 BOOST_AUTO_TEST_CASE(verify_cpl_content_version_label_text_empty)
5455 boost::filesystem::path const dir = "build/test/verify_cpl_content_version_label_text_empty";
5456 boost::filesystem::remove_all(dir);
5458 auto dcp = make_simple(dir);
5459 BOOST_REQUIRE(dcp->cpls().size() == 1);
5460 auto cpl = dcp->cpls()[0];
5461 cpl->set_content_version(dcp::ContentVersion(""));
5464 check_verify_result(
5468 ok(dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, string{"1998x1080"}, cpl),
5469 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5470 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5471 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5472 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5473 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5474 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5475 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5476 dcp::VerificationNote(dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get()).set_cpl_id(cpl->id())
5481 /** Check that we don't get any strange errors when verifying encrypted DCPs (DoM #2659) */
5482 BOOST_AUTO_TEST_CASE(verify_encrypted_smpte_dcp)
5484 auto const dir = path("build/test/verify_encrypted_smpte_dcp");
5486 auto key_id = dcp::make_uuid();
5487 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset>(dir, {{ 4 * 24, 5 * 24 }}, key, key_id);
5489 dcp::DecryptedKDM kdm(dcp::LocalTime(), dcp::LocalTime(), "", "", "");
5490 kdm.add_key(dcp::DecryptedKDMKey(string{"MDIK"}, key_id, key, cpl->id(), dcp::Standard::SMPTE));
5492 path const pkl_file = find_file(dir, "pkl_");
5493 path const cpl_file = find_file(dir, "cpl_");
5495 check_verify_result(
5499 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5500 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5501 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5502 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5503 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5504 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
5505 dcp::VerificationNote(
5506 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_file)
5507 ).set_cpl_id(cpl->id()),
5508 dcp::VerificationNote(
5509 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_file)
5510 ).set_cpl_id(cpl->id()),
5511 dcp::VerificationNote(
5512 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, filename_to_id(pkl_file.filename()), canonical(pkl_file)