2 Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
35 #include "compose.hpp"
39 #include "interop_subtitle_asset.h"
40 #include "j2k_transcode.h"
41 #include "mono_picture_asset.h"
42 #include "mono_picture_asset_writer.h"
43 #include "openjpeg_image.h"
44 #include "raw_convert.h"
46 #include "reel_interop_closed_caption_asset.h"
47 #include "reel_interop_subtitle_asset.h"
48 #include "reel_markers_asset.h"
49 #include "reel_mono_picture_asset.h"
50 #include "reel_sound_asset.h"
51 #include "reel_stereo_picture_asset.h"
52 #include "reel_smpte_closed_caption_asset.h"
53 #include "reel_smpte_subtitle_asset.h"
54 #include "smpte_subtitle_asset.h"
55 #include "stereo_picture_asset.h"
56 #include "stream_operators.h"
60 #include "verify_j2k.h"
61 #include <boost/algorithm/string.hpp>
62 #include <boost/random.hpp>
63 #include <boost/test/unit_test.hpp>
71 using std::make_shared;
73 using std::shared_ptr;
76 using boost::optional;
77 using namespace boost::filesystem;
80 static list<pair<string, optional<path>>> stages;
82 static string filename_to_id(boost::filesystem::path path)
84 return path.string().substr(4, path.string().length() - 8);
88 boost::filesystem::path
91 return find_file("test/ref/DCP/dcp_test1", "pkl_").filename();
98 return filename_to_id(dcp_test1_pkl());
102 boost::filesystem::path
105 return find_file("test/ref/DCP/dcp_test1", "cpl_").filename();
112 return filename_to_id(dcp_test1_cpl());
115 static string const dcp_test1_asset_map_id = "017b3de4-6dda-408d-b19b-6711354b0bc3";
119 encryption_test_cpl_id()
121 return filename_to_id(find_file("test/ref/DCP/encryption_test", "cpl_").filename());
126 encryption_test_pkl_id()
128 return filename_to_id(find_file("test/ref/DCP/encryption_test", "pkl_").filename());
132 stage (string s, optional<path> p)
134 stages.push_back (make_pair (s, p));
144 prepare_directory (path path)
146 using namespace boost::filesystem;
148 create_directories (path);
154 find_prefix(path dir, string prefix)
156 auto iter = std::find_if(directory_iterator(dir), directory_iterator(), [prefix](path const& p) {
157 return boost::starts_with(p.filename().string(), prefix);
160 BOOST_REQUIRE(iter != directory_iterator());
169 return find_prefix(dir, "cpl_");
177 return find_prefix(dir, "pkl_");
183 find_asset_map(path dir)
185 return find_prefix(dir, "ASSETMAP");
189 /** Copy dcp_test{reference_number} to build/test/verify_test{verify_test_suffix}
190 * to make a new sacrificial test DCP.
193 setup (int reference_number, string verify_test_suffix)
195 auto const dir = dcp::String::compose("build/test/verify_test%1", verify_test_suffix);
196 prepare_directory (dir);
197 for (auto i: directory_iterator(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number))) {
198 copy_file (i.path(), dir / i.path().filename());
207 write_dcp_with_single_asset (path dir, shared_ptr<dcp::ReelAsset> reel_asset, dcp::Standard standard = dcp::Standard::SMPTE)
209 auto reel = make_shared<dcp::Reel>();
210 reel->add (reel_asset);
211 reel->add (simple_markers());
213 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, standard);
215 auto dcp = make_shared<dcp::DCP>(dir);
217 dcp->set_annotation_text("hello");
224 LIBDCP_DISABLE_WARNINGS
227 dump_notes (vector<dcp::VerificationNote> const & notes)
229 for (auto i: notes) {
230 std::cout << dcp::note_to_string(i) << "\n";
233 LIBDCP_ENABLE_WARNINGS
238 to_string(dcp::VerificationNote const& note)
240 string s = note_to_string(note) + dcp::String::compose(
241 "\n [%1 %2 %3 %4 %5 %6 ",
242 static_cast<int>(note.type()),
243 static_cast<int>(note.code()),
244 note.note().get_value_or("<none>"),
245 note.file().get_value_or("<none>"),
246 note.line().get_value_or(0),
247 note.frame().get_value_or(0)
250 s += dcp::String::compose(
252 note.id().get_value_or("<none>"),
253 note.other_id().get_value_or("<none>"),
254 note.cpl_id().get_value_or("<none>"),
255 note.reference_hash().get_value_or("<none>"),
256 note.calculated_hash().get_value_or("<none>")
265 check_verify_result(vector<dcp::VerificationNote> notes, vector<dcp::VerificationNote> test_notes)
267 std::sort(notes.begin(), notes.end());
268 std::sort(test_notes.begin(), test_notes.end());
270 string message = "\n";
272 vector<dcp::VerificationNote> not_expected;
273 for (auto note: notes) {
274 auto iter = std::find_if(test_notes.begin(), test_notes.end(), [note](dcp::VerificationNote const& n) { return note.type() == n.type() && note.code() == n.code(); });
275 if (iter != test_notes.end() && *iter != note) {
276 message += "Wrong details:\n --seen " + to_string(note) + " --expected " + to_string(*iter) + "\n";
277 } else if (iter == test_notes.end()) {
278 not_expected.push_back(note);
282 vector<dcp::VerificationNote> not_seen;
283 for (auto note: test_notes) {
284 auto iter = std::find_if(notes.begin(), notes.end(), [note](dcp::VerificationNote const& n) { return note.type() == n.type() && note.code() == n.code(); });
285 if (iter == notes.end()) {
286 not_seen.push_back(note);
290 for (auto note: not_expected) {
291 message += "Not expected:\n" + to_string(note) + "\n";
294 for (auto note: not_seen) {
295 message += "Not seen:\n" + to_string(note) + "\n";
298 BOOST_REQUIRE_MESSAGE(notes == test_notes, message);
304 check_verify_result(vector<path> dir, vector<dcp::DecryptedKDM> kdm, vector<dcp::VerificationNote> test_notes)
306 check_verify_result(dcp::verify({dir}, kdm, &stage, &progress, {}, xsd_test).notes, test_notes);
310 /* Copy dcp_test1 to build/test/verify_test{suffix} then edit a file found by the functor 'file',
311 * replacing from with to.
315 replace(string suffix, boost::function<path (string)> file, string from, string to)
317 auto dir = setup (1, suffix);
320 Editor e (file(suffix));
321 e.replace (from, to);
328 add_font(shared_ptr<dcp::SubtitleAsset> asset)
330 dcp::ArrayData fake_font(1024);
331 asset->add_font("font", fake_font);
338 HashCalculator(boost::filesystem::path path)
340 , _old_hash(dcp::make_digest(path, [](int64_t, int64_t) {}))
343 std::string old_hash() const {
347 std::string new_hash() const {
348 return dcp::make_digest(_path, [](int64_t, int64_t) {});
352 boost::filesystem::path _path;
353 std::string _old_hash;
358 dcp::VerificationNote
359 ok(dcp::VerificationNote::Code code, shared_ptr<const dcp::CPL> cpl)
361 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code).set_cpl_id(cpl->id());
366 dcp::VerificationNote
367 ok(dcp::VerificationNote::Code code, string note, shared_ptr<const dcp::CPL> cpl)
369 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, note).set_cpl_id(cpl->id());
374 dcp::VerificationNote
375 ok(dcp::VerificationNote::Code code, boost::filesystem::path path, shared_ptr<const dcp::CPL> cpl)
377 return dcp::VerificationNote(dcp::VerificationNote::Type::OK, code, path).set_cpl_id(cpl->id());
382 add(vector<dcp::VerificationNote>& notes, vector<dcp::VerificationNote> const& add)
390 BOOST_AUTO_TEST_CASE (verify_no_error)
393 auto dir = setup (1, "no_error");
394 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
396 path const cpl_file = dir / dcp_test1_cpl();
397 path const pkl_file = dir / dcp_test1_pkl();
398 path const assetmap_file = dir / "ASSETMAP.xml";
400 auto st = stages.begin();
401 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
402 BOOST_REQUIRE (st->second);
403 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
405 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
406 BOOST_REQUIRE (st->second);
407 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
409 BOOST_CHECK_EQUAL (st->first, "Checking reel");
410 BOOST_REQUIRE (!st->second);
412 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
413 BOOST_REQUIRE (st->second);
414 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
416 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
417 BOOST_REQUIRE (st->second);
418 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "video.mxf"));
420 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
421 BOOST_REQUIRE (st->second);
422 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
424 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
425 BOOST_REQUIRE (st->second);
426 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "audio.mxf"));
428 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
429 BOOST_REQUIRE (st->second);
430 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
431 ++st; BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
432 BOOST_REQUIRE (st->second);
433 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
435 BOOST_REQUIRE (st == stages.end());
437 for (auto note: notes) {
438 BOOST_CHECK(note.type() == dcp::VerificationNote::Type::OK);
443 BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash)
445 using namespace boost::filesystem;
447 auto dir = setup (1, "incorrect_picture_sound_hash");
448 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
450 auto video_path = path(dir / "video.mxf");
451 HashCalculator video_calc(video_path);
452 auto mod = fopen(video_path.string().c_str(), "r+b");
454 BOOST_REQUIRE_EQUAL(fseek(mod, -16, SEEK_END), 0);
456 BOOST_REQUIRE(fwrite(&x, sizeof(x), 1, mod) == 1);
459 auto audio_path = path(dir / "audio.mxf");
460 HashCalculator audio_calc(audio_path);
461 mod = fopen(audio_path.string().c_str(), "r+b");
463 BOOST_REQUIRE_EQUAL(fseek(mod, 0, SEEK_END), 0);
464 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
467 dcp::ASDCPErrorSuspender sus;
468 check_verify_result (
472 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
473 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
474 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
475 dcp::VerificationNote(
476 dcp::VerificationNote::Type::OK,
477 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
479 canonical(cpl->file().get())
480 ).set_cpl_id(dcp_test1_cpl_id()),
481 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
482 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
483 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
484 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
485 dcp::VerificationNote(
486 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path)
487 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(video_calc.old_hash()).set_calculated_hash(video_calc.new_hash()),
488 dcp::VerificationNote(
489 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path)
490 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(audio_calc.old_hash()).set_calculated_hash(audio_calc.new_hash()),
495 BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes)
497 using namespace boost::filesystem;
499 auto dir = setup (1, "mismatched_picture_sound_hashes");
500 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
502 HashCalculator calc(dir / dcp_test1_cpl());
505 Editor e (dir / dcp_test1_pkl());
506 e.replace ("<Hash>", "<Hash>x");
509 check_verify_result (
513 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
514 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
515 dcp::VerificationNote(
516 dcp::VerificationNote::Type::OK,
517 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
519 canonical(cpl->file().get())
520 ).set_cpl_id(cpl->id()),
521 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
522 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
523 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
524 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
525 dcp::VerificationNote(
526 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
527 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash("x" + calc.old_hash()).set_calculated_hash(calc.old_hash()),
528 dcp::VerificationNote(
529 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf")
530 ).set_cpl_id(dcp_test1_cpl_id()),
531 dcp::VerificationNote(
532 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf")
533 ).set_cpl_id(dcp_test1_cpl_id()),
534 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'x3M7YTgvFKXXMEGLkIbV4miC90FE=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 28 },
535 { 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 },
536 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xvsVjRV9vhTBPUWfE/TT1o2vdQsI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 20 },
541 BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind)
543 auto dir = setup (1, "failed_read_content_kind");
545 HashCalculator calc(dir / dcp_test1_cpl());
548 Editor e (dir / dcp_test1_cpl());
549 e.replace ("<ContentKind>", "<ContentKind>x");
552 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
554 check_verify_result (
558 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
559 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
560 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
561 dcp::VerificationNote(
562 dcp::VerificationNote::Type::OK,
563 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
565 canonical(cpl->file().get())
566 ).set_cpl_id(cpl->id()),
567 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
568 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
569 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
570 dcp::VerificationNote(
571 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(dir / dcp_test1_cpl())
572 ).set_cpl_id(dcp_test1_cpl_id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
573 dcp::VerificationNote(
574 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer")
575 ).set_cpl_id(dcp_test1_cpl_id())
582 dcp_test1_cpl_path(string suffix)
584 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_cpl());
590 dcp_test1_pkl_path(string suffix)
592 return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_pkl());
598 asset_map (string suffix)
600 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", suffix);
604 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_rate)
606 auto const suffix = "invalid_picture_frame_rate";
608 replace(suffix, &dcp_test1_cpl_path, "<FrameRate>24 1", "<FrameRate>99 1");
610 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
611 auto const cpl_path = find_cpl(dir);
612 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
614 std::vector<dcp::VerificationNote> expected =
616 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
617 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
618 dcp::VerificationNote(
619 dcp::VerificationNote::Type::OK,
620 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
622 canonical(cpl->file().get())
623 ).set_cpl_id(cpl->id()),
624 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
625 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
626 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
627 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
628 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
629 dcp::VerificationNote(
630 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
631 ).set_cpl_id(cpl->id()).set_calculated_hash("7n7GQ2TbxQbmHYuAR8ml7XDOep8=").set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI="),
632 dcp::VerificationNote(
633 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, string{"99/1"}
634 ).set_cpl_id(cpl->id())
637 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
641 BOOST_AUTO_TEST_CASE (verify_missing_asset)
643 auto dir = setup (1, "missing_asset");
644 remove (dir / "video.mxf");
646 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
648 check_verify_result (
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::NONE_ENCRYPTED, cpl),
655 dcp::VerificationNote(
656 dcp::VerificationNote::Type::OK,
657 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
659 canonical(cpl->file().get())
660 ).set_cpl_id(cpl->id()),
661 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
662 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
663 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
664 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_ASSET, canonical(dir) / "video.mxf" }
669 BOOST_AUTO_TEST_CASE (verify_empty_asset_path)
671 auto const suffix = "empty_asset_path";
673 replace("empty_asset_path", &asset_map, "<Path>video.mxf</Path>", "<Path></Path>");
675 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
676 auto const cpl_path = find_cpl(dir);
677 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
679 std::vector<dcp::VerificationNote> expected = {
680 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
681 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
682 dcp::VerificationNote(
683 dcp::VerificationNote::Type::OK,
684 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
686 canonical(cpl->file().get())
687 ).set_cpl_id(cpl->id()),
688 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
689 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
690 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
691 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
692 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_ASSET_PATH }
695 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
699 BOOST_AUTO_TEST_CASE (verify_mismatched_standard)
701 auto const suffix = "mismatched_standard";
703 replace(suffix, &dcp_test1_cpl_path, "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#");
705 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
706 auto const cpl_path = find_cpl(dir);
707 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
709 std::vector<dcp::VerificationNote> expected = {
710 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
711 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
712 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
713 dcp::VerificationNote(
714 dcp::VerificationNote::Type::OK,
715 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
717 canonical(cpl->file().get())
718 ).set_cpl_id(cpl->id()),
719 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
720 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
721 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
722 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
723 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_STANDARD },
724 dcp::VerificationNote(
725 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "invalid character encountered", canonical(cpl_path), 42
726 ).set_cpl_id(cpl->id()),
727 dcp::VerificationNote(
728 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'Id'", canonical(cpl_path), 53
729 ).set_cpl_id(cpl->id()),
730 dcp::VerificationNote(
731 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'EditRate'", canonical(cpl_path), 54
732 ).set_cpl_id(cpl->id()),
733 dcp::VerificationNote(
734 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "no declaration found for element 'IntrinsicDuration'", canonical(cpl_path), 55
735 ).set_cpl_id(cpl->id()),
736 dcp::VerificationNote(
737 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
738 "element 'Id' is not allowed for content model '(Id,AnnotationText?,EditRate,IntrinsicDuration,"
739 "EntryPoint?,Duration?,FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
740 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,MainSoundSampleRate,"
741 "MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,ExtensionMetadataList?,)'",
742 canonical(cpl_path), 149
743 ).set_cpl_id(cpl->id()),
744 dcp::VerificationNote(
745 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
746 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("FZ9E7L/pOuJ6aZfbiaANTv8BFOo=")
749 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
753 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_id)
755 auto const suffix = "invalid_xml_cpl_id";
757 /* There's no MISMATCHED_CPL_HASHES error here because it can't find the correct hash by ID (since the ID is wrong) */
758 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");
760 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
761 auto const cpl_path = find_cpl(dir);
762 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
764 std::vector<dcp::VerificationNote> expected = {
765 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
766 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
767 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
768 dcp::VerificationNote(
769 dcp::VerificationNote::Type::OK,
770 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
772 canonical(cpl->file().get())
773 ).set_cpl_id(cpl->id()),
774 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
775 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
776 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
777 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
778 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
779 dcp::VerificationNote(
780 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
781 "value 'urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358a' does not match regular expression "
782 "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
783 ).set_cpl_id(cpl->id())
786 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
790 BOOST_AUTO_TEST_CASE (verify_invalid_xml_issue_date)
792 auto const suffix = "invalid_xml_issue_date";
794 replace("invalid_xml_issue_date", &dcp_test1_cpl_path, "<IssueDate>", "<IssueDate>x");
796 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
797 auto const cpl_path = find_cpl(dir);
798 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
800 std::vector<dcp::VerificationNote> expected = {
801 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
802 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
803 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
804 dcp::VerificationNote(
805 dcp::VerificationNote::Type::OK,
806 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
808 canonical(cpl->file().get())
809 ).set_cpl_id(cpl->id()),
810 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
811 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
812 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
813 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
814 dcp::VerificationNote(
815 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
816 ).set_cpl_id(cpl->id()).set_reference_hash("skI+5b/9LA/y6h0mcyxysJYanxI=").set_calculated_hash("sz3BeIugJ567q3HMnA62JeRw4TE="),
817 dcp::VerificationNote(
818 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
819 "invalid character encountered",
820 canonical(cpl_path), 5
821 ).set_cpl_id(cpl->id()),
824 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
828 BOOST_AUTO_TEST_CASE (verify_invalid_xml_pkl_id)
830 auto const suffix = "invalid_xml_pkl_id";
832 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));
834 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
835 auto const pkl_path = find_pkl(dir);
836 auto const cpl_path = find_cpl(dir);
837 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
839 std::vector<dcp::VerificationNote> expected = {
840 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
841 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
842 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
843 dcp::VerificationNote(
844 dcp::VerificationNote::Type::OK,
845 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
847 canonical(cpl->file().get())
848 ).set_cpl_id(cpl->id()),
849 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
850 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
851 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
852 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
853 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
854 dcp::VerificationNote(
855 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
856 "value 'urn:uuid:x199d58b-5ef8-4d49-b270-07e590ccb280' does not match regular "
857 "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}'",
858 canonical(pkl_path), 3
862 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
866 BOOST_AUTO_TEST_CASE (verify_invalid_xml_asset_map_id)
868 auto const suffix = "invalid_xml_asset_map_id";
870 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));
872 auto const dir = dcp::String::compose("build/test/verify_test%1", suffix);
873 auto const cpl_path = find_cpl(dir);
874 auto const asset_map_path = find_asset_map(dir);
875 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
877 std::vector<dcp::VerificationNote> expected = {
878 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
879 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
880 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
881 dcp::VerificationNote(
882 dcp::VerificationNote::Type::OK,
883 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
885 canonical(cpl->file().get())
886 ).set_cpl_id(cpl->id()),
887 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
888 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
889 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
890 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
891 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
892 dcp::VerificationNote(
893 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML,
894 "value 'urn:uuid:x17b3de4-6dda-408d-b19b-6711354b0bc3' does not match regular "
895 "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}'",
896 canonical(asset_map_path), 3
900 check_verify_result(dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes, expected);
904 BOOST_AUTO_TEST_CASE (verify_invalid_standard)
907 auto dir = setup (3, "verify_invalid_standard");
908 auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test).notes;
910 path const cpl_file = dir / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
911 path const pkl_file = dir / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
912 path const assetmap_file = dir / "ASSETMAP";
913 auto cpl = std::make_shared<dcp::CPL>(cpl_file);
915 auto st = stages.begin();
916 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
917 BOOST_REQUIRE (st->second);
918 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir));
920 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
921 BOOST_REQUIRE (st->second);
922 BOOST_CHECK_EQUAL (st->second.get(), canonical(cpl_file));
924 BOOST_CHECK_EQUAL (st->first, "Checking reel");
925 BOOST_REQUIRE (!st->second);
927 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
928 BOOST_REQUIRE (st->second);
929 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
931 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
932 BOOST_REQUIRE (st->second);
933 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
935 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
936 BOOST_REQUIRE (st->second);
937 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
939 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
940 BOOST_REQUIRE (st->second);
941 BOOST_CHECK_EQUAL (st->second.get(), canonical(dir / "pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
943 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
944 BOOST_REQUIRE (st->second);
945 BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file));
947 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
948 BOOST_REQUIRE (st->second);
949 BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file));
951 BOOST_REQUIRE (st == stages.end());
953 vector<dcp::VerificationNote> expected = {
954 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
955 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
956 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
957 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
958 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
959 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
960 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl),
961 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"), cpl)
964 for (int j = 0; j < 24; ++j) {
966 dcp::VerificationNote(
967 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
968 ).set_cpl_id(cpl->id())
972 check_verify_result(notes, expected);
975 /* DCP with a short asset */
976 BOOST_AUTO_TEST_CASE (verify_invalid_duration)
978 auto dir = setup (8, "invalid_duration");
982 BOOST_REQUIRE(dcp.cpls().size() == 1);
983 auto cpl = dcp.cpls()[0];
985 vector<dcp::VerificationNote> expected = {
986 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
987 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
988 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
989 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
990 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
991 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_d7576dcb-a361-4139-96b8-267f5f8d7f91.mxf"), cpl),
992 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
993 dcp::VerificationNote(
994 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
995 ).set_cpl_id(cpl->id()),
996 dcp::VerificationNote(
997 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91")
998 ).set_cpl_id(cpl->id()),
999 dcp::VerificationNote(
1000 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
1001 ).set_cpl_id(cpl->id()),
1002 dcp::VerificationNote(
1003 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626")
1004 ).set_cpl_id(cpl->id()),
1005 dcp::VerificationNote(
1006 dcp::VerificationNote::Type::WARNING,
1007 dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT,
1009 ).set_cpl_id(cpl->id())
1012 for (int i = 0; i < 23; ++i) {
1014 dcp::VerificationNote(
1015 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2")
1016 ).set_cpl_id(cpl->id())
1020 check_verify_result({ dir }, {}, expected);
1025 shared_ptr<dcp::CPL>
1026 dcp_from_frame (dcp::ArrayData const& frame, path dir)
1028 auto asset = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
1029 create_directories (dir);
1030 auto writer = asset->start_write(dir / "pic.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
1031 for (int i = 0; i < 24; ++i) {
1032 writer->write (frame.data(), frame.size());
1034 writer->finalize ();
1036 auto reel_asset = make_shared<dcp::ReelMonoPictureAsset>(asset, 0);
1037 return write_dcp_with_single_asset (dir, reel_asset);
1041 BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_size_in_bytes)
1043 int const too_big = 1302083 * 2;
1045 /* Compress a black image */
1046 auto image = black_image ();
1047 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1048 BOOST_REQUIRE (frame.size() < too_big);
1050 /* Place it in a bigger block with some zero padding at the end */
1051 dcp::ArrayData oversized_frame(too_big);
1052 memcpy (oversized_frame.data(), frame.data(), frame.size());
1053 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
1055 path const dir("build/test/verify_invalid_picture_frame_size_in_bytes");
1056 prepare_directory (dir);
1057 auto cpl = dcp_from_frame (oversized_frame, dir);
1059 vector<dcp::VerificationNote> expected = {
1060 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1061 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1062 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1063 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1064 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1065 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1066 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1069 for (auto i = 0; i < 24; ++i) {
1071 dcp::VerificationNote(
1072 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1073 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1077 for (auto i = 0; i < 24; ++i) {
1079 dcp::VerificationNote(
1080 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1081 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1086 dcp::VerificationNote(
1087 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1088 ).set_cpl_id(cpl->id())
1091 check_verify_result({ dir }, {}, expected);
1095 BOOST_AUTO_TEST_CASE (verify_nearly_invalid_picture_frame_size_in_bytes)
1097 int const nearly_too_big = 1302083 * 0.98;
1099 /* Compress a black image */
1100 auto image = black_image ();
1101 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1102 BOOST_REQUIRE (frame.size() < nearly_too_big);
1104 /* Place it in a bigger block with some zero padding at the end */
1105 dcp::ArrayData oversized_frame(nearly_too_big);
1106 memcpy (oversized_frame.data(), frame.data(), frame.size());
1107 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
1109 path const dir("build/test/verify_nearly_invalid_picture_frame_size_in_bytes");
1110 prepare_directory (dir);
1111 auto cpl = dcp_from_frame (oversized_frame, dir);
1113 vector<dcp::VerificationNote> expected = {
1114 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1115 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1116 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1117 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1118 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1119 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1120 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1123 for (auto i = 0; i < 24; ++i) {
1125 dcp::VerificationNote(
1126 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte")
1127 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1131 for (auto i = 0; i < 24; ++i) {
1133 dcp::VerificationNote(
1134 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf")
1135 ).set_frame(i).set_frame_rate(24).set_cpl_id(cpl->id())
1140 dcp::VerificationNote(
1141 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1142 ).set_cpl_id(cpl->id())
1145 check_verify_result ({ dir }, {}, expected);
1149 BOOST_AUTO_TEST_CASE (verify_valid_picture_frame_size_in_bytes)
1151 /* Compress a black image */
1152 auto image = black_image ();
1153 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1154 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1156 path const dir("build/test/verify_valid_picture_frame_size_in_bytes");
1157 prepare_directory (dir);
1158 auto cpl = dcp_from_frame (frame, dir);
1160 check_verify_result(
1164 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1165 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1166 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1167 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1168 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1169 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1170 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1171 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1172 dcp::VerificationNote(dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()).set_cpl_id(cpl->id())
1177 BOOST_AUTO_TEST_CASE (verify_valid_interop_subtitles)
1179 path const dir("build/test/verify_valid_interop_subtitles");
1180 prepare_directory (dir);
1181 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1182 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1183 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1184 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1186 check_verify_result (
1190 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1191 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1192 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1193 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1194 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1195 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1196 dcp::VerificationNote(
1197 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1198 ).set_cpl_id(cpl->id())
1203 BOOST_AUTO_TEST_CASE(verify_catch_missing_font_file_with_interop_ccap)
1205 path const dir("build/test/verify_catch_missing_font_file_with_interop_ccap");
1206 prepare_directory(dir);
1207 copy_file("test/data/subs1.xml", dir / "ccap.xml");
1208 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "ccap.xml");
1209 auto reel_asset = make_shared<dcp::ReelInteropClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1210 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1212 check_verify_result (
1216 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1217 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1218 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1219 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1220 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1221 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1222 dcp::VerificationNote(
1223 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1224 ).set_cpl_id(cpl->id())
1229 BOOST_AUTO_TEST_CASE (verify_invalid_interop_subtitles)
1231 using namespace boost::filesystem;
1233 path const dir("build/test/verify_invalid_interop_subtitles");
1234 prepare_directory (dir);
1235 copy_file ("test/data/subs1.xml", dir / "subs.xml");
1236 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1237 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1238 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1241 Editor e (dir / "subs.xml");
1242 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
1245 check_verify_result (
1249 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1250 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1251 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1252 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1253 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1254 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1255 dcp::VerificationNote(
1256 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 5
1257 ).set_cpl_id(cpl->id()),
1258 dcp::VerificationNote(
1259 dcp::VerificationNote::Type::ERROR,
1260 dcp::VerificationNote::Code::INVALID_XML,
1261 string("element 'Foo' is not allowed for content model '(SubtitleID,MovieTitle,ReelNumber,Language,LoadFont*,Font*,Subtitle*)'"),
1264 ).set_cpl_id(cpl->id()),
1265 dcp::VerificationNote(
1266 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1267 ).set_cpl_id(cpl->id())
1272 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_no_subtitles)
1274 path const dir("build/test/verify_interop_subtitle_asset_with_no_subtitles");
1275 prepare_directory(dir);
1276 copy_file("test/data/subs4.xml", dir / "subs.xml");
1277 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1278 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1279 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1281 check_verify_result (
1285 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1286 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1287 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1288 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1289 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1290 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1291 dcp::VerificationNote(
1292 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1293 ).set_cpl_id(cpl->id()),
1294 dcp::VerificationNote(
1295 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"}
1296 ).set_cpl_id(cpl->id())
1302 BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_single_space_subtitle)
1304 path const dir("build/test/verify_interop_subtitle_asset_with_single_space_subtitle");
1305 prepare_directory(dir);
1306 copy_file("test/data/subs5.xml", dir / "subs.xml");
1307 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1308 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1309 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
1311 check_verify_result (
1315 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1316 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1317 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1318 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1319 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1320 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1321 dcp::VerificationNote(
1322 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"Arial"}
1323 ).set_cpl_id(cpl->id())
1329 BOOST_AUTO_TEST_CASE (verify_valid_smpte_subtitles)
1331 path const dir("build/test/verify_valid_smpte_subtitles");
1332 prepare_directory (dir);
1333 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1334 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1335 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1336 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1338 check_verify_result(
1342 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1343 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1344 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1345 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1346 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1347 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1348 dcp::VerificationNote(
1349 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1350 ).set_cpl_id(cpl->id()),
1351 dcp::VerificationNote(
1352 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-04-14T13:19:14.000+02:00"}
1353 ).set_cpl_id(cpl->id()),
1354 dcp::VerificationNote(
1355 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1356 ).set_cpl_id(cpl->id()),
1361 BOOST_AUTO_TEST_CASE (verify_invalid_smpte_subtitles)
1363 using namespace boost::filesystem;
1365 path const dir("build/test/verify_invalid_smpte_subtitles");
1366 prepare_directory (dir);
1367 /* This broken_smpte.mxf does not use urn:uuid: for its subtitle ID, which we tolerate (rightly or wrongly) */
1368 copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
1369 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1370 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1371 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1373 check_verify_result (
1377 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1378 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1379 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1380 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1381 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1382 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1383 dcp::VerificationNote(
1384 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 2
1385 ).set_cpl_id(cpl->id()),
1386 dcp::VerificationNote(
1387 dcp::VerificationNote::Type::ERROR,
1388 dcp::VerificationNote::Code::INVALID_XML,
1389 string("element 'Foo' is not allowed for content model '(Id,ContentTitleText,AnnotationText?,IssueDate,ReelNumber?,Language?,EditRate,TimeCodeRate,StartTime?,DisplayType?,LoadFont*,SubtitleList)'"),
1392 ).set_cpl_id(cpl->id()),
1393 dcp::VerificationNote(
1394 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
1395 ).set_cpl_id(cpl->id()),
1396 dcp::VerificationNote(
1397 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1398 ).set_cpl_id(cpl->id()),
1399 dcp::VerificationNote(
1400 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2020-05-09T00:29:21.000+02:00"}
1401 ).set_cpl_id(cpl->id()),
1402 dcp::VerificationNote(
1403 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1404 ).set_cpl_id(cpl->id()),
1409 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles)
1411 path const dir("build/test/verify_empty_text_node_in_subtitles");
1412 prepare_directory (dir);
1413 copy_file ("test/data/empty_text.mxf", dir / "subs.mxf");
1414 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1415 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1416 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1418 check_verify_result (
1422 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1423 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1424 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1425 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1426 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1427 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1428 dcp::VerificationNote(
1429 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1430 ).set_cpl_id(cpl->id()),
1431 dcp::VerificationNote(
1432 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
1433 ).set_cpl_id(cpl->id()),
1434 dcp::VerificationNote(
1435 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
1436 ).set_cpl_id(cpl->id()),
1437 dcp::VerificationNote(
1438 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1439 ).set_cpl_id(cpl->id()),
1440 dcp::VerificationNote(
1441 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-08-09T18:34:46.000+02:00"}
1442 ).set_cpl_id(cpl->id()),
1443 dcp::VerificationNote(
1444 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()
1445 ).set_cpl_id(cpl->id())
1450 /** A <Text> node with no content except some <Font> nodes, which themselves do have content */
1451 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_child_nodes)
1453 path const dir("build/test/verify_empty_text_node_in_subtitles_with_child_nodes");
1454 prepare_directory (dir);
1455 copy_file ("test/data/empty_but_with_children.xml", dir / "subs.xml");
1456 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1457 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1458 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1460 check_verify_result (
1464 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1465 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1466 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1467 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1468 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1469 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1470 dcp::VerificationNote(
1471 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1472 ).set_cpl_id(cpl->id())
1477 /** A <Text> node with no content except some <Font> nodes, which themselves also have no content */
1478 BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_empty_child_nodes)
1480 path const dir("build/test/verify_empty_text_node_in_subtitles_with_empty_child_nodes");
1481 prepare_directory (dir);
1482 copy_file ("test/data/empty_with_empty_children.xml", dir / "subs.xml");
1483 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
1484 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 192, 0);
1485 auto cpl = write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP);
1487 check_verify_result (
1491 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1492 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1493 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1494 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1495 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1496 dcp::VerificationNote(
1497 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get())
1498 ).set_cpl_id(cpl->id()),
1499 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
1500 dcp::VerificationNote(
1501 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT
1502 ).set_cpl_id(cpl->id()),
1503 dcp::VerificationNote(
1504 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"}
1505 ).set_cpl_id(cpl->id())
1510 BOOST_AUTO_TEST_CASE (verify_external_asset)
1512 path const ov_dir("build/test/verify_external_asset");
1513 prepare_directory (ov_dir);
1515 auto image = black_image ();
1516 auto frame = dcp::compress_j2k (image, 100000000, 24, false, false);
1517 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
1518 dcp_from_frame (frame, ov_dir);
1520 dcp::DCP ov (ov_dir);
1523 path const vf_dir("build/test/verify_external_asset_vf");
1524 prepare_directory (vf_dir);
1526 auto picture = ov.cpls()[0]->reels()[0]->main_picture();
1527 auto cpl = write_dcp_with_single_asset (vf_dir, picture);
1529 check_verify_result (
1533 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1534 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1535 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1536 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1537 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1538 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1539 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, picture->asset()->id() },
1540 dcp::VerificationNote(
1541 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1542 ).set_cpl_id(cpl->id())
1547 BOOST_AUTO_TEST_CASE (verify_valid_cpl_metadata)
1549 path const dir("build/test/verify_valid_cpl_metadata");
1550 prepare_directory (dir);
1552 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1553 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1554 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
1556 auto reel = make_shared<dcp::Reel>();
1557 reel->add (reel_asset);
1559 reel->add (make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 16 * 24), 0));
1560 reel->add (simple_markers(16 * 24));
1562 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1564 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1565 cpl->set_main_sound_sample_rate (48000);
1566 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1567 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1568 cpl->set_version_number (1);
1572 dcp.set_annotation_text("hello");
1577 /* DCP with invalid CompositionMetadataAsset */
1578 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag)
1580 using namespace boost::filesystem;
1582 path const dir("build/test/verify_invalid_cpl_metadata_bad_tag");
1583 prepare_directory (dir);
1585 auto reel = make_shared<dcp::Reel>();
1586 reel->add (black_picture_asset(dir));
1587 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1589 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1590 cpl->set_main_sound_sample_rate (48000);
1591 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1592 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1593 cpl->set_version_number (1);
1595 reel->add (simple_markers());
1599 dcp.set_annotation_text("hello");
1602 HashCalculator calc(find_cpl(dir));
1605 Editor e (find_cpl(dir));
1606 e.replace ("MainSound", "MainSoundX");
1609 check_verify_result (
1613 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "pic.mxf"), cpl),
1614 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1615 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1616 dcp::VerificationNote(
1617 dcp::VerificationNote::Type::OK,
1618 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1619 string{"1440x1080"},
1621 ).set_cpl_id(cpl->id()),
1622 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1623 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1624 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1625 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "pic.mxf"), cpl),
1626 dcp::VerificationNote(
1627 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXConfiguration'"), canonical(cpl->file().get()), 50
1628 ).set_cpl_id(cpl->id()),
1629 dcp::VerificationNote(
1630 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXSampleRate'"), canonical(cpl->file().get()), 51
1631 ).set_cpl_id(cpl->id()),
1632 dcp::VerificationNote(
1633 dcp::VerificationNote::Type::ERROR,
1634 dcp::VerificationNote::Code::INVALID_XML,
1635 string("element 'meta:MainSoundXConfiguration' is not allowed for content model "
1636 "'(Id,AnnotationText?,EditRate,IntrinsicDuration,EntryPoint?,Duration?,"
1637 "FullContentTitleText,ReleaseTerritory?,VersionNumber?,Chain?,Distributor?,"
1638 "Facility?,AlternateContentVersionList?,Luminance?,MainSoundConfiguration,"
1639 "MainSoundSampleRate,MainPictureStoredArea,MainPictureActiveArea,MainSubtitleLanguageList?,"
1640 "ExtensionMetadataList?,)'"),
1641 canonical(cpl->file().get()),
1642 71).set_cpl_id(cpl->id()),
1643 dcp::VerificationNote(
1644 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
1645 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
1650 /* DCP with invalid CompositionMetadataAsset */
1651 BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag)
1653 path const dir("build/test/verify_invalid_cpl_metadata_missing_tag");
1654 prepare_directory (dir);
1656 auto reel = make_shared<dcp::Reel>();
1657 reel->add (black_picture_asset(dir));
1658 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1660 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1661 cpl->set_main_sound_sample_rate (48000);
1662 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1663 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1667 dcp.set_annotation_text("hello");
1671 Editor e (find_cpl(dir));
1672 e.replace ("meta:Width", "meta:WidthX");
1675 check_verify_result (
1678 {{ dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::FAILED_READ, string("missing XML tag Width in MainPictureStoredArea") }}
1683 BOOST_AUTO_TEST_CASE (verify_invalid_language1)
1685 path const dir("build/test/verify_invalid_language1");
1686 prepare_directory (dir);
1687 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1688 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1689 asset->_language = "wrong-andbad";
1690 asset->write (dir / "subs.mxf");
1691 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1692 reel_asset->_language = "badlang";
1693 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1695 check_verify_result (
1699 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1700 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1701 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1702 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1703 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1704 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1705 dcp::VerificationNote(
1706 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang")
1707 ).set_cpl_id(cpl->id()),
1708 dcp::VerificationNote(
1709 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad")
1710 ).set_cpl_id(cpl->id()),
1711 dcp::VerificationNote(
1712 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1713 ).set_cpl_id(cpl->id())
1718 /* SMPTE DCP with invalid <Language> in the MainClosedCaption reel and also in the XML within the MXF */
1719 BOOST_AUTO_TEST_CASE (verify_invalid_language2)
1721 path const dir("build/test/verify_invalid_language2");
1722 prepare_directory (dir);
1723 copy_file ("test/data/subs.mxf", dir / "subs.mxf");
1724 auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
1725 asset->_language = "wrong-andbad";
1726 asset->write (dir / "subs.mxf");
1727 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
1728 reel_asset->_language = "badlang";
1729 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
1731 check_verify_result (
1735 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1736 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1737 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1738 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1739 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1740 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1741 dcp::VerificationNote(
1742 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang")
1743 ).set_cpl_id(cpl->id()),
1744 dcp::VerificationNote(
1745 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad")
1746 ).set_cpl_id(cpl->id()),
1747 dcp::VerificationNote(
1748 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
1749 ).set_cpl_id(cpl->id())
1754 /* SMPTE DCP with invalid <Language> in the MainSound reel, the CPL additional subtitles languages and
1755 * the release territory.
1757 BOOST_AUTO_TEST_CASE (verify_invalid_language3)
1759 path const dir("build/test/verify_invalid_language3");
1760 prepare_directory (dir);
1762 auto picture = simple_picture (dir, "foo");
1763 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
1764 auto reel = make_shared<dcp::Reel>();
1765 reel->add (reel_picture);
1766 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "frobozz");
1767 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
1768 reel->add (reel_sound);
1769 reel->add (simple_markers());
1771 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1773 cpl->_additional_subtitle_languages.push_back("this-is-wrong");
1774 cpl->_additional_subtitle_languages.push_back("andso-is-this");
1775 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1776 cpl->set_main_sound_sample_rate (48000);
1777 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
1778 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
1779 cpl->set_version_number (1);
1780 cpl->_release_territory = "fred-jim";
1781 auto dcp = make_shared<dcp::DCP>(dir);
1783 dcp->set_annotation_text("hello");
1786 check_verify_result (
1790 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
1791 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1792 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1793 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1794 dcp::VerificationNote(
1795 dcp::VerificationNote::Type::OK,
1796 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1797 string{"1440x1080"},
1799 ).set_cpl_id(cpl->id()),
1800 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1801 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1802 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
1803 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
1804 dcp::VerificationNote(
1805 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("this-is-wrong")
1806 ).set_cpl_id(cpl->id()),
1807 dcp::VerificationNote(
1808 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("andso-is-this")
1809 ).set_cpl_id(cpl->id()),
1810 dcp::VerificationNote(
1811 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("fred-jim")
1812 ).set_cpl_id(cpl->id()),
1813 dcp::VerificationNote(
1814 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("frobozz")
1815 ).set_cpl_id(cpl->id()),
1821 std::tuple<vector<dcp::VerificationNote>, shared_ptr<dcp::CPL>, boost::filesystem::path>
1822 check_picture_size (int width, int height, int frame_rate, bool three_d)
1824 using namespace boost::filesystem;
1826 path dcp_path = "build/test/verify_picture_test";
1827 prepare_directory (dcp_path);
1829 shared_ptr<dcp::PictureAsset> mp;
1831 mp = make_shared<dcp::StereoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1833 mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(frame_rate, 1), dcp::Standard::SMPTE);
1835 auto picture_writer = mp->start_write(dcp_path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
1837 auto image = black_image (dcp::Size(width, height));
1838 auto j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048);
1839 int const length = three_d ? frame_rate * 2 : frame_rate;
1840 for (int i = 0; i < length; ++i) {
1841 picture_writer->write (j2c.data(), j2c.size());
1843 picture_writer->finalize ();
1845 auto d = make_shared<dcp::DCP>(dcp_path);
1846 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
1847 cpl->set_annotation_text ("A Test DCP");
1848 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
1849 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
1850 cpl->set_main_sound_sample_rate (48000);
1851 cpl->set_main_picture_stored_area(dcp::Size(width, height));
1852 cpl->set_main_picture_active_area(dcp::Size(width, height));
1853 cpl->set_version_number (1);
1855 auto reel = make_shared<dcp::Reel>();
1858 reel->add (make_shared<dcp::ReelStereoPictureAsset>(std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp), 0));
1860 reel->add (make_shared<dcp::ReelMonoPictureAsset>(std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp), 0));
1863 reel->add (simple_markers(frame_rate));
1868 d->set_annotation_text("A Test DCP");
1871 /* It seems that for the Ubuntu 16.04 compiler we can't use an initializer list here */
1872 return std::tuple<vector<dcp::VerificationNote>, shared_ptr<dcp::CPL>, boost::filesystem::path>{ dcp::verify({dcp_path}, {}, &stage, &progress, {}, xsd_test).notes, cpl, dcp_path };
1878 check_picture_size_ok (int width, int height, int frame_rate, bool three_d)
1880 vector<dcp::VerificationNote> notes;
1881 shared_ptr<dcp::CPL> cpl;
1882 boost::filesystem::path dir;
1883 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1885 std::vector<dcp::VerificationNote> expected = {
1886 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1887 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1888 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1889 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1890 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1891 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1892 dcp::VerificationNote(
1893 dcp::VerificationNote::Type::OK,
1894 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1895 dcp::String::compose("%1x%2", width, height),
1897 ).set_cpl_id(cpl->id()),
1898 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1899 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl)
1901 check_verify_result(notes, expected);
1907 check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d)
1909 vector<dcp::VerificationNote> notes;
1910 shared_ptr<dcp::CPL> cpl;
1911 boost::filesystem::path dir;
1912 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1914 std::vector<dcp::VerificationNote> expected = {
1915 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1916 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1917 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1918 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1919 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1920 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1921 dcp::VerificationNote(
1922 dcp::VerificationNote::Type::OK,
1923 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1924 dcp::String::compose("%1x%2", width, height),
1926 ).set_cpl_id(cpl->id()),
1927 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1928 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1929 dcp::VerificationNote(
1930 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS, dcp::String::compose("%1x%2", width, height), canonical(dir / "video.mxf")
1931 ).set_cpl_id(cpl->id())
1933 check_verify_result(notes, expected);
1939 check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d)
1941 vector<dcp::VerificationNote> notes;
1942 shared_ptr<dcp::CPL> cpl;
1943 boost::filesystem::path dir;
1944 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1946 std::vector<dcp::VerificationNote> expected = {
1947 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1948 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1949 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1950 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1951 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1952 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1953 dcp::VerificationNote(
1954 dcp::VerificationNote::Type::OK,
1955 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1956 dcp::String::compose("%1x%2", width, height),
1958 ).set_cpl_id(cpl->id()),
1959 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1960 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1961 dcp::VerificationNote(
1962 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, dcp::String::compose("%1/1", frame_rate * (three_d ? 2 : 1))
1963 ).set_cpl_id(cpl->id()),
1964 dcp::VerificationNote(
1965 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")
1966 ).set_cpl_id(cpl->id())
1969 check_verify_result(notes, expected);
1975 check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d)
1977 vector<dcp::VerificationNote> notes;
1978 shared_ptr<dcp::CPL> cpl;
1979 boost::filesystem::path dir;
1980 std::tie(notes, cpl, dir) = check_picture_size(width, height, frame_rate, three_d);
1982 std::vector<dcp::VerificationNote> expected = {
1983 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
1984 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
1985 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
1986 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
1987 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
1988 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
1989 dcp::VerificationNote(
1990 dcp::VerificationNote::Type::OK,
1991 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
1992 dcp::String::compose("%1x%2", width, height),
1994 ).set_cpl_id(cpl->id()),
1995 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
1996 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
1997 dcp::VerificationNote(
1998 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")
1999 ).set_cpl_id(cpl->id())
2002 check_verify_result(notes, expected);
2006 BOOST_AUTO_TEST_CASE (verify_picture_size)
2008 using namespace boost::filesystem;
2011 check_picture_size_ok (2048, 858, 24, false);
2012 check_picture_size_ok (2048, 858, 25, false);
2013 check_picture_size_ok (2048, 858, 48, false);
2014 check_picture_size_ok (2048, 858, 24, true);
2015 check_picture_size_ok (2048, 858, 25, true);
2016 check_picture_size_ok (2048, 858, 48, true);
2019 check_picture_size_ok (1998, 1080, 24, false);
2020 check_picture_size_ok (1998, 1080, 25, false);
2021 check_picture_size_ok (1998, 1080, 48, false);
2022 check_picture_size_ok (1998, 1080, 24, true);
2023 check_picture_size_ok (1998, 1080, 25, true);
2024 check_picture_size_ok (1998, 1080, 48, true);
2027 check_picture_size_ok (4096, 1716, 24, false);
2030 check_picture_size_ok (3996, 2160, 24, false);
2032 /* Bad frame size */
2033 check_picture_size_bad_frame_size (2050, 858, 24, false);
2034 check_picture_size_bad_frame_size (2048, 658, 25, false);
2035 check_picture_size_bad_frame_size (1920, 1080, 48, true);
2036 check_picture_size_bad_frame_size (4000, 2000, 24, true);
2038 /* Bad 2K frame rate */
2039 check_picture_size_bad_2k_frame_rate (2048, 858, 26, false);
2040 check_picture_size_bad_2k_frame_rate (2048, 858, 31, false);
2041 check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true);
2043 /* Bad 4K frame rate */
2044 check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false);
2045 check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false);
2048 vector<dcp::VerificationNote> notes;
2049 shared_ptr<dcp::CPL> cpl;
2050 boost::filesystem::path dir;
2051 std::tie(notes, cpl, dir) = check_picture_size(3996, 2160, 24, true);
2053 std::vector<dcp::VerificationNote> expected = {
2054 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2055 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2056 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2057 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2058 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2059 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2060 dcp::VerificationNote(
2061 dcp::VerificationNote::Type::OK,
2062 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2063 string{"3996x2160"},
2065 ).set_cpl_id(cpl->id()),
2066 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2067 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2068 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D },
2075 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")
2078 std::make_shared<dcp::SubtitleString>(
2086 dcp::Time(start_frame, 24, 24),
2087 dcp::Time(end_frame, 24, 24),
2089 dcp::HAlign::CENTER,
2093 dcp::Direction::LTR,
2100 std::vector<dcp::Ruby>()
2106 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
2108 path const dir("build/test/verify_invalid_closed_caption_xml_size_in_bytes");
2109 prepare_directory (dir);
2111 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2112 for (int i = 0; i < 2048; ++i) {
2113 add_test_subtitle (asset, i * 24, i * 24 + 20);
2116 asset->set_language (dcp::LanguageTag("de-DE"));
2117 asset->write (dir / "subs.mxf");
2118 auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
2119 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2121 check_verify_result (
2125 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2126 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2127 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2128 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2129 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2130 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2131 dcp::VerificationNote(
2132 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2133 ).set_cpl_id(cpl->id()),
2134 dcp::VerificationNote(
2135 dcp::VerificationNote::Type::BV21_ERROR,
2136 dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES,
2138 canonical(dir / "subs.mxf")
2139 ).set_cpl_id(cpl->id()),
2140 dcp::VerificationNote(
2141 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2142 ).set_cpl_id(cpl->id()),
2143 dcp::VerificationNote(
2144 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2145 ).set_cpl_id(cpl->id())
2151 shared_ptr<dcp::SMPTESubtitleAsset>
2152 make_large_subtitle_asset (path font_file)
2154 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2155 dcp::ArrayData big_fake_font(1024 * 1024);
2156 big_fake_font.write (font_file);
2157 for (int i = 0; i < 116; ++i) {
2158 asset->add_font (dcp::String::compose("big%1", i), big_fake_font);
2166 verify_timed_text_asset_too_large (string name)
2168 auto const dir = path("build/test") / name;
2169 prepare_directory (dir);
2170 auto asset = make_large_subtitle_asset (dir / "font.ttf");
2171 add_test_subtitle (asset, 0, 240);
2172 asset->set_language (dcp::LanguageTag("de-DE"));
2173 asset->write (dir / "subs.mxf");
2175 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), 240, 0);
2176 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2178 check_verify_result (
2182 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2183 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2184 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2185 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2186 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2187 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2188 dcp::VerificationNote(
2189 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, string("121698284"), canonical(dir / "subs.mxf")
2190 ).set_cpl_id(cpl->id()),
2191 dcp::VerificationNote(
2192 dcp::VerificationNote::Type::BV21_ERROR,
2193 dcp::VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES,
2194 dcp::raw_convert<string>(121634816),
2195 canonical(dir / "subs.mxf")
2196 ).set_cpl_id(cpl->id()),
2197 dcp::VerificationNote(
2198 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2199 ).set_cpl_id(cpl->id()),
2200 dcp::VerificationNote(
2201 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2202 ).set_cpl_id(cpl->id()),
2203 dcp::VerificationNote(
2204 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2205 ).set_cpl_id(cpl->id())
2210 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
2212 verify_timed_text_asset_too_large<dcp::ReelSMPTESubtitleAsset>("verify_subtitle_asset_too_large");
2213 verify_timed_text_asset_too_large<dcp::ReelSMPTEClosedCaptionAsset>("verify_closed_caption_asset_too_large");
2217 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language)
2219 path dir = "build/test/verify_missing_subtitle_language";
2220 prepare_directory (dir);
2221 auto dcp = make_simple (dir, 1, 106);
2224 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2225 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2226 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2227 "<ContentTitleText>Content</ContentTitleText>"
2228 "<AnnotationText>Annotation</AnnotationText>"
2229 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2230 "<ReelNumber>1</ReelNumber>"
2231 "<EditRate>24 1</EditRate>"
2232 "<TimeCodeRate>24</TimeCodeRate>"
2233 "<StartTime>00:00:00:00</StartTime>"
2234 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2236 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2237 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2238 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2244 dcp::File xml_file(dir / "subs.xml", "w");
2245 BOOST_REQUIRE (xml_file);
2246 xml_file.write(xml.c_str(), xml.size(), 1);
2248 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2249 subs->write (dir / "subs.mxf");
2251 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2252 auto cpl = dcp->cpls()[0];
2253 cpl->reels()[0]->add(reel_subs);
2256 check_verify_result (
2260 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2261 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2262 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2263 dcp::VerificationNote(
2264 dcp::VerificationNote::Type::OK,
2265 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2266 string{"1998x1080"},
2268 ).set_cpl_id(cpl->id()),
2269 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2270 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2271 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2272 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2273 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2274 dcp::VerificationNote(
2275 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf")
2276 ).set_cpl_id(cpl->id()),
2277 dcp::VerificationNote(
2278 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2279 ).set_cpl_id(cpl->id())
2284 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
2286 path path ("build/test/verify_mismatched_subtitle_languages");
2287 auto constexpr reel_length = 192;
2288 auto dcp = make_simple (path, 2, reel_length);
2289 auto cpl = dcp->cpls()[0];
2292 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2293 subs->set_language (dcp::LanguageTag("de-DE"));
2294 subs->add (simple_subtitle());
2296 subs->write (path / "subs1.mxf");
2297 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2298 cpl->reels()[0]->add(reel_subs);
2302 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
2303 subs->set_language (dcp::LanguageTag("en-US"));
2304 subs->add (simple_subtitle());
2306 subs->write (path / "subs2.mxf");
2307 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
2308 cpl->reels()[1]->add(reel_subs);
2313 check_verify_result (
2317 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2318 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2319 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2320 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2321 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2322 dcp::VerificationNote(
2323 dcp::VerificationNote::Type::OK,
2324 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2325 string{"1998x1080"},
2327 ).set_cpl_id(cpl->id()),
2328 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2329 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2330 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2331 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2332 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2333 dcp::VerificationNote(
2334 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2335 ).set_cpl_id(cpl->id()),
2336 dcp::VerificationNote(
2337 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2338 ).set_cpl_id(cpl->id()),
2339 dcp::VerificationNote(
2340 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES
2341 ).set_cpl_id(cpl->id()),
2346 BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
2348 path path ("build/test/verify_multiple_closed_caption_languages_allowed");
2349 auto constexpr reel_length = 192;
2350 auto dcp = make_simple (path, 2, reel_length);
2351 auto cpl = dcp->cpls()[0];
2354 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2355 ccaps->set_language (dcp::LanguageTag("de-DE"));
2356 ccaps->add (simple_subtitle());
2358 ccaps->write (path / "subs1.mxf");
2359 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2360 cpl->reels()[0]->add(reel_ccaps);
2364 auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
2365 ccaps->set_language (dcp::LanguageTag("en-US"));
2366 ccaps->add (simple_subtitle());
2368 ccaps->write (path / "subs2.mxf");
2369 auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
2370 cpl->reels()[1]->add(reel_ccaps);
2375 check_verify_result (
2379 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2380 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2381 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2382 dcp::VerificationNote(
2383 dcp::VerificationNote::Type::OK,
2384 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2385 string{"1998x1080"},
2387 ).set_cpl_id(cpl->id()),
2388 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2389 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2390 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2391 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video0.mxf"), cpl),
2392 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
2393 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video0.mxf"), cpl),
2394 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
2395 dcp::VerificationNote(
2396 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf")
2397 ).set_cpl_id(cpl->id()),
2398 dcp::VerificationNote(
2399 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf")
2400 ).set_cpl_id(cpl->id())
2405 BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time)
2407 path dir = "build/test/verify_missing_subtitle_start_time";
2408 prepare_directory (dir);
2409 auto dcp = make_simple (dir, 1, 106);
2412 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2413 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2414 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2415 "<ContentTitleText>Content</ContentTitleText>"
2416 "<AnnotationText>Annotation</AnnotationText>"
2417 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2418 "<ReelNumber>1</ReelNumber>"
2419 "<Language>de-DE</Language>"
2420 "<EditRate>24 1</EditRate>"
2421 "<TimeCodeRate>24</TimeCodeRate>"
2422 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2424 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2425 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2426 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2432 dcp::File xml_file(dir / "subs.xml", "w");
2433 BOOST_REQUIRE (xml_file);
2434 xml_file.write(xml.c_str(), xml.size(), 1);
2436 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2437 subs->write (dir / "subs.mxf");
2439 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2440 auto cpl = dcp->cpls()[0];
2441 cpl->reels()[0]->add(reel_subs);
2444 check_verify_result (
2448 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2449 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2450 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2451 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2452 dcp::VerificationNote(
2453 dcp::VerificationNote::Type::OK,
2454 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2455 string{"1998x1080"},
2457 ).set_cpl_id(cpl->id()),
2458 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2459 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2460 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2461 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2462 dcp::VerificationNote(
2463 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2464 ).set_cpl_id(cpl->id()),
2465 dcp::VerificationNote(
2466 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2467 ).set_cpl_id(cpl->id())
2472 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time)
2474 path dir = "build/test/verify_invalid_subtitle_start_time";
2475 prepare_directory (dir);
2476 auto dcp = make_simple (dir, 1, 106);
2479 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2480 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
2481 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
2482 "<ContentTitleText>Content</ContentTitleText>"
2483 "<AnnotationText>Annotation</AnnotationText>"
2484 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
2485 "<ReelNumber>1</ReelNumber>"
2486 "<Language>de-DE</Language>"
2487 "<EditRate>24 1</EditRate>"
2488 "<TimeCodeRate>24</TimeCodeRate>"
2489 "<StartTime>00:00:02:00</StartTime>"
2490 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
2492 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
2493 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
2494 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
2500 dcp::File xml_file(dir / "subs.xml", "w");
2501 BOOST_REQUIRE (xml_file);
2502 xml_file.write(xml.c_str(), xml.size(), 1);
2504 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
2505 subs->write (dir / "subs.mxf");
2507 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
2508 auto cpl = dcp->cpls()[0];
2509 cpl->reels().front()->add(reel_subs);
2512 check_verify_result (
2516 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2517 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2518 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
2519 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2520 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2521 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2522 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
2523 dcp::VerificationNote(
2524 dcp::VerificationNote::Type::OK,
2525 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
2526 string{"1998x1080"},
2528 ).set_cpl_id(cpl->id()),
2529 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
2530 dcp::VerificationNote(
2531 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SUBTITLE_START_TIME, canonical(dir / "subs.mxf")
2532 ).set_cpl_id(cpl->id()),
2533 dcp::VerificationNote(
2534 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2535 ).set_cpl_id(cpl->id())
2543 TestText (int in_, int out_, float v_position_ = 0, dcp::VAlign v_align_ = dcp::VAlign::CENTER, string text_ = "Hello")
2546 , v_position(v_position_)
2554 dcp::VAlign v_align;
2560 shared_ptr<dcp::CPL>
2561 dcp_with_text(path dir, vector<TestText> subs, optional<dcp::Key> key = boost::none, optional<string> key_id = boost::none)
2563 prepare_directory (dir);
2564 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2565 asset->set_start_time (dcp::Time());
2566 for (auto i: subs) {
2567 add_test_subtitle (asset, i.in, i.out, i.v_position, i.v_align, i.text);
2569 asset->set_language (dcp::LanguageTag("de-DE"));
2570 if (key && key_id) {
2571 asset->set_key(*key);
2572 asset->set_key_id(*key_id);
2575 asset->write (dir / "subs.mxf");
2577 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2578 return write_dcp_with_single_asset (dir, reel_asset);
2583 shared_ptr<dcp::CPL>
2584 dcp_with_text_from_file (path dir, boost::filesystem::path subs_xml)
2586 prepare_directory (dir);
2587 auto asset = make_shared<dcp::SMPTESubtitleAsset>(subs_xml);
2588 asset->set_start_time (dcp::Time());
2589 asset->set_language (dcp::LanguageTag("de-DE"));
2591 auto subs_mxf = dir / "subs.mxf";
2592 asset->write (subs_mxf);
2594 /* The call to write() puts the asset into the DCP correctly but it will have
2595 * XML re-written by our parser. Overwrite the MXF using the given file's verbatim
2598 ASDCP::TimedText::MXFWriter writer;
2599 ASDCP::WriterInfo writer_info;
2600 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
2602 Kumu::hex2bin (asset->id().c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
2603 DCP_ASSERT (c == Kumu::UUID_Length);
2604 ASDCP::TimedText::TimedTextDescriptor descriptor;
2605 descriptor.ContainerDuration = asset->intrinsic_duration();
2606 Kumu::hex2bin (asset->xml_id()->c_str(), descriptor.AssetID, ASDCP::UUIDlen, &c);
2607 DCP_ASSERT (c == Kumu::UUID_Length);
2608 ASDCP::Result_t r = writer.OpenWrite (subs_mxf.string().c_str(), writer_info, descriptor, 16384);
2609 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2610 r = writer.WriteTimedTextResource (dcp::file_to_string(subs_xml));
2611 BOOST_REQUIRE (!ASDCP_FAILURE(r));
2614 auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
2615 return write_dcp_with_single_asset (dir, reel_asset);
2619 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_first_text_time)
2621 auto const dir = path("build/test/verify_invalid_subtitle_first_text_time");
2622 /* Just too early */
2623 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24 - 1, 5 * 24 }});
2624 check_verify_result (
2628 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2629 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2630 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2631 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2632 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2633 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2634 dcp::VerificationNote(
2635 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2636 ).set_cpl_id(cpl->id()),
2637 dcp::VerificationNote(
2638 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2639 ).set_cpl_id(cpl->id())
2645 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time)
2647 auto const dir = path("build/test/verify_valid_subtitle_first_text_time");
2648 /* Just late enough */
2649 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 5 * 24 }});
2650 check_verify_result(
2654 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2655 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2656 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2657 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2658 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2659 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2660 dcp::VerificationNote(
2661 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2662 ).set_cpl_id(cpl->id())
2667 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
2669 auto const dir = path("build/test/verify_valid_subtitle_first_text_time_on_second_reel");
2670 prepare_directory (dir);
2672 auto asset1 = make_shared<dcp::SMPTESubtitleAsset>();
2673 asset1->set_start_time (dcp::Time());
2674 /* Just late enough */
2675 add_test_subtitle (asset1, 4 * 24, 5 * 24);
2676 asset1->set_language (dcp::LanguageTag("de-DE"));
2678 asset1->write (dir / "subs1.mxf");
2679 auto reel_asset1 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset1, dcp::Fraction(24, 1), 5 * 24, 0);
2680 auto reel1 = make_shared<dcp::Reel>();
2681 reel1->add (reel_asset1);
2682 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 5 * 24);
2683 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
2684 reel1->add (markers1);
2686 auto asset2 = make_shared<dcp::SMPTESubtitleAsset>();
2687 asset2->set_start_time (dcp::Time());
2689 /* This would be too early on first reel but should be OK on the second */
2690 add_test_subtitle (asset2, 3, 4 * 24);
2691 asset2->set_language (dcp::LanguageTag("de-DE"));
2692 asset2->write (dir / "subs2.mxf");
2693 auto reel_asset2 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset2, dcp::Fraction(24, 1), 4 * 24, 0);
2694 auto reel2 = make_shared<dcp::Reel>();
2695 reel2->add (reel_asset2);
2696 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 4 * 24);
2697 markers2->set (dcp::Marker::LFOC, dcp::Time(4 * 24 - 1, 24, 24));
2698 reel2->add (markers2);
2700 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
2703 auto dcp = make_shared<dcp::DCP>(dir);
2705 dcp->set_annotation_text("hello");
2708 check_verify_result(
2712 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2713 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2714 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2715 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2716 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2717 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2718 dcp::VerificationNote(
2719 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2720 ).set_cpl_id(cpl->id())
2725 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_spacing)
2727 auto const dir = path("build/test/verify_invalid_subtitle_spacing");
2728 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2732 { 5 * 24 + 1, 6 * 24 },
2734 check_verify_result (
2738 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2739 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2740 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2741 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2742 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2743 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2744 dcp::VerificationNote(
2745 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING
2746 ).set_cpl_id(cpl->id()),
2747 dcp::VerificationNote(
2748 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2749 ).set_cpl_id(cpl->id())
2754 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_spacing)
2756 auto const dir = path("build/test/verify_valid_subtitle_spacing");
2757 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2761 { 5 * 24 + 16, 8 * 24 },
2764 check_verify_result(
2768 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2769 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2770 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2771 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2772 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2773 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2774 dcp::VerificationNote(
2775 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2776 ).set_cpl_id(cpl->id())
2781 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_duration)
2783 auto const dir = path("build/test/verify_invalid_subtitle_duration");
2784 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 1 }});
2785 check_verify_result (
2789 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2790 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2791 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2792 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2793 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2794 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2795 dcp::VerificationNote(
2796 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION
2797 ).set_cpl_id(cpl->id()),
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_valid_subtitle_duration)
2807 auto const dir = path("build/test/verify_valid_subtitle_duration");
2808 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 17 }});
2810 check_verify_result(
2814 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2815 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2816 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2817 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2818 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2819 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2820 dcp::VerificationNote(
2821 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2822 ).set_cpl_id(cpl->id())
2827 BOOST_AUTO_TEST_CASE (verify_subtitle_overlapping_reel_boundary)
2829 auto const dir = path("build/test/verify_subtitle_overlapping_reel_boundary");
2830 prepare_directory (dir);
2831 auto asset = make_shared<dcp::SMPTESubtitleAsset>();
2832 asset->set_start_time (dcp::Time());
2833 add_test_subtitle (asset, 0, 4 * 24);
2835 asset->set_language (dcp::LanguageTag("de-DE"));
2836 asset->write (dir / "subs.mxf");
2838 auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 3 * 24, 0);
2839 auto cpl = write_dcp_with_single_asset (dir, reel_asset);
2840 check_verify_result (
2844 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2845 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2846 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2847 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2848 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2849 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2850 dcp::VerificationNote(
2851 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "72 96", boost::filesystem::canonical(asset->file().get())
2852 ).set_cpl_id(cpl->id()),
2853 dcp::VerificationNote(
2854 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
2855 ).set_cpl_id(cpl->id()),
2856 dcp::VerificationNote(
2857 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY
2858 ).set_cpl_id(cpl->id()),
2859 dcp::VerificationNote(
2860 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2861 ).set_cpl_id(cpl->id())
2867 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count1)
2869 auto const dir = path ("build/test/invalid_subtitle_line_count1");
2870 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2873 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2874 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2875 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2876 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
2878 check_verify_result (
2882 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2883 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2884 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2885 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2886 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2887 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2888 dcp::VerificationNote(
2889 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2890 ).set_cpl_id(cpl->id()),
2891 dcp::VerificationNote(
2892 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2893 ).set_cpl_id(cpl->id())
2898 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count1)
2900 auto const dir = path ("build/test/verify_valid_subtitle_line_count1");
2901 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2904 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
2905 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
2906 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
2909 check_verify_result(
2913 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2914 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2915 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2916 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2917 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2918 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2919 dcp::VerificationNote(
2920 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2921 ).set_cpl_id(cpl->id())
2926 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count2)
2928 auto const dir = path ("build/test/verify_invalid_subtitle_line_count2");
2929 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2932 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2933 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2934 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2935 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
2937 check_verify_result (
2941 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2942 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2943 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2944 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2945 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2946 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2947 dcp::VerificationNote(
2948 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT
2949 ).set_cpl_id(cpl->id()),
2950 dcp::VerificationNote(
2951 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2952 ).set_cpl_id(cpl->id())
2957 BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count2)
2959 auto const dir = path ("build/test/verify_valid_subtitle_line_count2");
2960 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2963 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
2964 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
2965 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
2966 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
2969 check_verify_result(
2973 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2974 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
2975 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
2976 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
2977 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
2978 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
2979 dcp::VerificationNote(
2980 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
2981 ).set_cpl_id(cpl->id())
2986 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length1)
2988 auto const dir = path ("build/test/verify_invalid_subtitle_line_length1");
2989 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
2992 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123" }
2994 check_verify_result (
2998 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
2999 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3000 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3001 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3002 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3003 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3004 dcp::VerificationNote(
3005 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH
3006 ).set_cpl_id(cpl->id()),
3007 dcp::VerificationNote(
3008 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3009 ).set_cpl_id(cpl->id())
3014 BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length2)
3016 auto const dir = path ("build/test/verify_invalid_subtitle_line_length2");
3017 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset> (
3020 { 96, 300, 0.0, dcp::VAlign::CENTER, "012345678901234567890123456789012345678901234567890123456789012345678901234567890" }
3022 check_verify_result (
3026 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3027 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3028 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3029 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3030 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3031 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3032 dcp::VerificationNote(
3033 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH
3034 ).set_cpl_id(cpl->id()),
3035 dcp::VerificationNote(
3036 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3037 ).set_cpl_id(cpl->id())
3042 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1)
3044 auto const dir = path ("build/test/verify_valid_closed_caption_line_count1");
3045 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3048 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
3049 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
3050 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
3051 { 96, 200, 0.3, dcp::VAlign::CENTER, "lines" }
3053 check_verify_result (
3057 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3058 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3059 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3060 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3061 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3062 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3063 dcp::VerificationNote(
3064 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
3065 ).set_cpl_id(cpl->id()),
3066 dcp::VerificationNote(
3067 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3068 ).set_cpl_id(cpl->id())
3073 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2)
3075 auto const dir = path ("build/test/verify_valid_closed_caption_line_count2");
3076 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3079 { 96, 200, 0.0, dcp::VAlign::CENTER, "We" },
3080 { 96, 200, 0.1, dcp::VAlign::CENTER, "have" },
3081 { 96, 200, 0.2, dcp::VAlign::CENTER, "four" },
3084 check_verify_result(
3088 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3089 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3090 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3091 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3092 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3093 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3094 dcp::VerificationNote(
3095 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3096 ).set_cpl_id(cpl->id())
3101 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3)
3103 auto const dir = path ("build/test/verify_invalid_closed_caption_line_count3");
3104 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3107 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
3108 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
3109 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
3110 { 150, 180, 0.3, dcp::VAlign::CENTER, "lines" }
3112 check_verify_result (
3116 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3117 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3118 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3119 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3120 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3121 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3122 dcp::VerificationNote(
3123 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT
3124 ).set_cpl_id(cpl->id()),
3125 dcp::VerificationNote(
3126 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3127 ).set_cpl_id(cpl->id())
3132 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4)
3134 auto const dir = path ("build/test/verify_valid_closed_caption_line_count4");
3135 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3138 { 96, 300, 0.0, dcp::VAlign::CENTER, "We" },
3139 { 96, 300, 0.1, dcp::VAlign::CENTER, "have" },
3140 { 150, 180, 0.2, dcp::VAlign::CENTER, "four" },
3141 { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" }
3144 check_verify_result(
3148 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3149 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3150 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3151 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3152 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3153 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3154 dcp::VerificationNote(
3155 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3156 ).set_cpl_id(cpl->id())
3161 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_length)
3163 auto const dir = path ("build/test/verify_valid_closed_caption_line_length");
3164 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3167 { 96, 300, 0.0, dcp::VAlign::CENTER, "01234567890123456789012345678901" }
3170 check_verify_result (
3174 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3175 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3176 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3177 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3178 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3179 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3180 dcp::VerificationNote(
3181 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3182 ).set_cpl_id(cpl->id())
3187 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length)
3189 auto const dir = path ("build/test/verify_invalid_closed_caption_line_length");
3190 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3193 { 96, 300, 0.0, dcp::VAlign::CENTER, "0123456789012345678901234567890123" }
3195 check_verify_result (
3199 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3200 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3201 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3202 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3203 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3204 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3205 dcp::VerificationNote(
3206 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH
3207 ).set_cpl_id(cpl->id()),
3208 dcp::VerificationNote(
3209 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3210 ).set_cpl_id(cpl->id())
3215 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign1)
3217 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign1");
3218 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3221 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3222 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3223 { 96, 300, 0.2, dcp::VAlign::TOP, "fine" },
3225 check_verify_result (
3229 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3230 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3231 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3232 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3233 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3234 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3235 dcp::VerificationNote(
3236 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3237 ).set_cpl_id(cpl->id())
3242 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign2)
3244 auto const dir = path ("build/test/verify_mismatched_closed_caption_valign2");
3245 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3248 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3249 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3250 { 96, 300, 0.2, dcp::VAlign::CENTER, "not fine" },
3252 check_verify_result (
3256 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3257 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3258 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3259 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3260 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3261 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3262 dcp::VerificationNote(
3263 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN
3264 ).set_cpl_id(cpl->id()),
3265 dcp::VerificationNote(
3266 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3267 ).set_cpl_id(cpl->id())
3272 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering1)
3274 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering1");
3275 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3278 { 96, 300, 0.0, dcp::VAlign::TOP, "This" },
3279 { 96, 300, 0.1, dcp::VAlign::TOP, "is" },
3280 { 96, 300, 0.2, dcp::VAlign::TOP, "fine" },
3283 check_verify_result(
3287 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3288 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3289 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3290 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3291 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3292 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3293 dcp::VerificationNote(
3294 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3295 ).set_cpl_id(cpl->id())
3300 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering2)
3302 auto const dir = path ("build/test/verify_invalid_incorrect_closed_caption_ordering2");
3303 auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
3306 { 96, 300, 0.2, dcp::VAlign::BOTTOM, "This" },
3307 { 96, 300, 0.1, dcp::VAlign::BOTTOM, "is" },
3308 { 96, 300, 0.0, dcp::VAlign::BOTTOM, "also fine" },
3311 check_verify_result(
3315 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3316 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3317 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3318 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3319 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3320 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3321 dcp::VerificationNote(
3322 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3323 ).set_cpl_id(cpl->id())
3328 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering3)
3330 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering3");
3331 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering3.xml");
3332 check_verify_result (
3336 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3337 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3338 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3339 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3340 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3341 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3342 dcp::VerificationNote(
3343 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING
3344 ).set_cpl_id(cpl->id()),
3345 dcp::VerificationNote(
3346 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3347 ).set_cpl_id(cpl->id())
3352 BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering4)
3354 auto const dir = path ("build/test/verify_incorrect_closed_caption_ordering4");
3355 auto cpl = dcp_with_text_from_file<dcp::ReelSMPTEClosedCaptionAsset> (dir, "test/data/verify_incorrect_closed_caption_ordering4.xml");
3357 check_verify_result(
3361 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3362 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3363 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3364 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3365 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3366 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3367 dcp::VerificationNote(
3368 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3369 ).set_cpl_id(cpl->id())
3375 BOOST_AUTO_TEST_CASE (verify_invalid_sound_frame_rate)
3377 path const dir("build/test/verify_invalid_sound_frame_rate");
3378 prepare_directory (dir);
3380 auto picture = simple_picture (dir, "foo");
3381 auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
3382 auto reel = make_shared<dcp::Reel>();
3383 reel->add (reel_picture);
3384 auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000, boost::none);
3385 auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
3386 reel->add (reel_sound);
3387 reel->add (simple_markers());
3388 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3390 auto dcp = make_shared<dcp::DCP>(dir);
3392 dcp->set_annotation_text("hello");
3395 check_verify_result (
3399 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3400 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3401 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
3402 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3403 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3404 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "videofoo.mxf"), cpl),
3405 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3406 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "videofoo.mxf"), cpl),
3407 dcp::VerificationNote(
3408 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SOUND_FRAME_RATE, string("96000"), canonical(dir / "audiofoo.mxf")
3409 ).set_cpl_id(cpl->id()),
3410 dcp::VerificationNote(
3411 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3412 ).set_cpl_id(cpl->id())
3417 BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text)
3419 path const dir("build/test/verify_missing_cpl_annotation_text");
3420 auto dcp = make_simple (dir);
3423 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3425 auto const cpl = dcp->cpls()[0];
3427 HashCalculator calc(cpl->file().get());
3430 BOOST_REQUIRE (cpl->file());
3431 Editor e(cpl->file().get());
3432 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "");
3435 check_verify_result (
3439 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3440 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3441 dcp::VerificationNote(
3442 dcp::VerificationNote::Type::OK,
3443 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3444 string{"1998x1080"},
3446 ).set_cpl_id(cpl->id()),
3447 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3448 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3449 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3450 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3451 dcp::VerificationNote(
3452 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3453 ).set_cpl_id(cpl->id()),
3454 dcp::VerificationNote(
3455 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3456 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
3461 BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text)
3463 path const dir("build/test/verify_mismatched_cpl_annotation_text");
3464 auto dcp = make_simple (dir);
3467 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3468 auto const cpl = dcp->cpls()[0];
3470 HashCalculator calc(cpl->file().get());
3473 BOOST_REQUIRE (cpl->file());
3474 Editor e(cpl->file().get());
3475 e.replace("<AnnotationText>A Test DCP</AnnotationText>", "<AnnotationText>A Test DCP 1</AnnotationText>");
3478 check_verify_result (
3482 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3483 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3484 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3485 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3486 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3487 dcp::VerificationNote(
3488 dcp::VerificationNote::Type::OK,
3489 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3490 string{"1998x1080"},
3492 ).set_cpl_id(cpl->id()),
3493 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3494 dcp::VerificationNote(
3495 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, canonical(cpl->file().get())
3496 ).set_cpl_id(cpl->id()),
3497 dcp::VerificationNote(
3498 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl->file().get())
3499 ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()).set_cpl_id(cpl->id())
3504 BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration)
3506 path const dir("build/test/verify_mismatched_asset_duration");
3507 prepare_directory (dir);
3508 shared_ptr<dcp::DCP> dcp (new dcp::DCP(dir));
3509 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3511 shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (dir, "", 24);
3512 shared_ptr<dcp::SoundAsset> ms = simple_sound (dir, "", dcp::MXFMetadata(), "en-US", 25);
3514 auto reel = make_shared<dcp::Reel>(
3515 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
3516 make_shared<dcp::ReelSoundAsset>(ms, 0)
3519 reel->add (simple_markers());
3523 dcp->set_annotation_text("A Test DCP");
3526 check_verify_result (
3530 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3531 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3532 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3533 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3534 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3535 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3536 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3537 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3538 dcp::VerificationNote(
3539 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_DURATION
3540 ).set_cpl_id(cpl->id()),
3541 dcp::VerificationNote(
3542 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl->file().get())
3543 ).set_cpl_id(cpl->id())
3550 shared_ptr<dcp::CPL>
3551 verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool add_to_reel2)
3553 prepare_directory (dir);
3554 auto dcp = make_shared<dcp::DCP>(dir);
3555 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3557 auto constexpr reel_length = 192;
3559 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3560 subs->set_language (dcp::LanguageTag("de-DE"));
3561 subs->set_start_time (dcp::Time());
3562 subs->add (simple_subtitle());
3564 subs->write (dir / "subs.mxf");
3565 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
3567 auto reel1 = make_shared<dcp::Reel>(
3568 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3569 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3573 reel1->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3576 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3577 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3578 reel1->add (markers1);
3582 auto reel2 = make_shared<dcp::Reel>(
3583 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3584 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3588 reel2->add (make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3591 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3592 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3593 reel2->add (markers2);
3598 dcp->set_annotation_text("A Test DCP");
3605 BOOST_AUTO_TEST_CASE (verify_missing_main_subtitle_from_some_reels)
3608 path dir ("build/test/missing_main_subtitle_from_some_reels");
3609 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, false);
3610 check_verify_result (
3614 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3615 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3616 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3617 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3618 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3619 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3620 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3621 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3622 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3623 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3624 dcp::VerificationNote(
3625 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS
3626 ).set_cpl_id(cpl->id()),
3627 dcp::VerificationNote(
3628 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3629 ).set_cpl_id(cpl->id())
3635 path dir ("build/test/verify_subtitles_must_be_in_all_reels2");
3636 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, true);
3637 check_verify_result(
3641 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3642 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3643 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3644 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3645 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3646 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3647 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3648 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3649 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3650 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), 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_subtitles_must_be_in_all_reels1");
3659 auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, false, false);
3660 check_verify_result(
3664 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3665 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3666 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3667 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3668 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3669 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3670 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3671 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3672 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3673 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), 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())
3683 shared_ptr<dcp::CPL>
3684 verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1, int caps_in_reel2)
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");
3699 auto reel1 = make_shared<dcp::Reel>(
3700 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
3701 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
3704 for (int i = 0; i < caps_in_reel1; ++i) {
3705 reel1->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3708 auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3709 markers1->set (dcp::Marker::FFOC, dcp::Time(1, 24, 24));
3710 reel1->add (markers1);
3714 auto reel2 = make_shared<dcp::Reel>(
3715 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
3716 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
3719 for (int i = 0; i < caps_in_reel2; ++i) {
3720 reel2->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
3723 auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length);
3724 markers2->set (dcp::Marker::LFOC, dcp::Time(reel_length - 1, 24, 24));
3725 reel2->add (markers2);
3730 dcp->set_annotation_text("A Test DCP");
3737 BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_asset_counts)
3740 path dir ("build/test/mismatched_closed_caption_asset_counts");
3741 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4);
3742 check_verify_result (
3746 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3747 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3748 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3749 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3750 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3751 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3752 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3753 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3754 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3755 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3756 dcp::VerificationNote(
3757 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS
3758 ).set_cpl_id(cpl->id()),
3759 dcp::VerificationNote(
3760 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3761 ).set_cpl_id(cpl->id())
3766 path dir ("build/test/verify_closed_captions_must_be_in_all_reels2");
3767 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4);
3768 check_verify_result(
3772 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3773 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3774 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3775 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3776 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3777 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3778 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3779 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3780 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3781 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3782 dcp::VerificationNote(
3783 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3784 ).set_cpl_id(cpl->id())
3789 path dir ("build/test/verify_closed_captions_must_be_in_all_reels3");
3790 auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0);
3791 check_verify_result(
3795 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3796 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video1.mxf"), cpl),
3797 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video2.mxf"), cpl),
3798 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3799 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3800 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3801 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3802 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video1.mxf"), cpl),
3803 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video2.mxf"), cpl),
3804 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3805 dcp::VerificationNote(
3806 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3807 ).set_cpl_id(cpl->id())
3815 verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost::function<void (shared_ptr<T>)> adjust)
3817 prepare_directory (dir);
3818 auto dcp = make_shared<dcp::DCP>(dir);
3819 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
3821 auto constexpr reel_length = 192;
3823 auto subs = make_shared<dcp::SMPTESubtitleAsset>();
3824 subs->set_language (dcp::LanguageTag("de-DE"));
3825 subs->set_start_time (dcp::Time());
3826 subs->add (simple_subtitle());
3828 subs->write (dir / "subs.mxf");
3829 auto reel_text = make_shared<T>(subs, dcp::Fraction(24, 1), reel_length, 0);
3832 auto reel = make_shared<dcp::Reel>(
3833 make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
3834 make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
3837 reel->add (reel_text);
3839 reel->add (simple_markers(reel_length));
3844 dcp->set_annotation_text("A Test DCP");
3847 check_verify_result (
3851 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3852 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3853 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3854 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3855 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3856 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3857 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
3858 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3859 dcp::VerificationNote(
3860 dcp::VerificationNote::Type::BV21_ERROR, code, subs->id()
3861 ).set_cpl_id(cpl->id()),
3862 dcp::VerificationNote(
3863 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
3864 ).set_cpl_id(cpl->id())
3869 BOOST_AUTO_TEST_CASE (verify_text_entry_point)
3871 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3872 "build/test/verify_subtitle_entry_point_must_be_present",
3873 dcp::VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT,
3874 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3875 asset->unset_entry_point ();
3879 verify_text_entry_point_check<dcp::ReelSMPTESubtitleAsset> (
3880 "build/test/verify_subtitle_entry_point_must_be_zero",
3881 dcp::VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT,
3882 [](shared_ptr<dcp::ReelSMPTESubtitleAsset> asset) {
3883 asset->set_entry_point (4);
3887 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3888 "build/test/verify_closed_caption_entry_point_must_be_present",
3889 dcp::VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT,
3890 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3891 asset->unset_entry_point ();
3895 verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
3896 "build/test/verify_closed_caption_entry_point_must_be_zero",
3897 dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT,
3898 [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
3899 asset->set_entry_point (9);
3905 BOOST_AUTO_TEST_CASE (verify_missing_hash)
3909 path const dir("build/test/verify_missing_hash");
3910 auto dcp = make_simple (dir);
3913 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
3914 auto const cpl = dcp->cpls()[0];
3915 BOOST_REQUIRE_EQUAL (cpl->reels().size(), 1U);
3916 BOOST_REQUIRE (cpl->reels()[0]->main_picture());
3917 auto asset_id = cpl->reels()[0]->main_picture()->id();
3919 HashCalculator calc(cpl->file().get());
3922 BOOST_REQUIRE (cpl->file());
3923 Editor e(cpl->file().get());
3924 e.delete_first_line_containing("<Hash>");
3927 check_verify_result (
3931 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
3932 dcp::VerificationNote(
3933 dcp::VerificationNote::Type::OK,
3934 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3935 string{"1998x1080"},
3937 ).set_cpl_id(cpl->id()),
3938 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
3939 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
3940 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
3941 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
3942 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
3943 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
3944 dcp::VerificationNote(
3945 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
3946 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
3947 dcp::VerificationNote(
3948 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id
3949 ).set_cpl_id(cpl->id())
3956 verify_markers_test (
3958 vector<pair<dcp::Marker, dcp::Time>> markers,
3959 vector<dcp::VerificationNote> test_notes
3962 auto dcp = make_simple (dir);
3963 auto cpl = dcp->cpls()[0];
3964 cpl->set_content_kind(dcp::ContentKind::FEATURE);
3965 auto markers_asset = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), 24);
3966 for (auto const& i: markers) {
3967 markers_asset->set (i.first, i.second);
3969 cpl->reels()[0]->add(markers_asset);
3972 for (auto& note: test_notes) {
3973 note.set_cpl_id(cpl->id());
3976 test_notes.push_back(ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl));
3977 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl));
3978 test_notes.push_back(ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl));
3979 test_notes.push_back(ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl));
3980 test_notes.push_back(
3981 dcp::VerificationNote(
3982 dcp::VerificationNote::Type::OK,
3983 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
3984 string{"1998x1080"},
3986 ).set_cpl_id(cpl->id())
3988 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl));
3989 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl));
3990 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl));
3991 test_notes.push_back(ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl));
3993 check_verify_result({dir}, {}, test_notes);
3997 BOOST_AUTO_TEST_CASE (verify_markers)
3999 verify_markers_test (
4000 "build/test/verify_markers_all_correct",
4002 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4003 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4004 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
4005 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
4010 verify_markers_test (
4011 "build/test/verify_markers_missing_ffec",
4013 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4014 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
4015 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
4018 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }
4021 verify_markers_test (
4022 "build/test/verify_markers_missing_ffmc",
4024 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4025 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
4026 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
4029 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }
4032 verify_markers_test (
4033 "build/test/verify_markers_missing_ffoc",
4035 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4036 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4037 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
4040 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC}
4043 verify_markers_test (
4044 "build/test/verify_markers_missing_lfoc",
4046 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4047 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4048 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) }
4051 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }
4054 verify_markers_test (
4055 "build/test/verify_markers_incorrect_ffoc",
4057 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4058 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4059 { dcp::Marker::FFOC, dcp::Time(3, 24, 24) },
4060 { dcp::Marker::LFOC, dcp::Time(23, 24, 24) }
4063 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_FFOC, string("3") }
4066 verify_markers_test (
4067 "build/test/verify_markers_incorrect_lfoc",
4069 { dcp::Marker::FFEC, dcp::Time(12, 24, 24) },
4070 { dcp::Marker::FFMC, dcp::Time(13, 24, 24) },
4071 { dcp::Marker::FFOC, dcp::Time(1, 24, 24) },
4072 { dcp::Marker::LFOC, dcp::Time(18, 24, 24) }
4075 { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_LFOC, string("18") }
4080 BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number)
4082 path dir = "build/test/verify_missing_cpl_metadata_version_number";
4083 prepare_directory (dir);
4084 auto dcp = make_simple (dir);
4085 auto cpl = dcp->cpls()[0];
4086 cpl->unset_version_number();
4089 check_verify_result(
4093 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4094 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4095 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4096 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4097 dcp::VerificationNote(
4098 dcp::VerificationNote::Type::OK,
4099 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4100 string{"1998x1080"},
4102 ).set_cpl_id(cpl->id()),
4103 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4104 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4105 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4106 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4107 dcp::VerificationNote(
4108 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->file().get()
4109 ).set_cpl_id(cpl->id())
4114 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1)
4116 path dir = "build/test/verify_missing_extension_metadata1";
4117 auto dcp = make_simple (dir);
4120 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
4121 auto cpl = dcp->cpls()[0];
4123 HashCalculator calc(cpl->file().get());
4126 Editor e (cpl->file().get());
4127 e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
4130 check_verify_result (
4134 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4135 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4136 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4137 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4138 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4139 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4140 dcp::VerificationNote(
4141 dcp::VerificationNote::Type::OK,
4142 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4143 string{"1998x1080"},
4145 ).set_cpl_id(cpl->id()),
4146 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4147 dcp::VerificationNote(
4148 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4149 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4150 dcp::VerificationNote(
4151 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
4152 ).set_cpl_id(cpl->id())
4157 BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2)
4159 path dir = "build/test/verify_missing_extension_metadata2";
4160 auto dcp = make_simple (dir);
4163 auto cpl = dcp->cpls()[0];
4165 HashCalculator calc(cpl->file().get());
4168 Editor e (cpl->file().get());
4169 e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
4172 check_verify_result (
4176 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4177 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4178 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4179 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4180 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4181 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4182 dcp::VerificationNote(
4183 dcp::VerificationNote::Type::OK,
4184 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4185 string{"1998x1080"},
4187 ).set_cpl_id(cpl->id()),
4188 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4189 dcp::VerificationNote(
4190 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4191 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4192 dcp::VerificationNote(
4193 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get()
4194 ).set_cpl_id(cpl->id())
4199 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3)
4201 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata3";
4202 auto dcp = make_simple (dir);
4205 auto const cpl = dcp->cpls()[0];
4207 HashCalculator calc(cpl->file().get());
4210 Editor e (cpl->file().get());
4211 e.replace ("<meta:Name>A", "<meta:NameX>A");
4212 e.replace ("n</meta:Name>", "n</meta:NameX>");
4215 check_verify_result (
4219 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4220 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4221 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4222 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4223 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4224 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4225 dcp::VerificationNote(
4226 dcp::VerificationNote::Type::OK,
4227 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4228 string{"1998x1080"},
4230 ).set_cpl_id(cpl->id()),
4231 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4232 dcp::VerificationNote(
4233 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:NameX'"), cpl->file().get(), 70
4234 ).set_cpl_id(cpl->id()),
4235 dcp::VerificationNote(
4236 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()),
4237 dcp::VerificationNote(
4238 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4239 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4244 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1)
4246 path dir = "build/test/verify_invalid_extension_metadata1";
4247 auto dcp = make_simple (dir);
4250 auto cpl = dcp->cpls()[0];
4252 HashCalculator calc(cpl->file().get());
4255 Editor e (cpl->file().get());
4256 e.replace ("Application", "Fred");
4259 check_verify_result (
4263 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4264 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4265 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4266 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4267 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4268 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4269 dcp::VerificationNote(
4270 dcp::VerificationNote::Type::OK,
4271 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4272 string{"1998x1080"},
4274 ).set_cpl_id(cpl->id()),
4275 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4276 dcp::VerificationNote(
4277 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4278 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4279 dcp::VerificationNote(
4280 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> should be 'Application'"), cpl->file().get()
4281 ).set_cpl_id(cpl->id())
4286 BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2)
4288 path dir = "build/test/verify_invalid_extension_metadata2";
4289 auto dcp = make_simple (dir);
4292 auto cpl = dcp->cpls()[0];
4294 HashCalculator calc(cpl->file().get());
4297 Editor e (cpl->file().get());
4298 e.replace ("DCP Constraints Profile", "Fred");
4301 check_verify_result (
4305 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4306 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4307 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4308 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4309 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4310 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4311 dcp::VerificationNote(
4312 dcp::VerificationNote::Type::OK,
4313 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4314 string{"1998x1080"},
4316 ).set_cpl_id(cpl->id()),
4317 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4318 dcp::VerificationNote(
4319 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4320 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4321 dcp::VerificationNote(
4322 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'"), cpl->file().get()
4323 ).set_cpl_id(cpl->id())
4328 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6)
4330 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata6";
4331 auto dcp = make_simple (dir);
4334 auto const cpl = dcp->cpls()[0];
4336 HashCalculator calc(cpl->file().get());
4339 Editor e (cpl->file().get());
4340 e.replace ("<meta:Value>", "<meta:ValueX>");
4341 e.replace ("</meta:Value>", "</meta:ValueX>");
4344 check_verify_result (
4348 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4349 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4350 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4351 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4352 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4353 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4354 dcp::VerificationNote(
4355 dcp::VerificationNote::Type::OK,
4356 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4357 string{"1998x1080"},
4359 ).set_cpl_id(cpl->id()),
4360 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4361 dcp::VerificationNote(
4362 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:ValueX'"), cpl->file().get(), 74
4363 ).set_cpl_id(cpl->id()),
4364 dcp::VerificationNote(
4365 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
4366 ).set_cpl_id(cpl->id()),
4367 dcp::VerificationNote(
4368 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4369 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash())
4374 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7)
4376 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata7";
4377 auto dcp = make_simple (dir);
4380 auto const cpl = dcp->cpls()[0];
4382 HashCalculator calc(cpl->file().get());
4385 Editor e (cpl->file().get());
4386 e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
4389 check_verify_result (
4393 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4394 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4395 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4396 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4397 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4398 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4399 dcp::VerificationNote(
4400 dcp::VerificationNote::Type::OK,
4401 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4402 string{"1998x1080"},
4404 ).set_cpl_id(cpl->id()),
4405 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4406 dcp::VerificationNote(
4407 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4408 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4409 dcp::VerificationNote(
4410 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()
4411 ).set_cpl_id(cpl->id())
4416 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8)
4418 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata8";
4419 auto dcp = make_simple (dir);
4422 auto const cpl = dcp->cpls()[0];
4424 HashCalculator calc(cpl->file().get());
4427 Editor e (cpl->file().get());
4428 e.replace ("<meta:Property>", "<meta:PropertyX>");
4429 e.replace ("</meta:Property>", "</meta:PropertyX>");
4432 check_verify_result (
4436 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4437 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4438 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4439 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4440 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4441 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4442 dcp::VerificationNote(
4443 dcp::VerificationNote::Type::OK,
4444 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4445 string{"1998x1080"},
4447 ).set_cpl_id(cpl->id()),
4448 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4449 dcp::VerificationNote(
4450 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyX'"), cpl->file().get(), 72
4451 ).set_cpl_id(cpl->id()),
4452 dcp::VerificationNote(
4453 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()),
4454 dcp::VerificationNote(
4455 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4456 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4461 BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9)
4463 path dir = "build/test/verify_invalid_xml_cpl_extension_metadata9";
4464 auto dcp = make_simple (dir);
4467 auto const cpl = dcp->cpls()[0];
4469 HashCalculator calc(cpl->file().get());
4472 Editor e (cpl->file().get());
4473 e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
4474 e.replace ("</meta:PropertyList>", "</meta:PropertyListX>");
4477 check_verify_result (
4481 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4482 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4483 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4484 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4485 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4486 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4487 dcp::VerificationNote(
4488 dcp::VerificationNote::Type::OK,
4489 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4490 string{"1998x1080"},
4492 ).set_cpl_id(cpl->id()),
4493 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4494 dcp::VerificationNote(
4495 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyListX'"), cpl->file().get(), 71
4496 ).set_cpl_id(cpl->id()),
4497 dcp::VerificationNote(
4498 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
4499 ).set_cpl_id(cpl->id()),
4500 dcp::VerificationNote(
4501 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->file().get()
4502 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4508 BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content)
4510 path const dir = "build/test/verify_unsigned_cpl_with_encrypted_content";
4511 prepare_directory (dir);
4512 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4513 copy_file (i.path(), dir / i.path().filename());
4516 path const pkl = dir / ( "pkl_" + encryption_test_pkl_id() + ".xml");
4517 path const cpl_path = dir / ( "cpl_" + encryption_test_cpl_id() + ".xml");
4519 HashCalculator calc(cpl_path);
4523 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4526 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4528 check_verify_result (
4532 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4533 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4534 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4535 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4536 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4537 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4538 dcp::VerificationNote(
4539 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(cpl_path)
4540 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
4541 dcp::VerificationNote(
4542 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4543 ).set_cpl_id(cpl->id()),
4544 dcp::VerificationNote(
4545 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4546 ).set_cpl_id(cpl->id()),
4547 dcp::VerificationNote(
4548 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4549 ).set_cpl_id(cpl->id()),
4550 dcp::VerificationNote(
4551 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4552 ).set_cpl_id(cpl->id()),
4553 dcp::VerificationNote(
4554 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4555 ).set_cpl_id(cpl->id()),
4556 dcp::VerificationNote(
4557 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4558 ).set_cpl_id(cpl->id()),
4559 dcp::VerificationNote(
4560 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_path)
4561 ).set_cpl_id(cpl->id())
4566 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_encrypted_content)
4568 path dir = "build/test/unsigned_pkl_with_encrypted_content";
4569 prepare_directory (dir);
4570 for (auto i: directory_iterator("test/ref/DCP/encryption_test")) {
4571 copy_file (i.path(), dir / i.path().filename());
4574 path const cpl_path = dir / ("cpl_" + encryption_test_cpl_id() + ".xml");
4575 path const pkl = dir / ("pkl_" + encryption_test_pkl_id() + ".xml");
4578 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4581 auto cpl = std::make_shared<dcp::CPL>(cpl_path);
4583 check_verify_result (
4587 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
4588 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4589 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4590 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
4591 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4592 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4593 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4594 dcp::VerificationNote(
4595 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl)
4596 ).set_cpl_id(cpl->id()),
4597 dcp::VerificationNote(
4598 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
4599 ).set_cpl_id(cpl->id()),
4600 dcp::VerificationNote(
4601 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
4602 ).set_cpl_id(cpl->id()),
4603 dcp::VerificationNote(
4604 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
4605 ).set_cpl_id(cpl->id()),
4606 dcp::VerificationNote(
4607 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
4608 ).set_cpl_id(cpl->id()),
4609 dcp::VerificationNote(
4610 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_path)
4611 ).set_cpl_id(cpl->id()),
4612 dcp::VerificationNote(
4613 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, encryption_test_pkl_id(), canonical(pkl)
4619 BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_unencrypted_content)
4621 path dir = "build/test/verify_unsigned_pkl_with_unencrypted_content";
4622 prepare_directory (dir);
4623 for (auto i: directory_iterator("test/ref/DCP/dcp_test1")) {
4624 copy_file (i.path(), dir / i.path().filename());
4628 Editor e (dir / dcp_test1_pkl());
4629 e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
4632 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4634 check_verify_result(
4638 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4639 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4640 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4641 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4642 dcp::VerificationNote(
4643 dcp::VerificationNote::Type::OK,
4644 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4645 string{"1998x1080"},
4646 canonical(cpl->file().get())
4647 ).set_cpl_id(cpl->id()),
4648 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4649 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4650 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4651 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4656 BOOST_AUTO_TEST_CASE (verify_partially_encrypted)
4658 path dir ("build/test/verify_must_not_be_partially_encrypted");
4659 prepare_directory (dir);
4663 auto signer = make_shared<dcp::CertificateChain>();
4664 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/ca.self-signed.pem")));
4665 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/intermediate.signed.pem")));
4666 signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/leaf.signed.pem")));
4667 signer->set_key (dcp::file_to_string("test/ref/crypt/leaf.key"));
4669 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
4673 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction (24, 1), dcp::Standard::SMPTE);
4676 auto writer = mp->start_write(dir / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
4677 dcp::ArrayData j2c ("test/data/flat_red.j2c");
4678 for (int i = 0; i < 24; ++i) {
4679 writer->write (j2c.data(), j2c.size());
4681 writer->finalize ();
4683 auto ms = simple_sound (dir, "", dcp::MXFMetadata(), "de-DE");
4685 auto reel = make_shared<dcp::Reel>(
4686 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
4687 make_shared<dcp::ReelSoundAsset>(ms, 0)
4690 reel->add (simple_markers());
4694 cpl->set_content_version (
4695 {"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"}
4697 cpl->set_annotation_text ("A Test DCP");
4698 cpl->set_issuer ("OpenDCP 0.0.25");
4699 cpl->set_creator ("OpenDCP 0.0.25");
4700 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
4701 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
4702 cpl->set_main_sound_sample_rate (48000);
4703 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
4704 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
4705 cpl->set_version_number (1);
4709 d.set_issuer("OpenDCP 0.0.25");
4710 d.set_creator("OpenDCP 0.0.25");
4711 d.set_issue_date("2012-07-17T04:45:18+00:00");
4712 d.set_annotation_text("A Test DCP");
4713 d.write_xml(signer);
4715 check_verify_result (
4719 dcp::VerificationNote(
4720 dcp::VerificationNote::Type::OK,
4721 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
4722 string{"1440x1080"},
4724 ).set_cpl_id(cpl->id()),
4725 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4726 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
4727 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4728 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4729 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4730 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4731 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4732 dcp::VerificationNote(
4733 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::PARTIALLY_ENCRYPTED
4734 ).set_cpl_id(cpl->id())
4739 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_2k)
4741 vector<dcp::VerificationNote> notes;
4742 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"));
4743 auto reader = picture.start_read ();
4744 auto frame = reader->get_frame (0);
4745 verify_j2k(frame, 0, 0, 24, notes);
4746 BOOST_CHECK(notes.empty());
4750 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_4k)
4752 vector<dcp::VerificationNote> notes;
4753 dcp::MonoPictureAsset picture (find_file(private_test / "data" / "sul", "TLR"));
4754 auto reader = picture.start_read ();
4755 auto frame = reader->get_frame (0);
4756 verify_j2k(frame, 0, 0, 24, notes);
4757 BOOST_CHECK(notes.empty());
4761 BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp)
4763 boost::filesystem::path dir = "build/test/verify_jpeg2000_codestream_libdcp";
4764 prepare_directory (dir);
4765 auto dcp = make_simple (dir);
4767 vector<dcp::VerificationNote> notes;
4768 dcp::MonoPictureAsset picture (find_file(dir, "video"));
4769 auto reader = picture.start_read ();
4770 auto frame = reader->get_frame (0);
4771 verify_j2k(frame, 0, 0, 24, notes);
4772 BOOST_CHECK(notes.empty());
4776 /** Check that ResourceID and the XML ID being different is spotted */
4777 BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id)
4779 boost::filesystem::path const dir = "build/test/verify_mismatched_subtitle_resource_id";
4780 prepare_directory (dir);
4782 ASDCP::WriterInfo writer_info;
4783 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4786 auto mxf_id = dcp::make_uuid ();
4787 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4788 BOOST_REQUIRE (c == Kumu::UUID_Length);
4790 auto resource_id = dcp::make_uuid ();
4791 ASDCP::TimedText::TimedTextDescriptor descriptor;
4792 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4793 DCP_ASSERT (c == Kumu::UUID_Length);
4795 auto xml_id = dcp::make_uuid ();
4796 ASDCP::TimedText::MXFWriter writer;
4797 auto subs_mxf = dir / "subs.mxf";
4798 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4799 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4800 writer.WriteTimedTextResource (dcp::String::compose(
4801 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4802 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4803 "<Id>urn:uuid:%1</Id>"
4804 "<ContentTitleText>Content</ContentTitleText>"
4805 "<AnnotationText>Annotation</AnnotationText>"
4806 "<IssueDate>2018-10-02T12:25:14</IssueDate>"
4807 "<ReelNumber>1</ReelNumber>"
4808 "<Language>en-US</Language>"
4809 "<EditRate>25 1</EditRate>"
4810 "<TimeCodeRate>25</TimeCodeRate>"
4811 "<StartTime>00:00:00:00</StartTime>"
4812 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
4814 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4815 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4816 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4825 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4826 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4828 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4830 check_verify_result (
4834 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4835 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4836 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4837 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4838 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4839 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4840 dcp::VerificationNote(
4841 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4842 ).set_cpl_id(cpl->id()),
4843 dcp::VerificationNote(
4844 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID
4845 ).set_cpl_id(cpl->id()),
4846 dcp::VerificationNote(
4847 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4848 ).set_cpl_id(cpl->id()),
4849 dcp::VerificationNote(
4850 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4851 ).set_cpl_id(cpl->id())
4856 /** Check that ResourceID and the MXF ID being the same is spotted */
4857 BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
4859 boost::filesystem::path const dir = "build/test/verify_incorrect_timed_text_id";
4860 prepare_directory (dir);
4862 ASDCP::WriterInfo writer_info;
4863 writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
4866 auto mxf_id = dcp::make_uuid ();
4867 Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
4868 BOOST_REQUIRE (c == Kumu::UUID_Length);
4870 auto resource_id = mxf_id;
4871 ASDCP::TimedText::TimedTextDescriptor descriptor;
4872 Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
4873 DCP_ASSERT (c == Kumu::UUID_Length);
4875 auto xml_id = resource_id;
4876 ASDCP::TimedText::MXFWriter writer;
4877 auto subs_mxf = dir / "subs.mxf";
4878 auto r = writer.OpenWrite(subs_mxf.string().c_str(), writer_info, descriptor, 4096);
4879 BOOST_REQUIRE (ASDCP_SUCCESS(r));
4880 writer.WriteTimedTextResource (dcp::String::compose(
4881 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
4882 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
4883 "<Id>urn:uuid:%1</Id>"
4884 "<ContentTitleText>Content</ContentTitleText>"
4885 "<AnnotationText>Annotation</AnnotationText>"
4886 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
4887 "<ReelNumber>1</ReelNumber>"
4888 "<Language>en-US</Language>"
4889 "<EditRate>25 1</EditRate>"
4890 "<TimeCodeRate>25</TimeCodeRate>"
4891 "<StartTime>00:00:00:00</StartTime>"
4892 "<LoadFont ID=\"font\">urn:uuid:0ce6e0ba-58b9-4344-8929-4d9c959c2d55</LoadFont>"
4894 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
4895 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
4896 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
4905 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
4906 auto subs_reel = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
4908 auto cpl = write_dcp_with_single_asset (dir, subs_reel);
4910 check_verify_result (
4914 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4915 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
4916 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4917 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
4918 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4919 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4920 dcp::VerificationNote(
4921 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf)
4922 ).set_cpl_id(cpl->id()),
4923 dcp::VerificationNote(
4924 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID
4925 ).set_cpl_id(cpl->id()),
4926 dcp::VerificationNote(
4927 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
4928 ).set_cpl_id(cpl->id()),
4929 dcp::VerificationNote(
4930 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get()
4931 ).set_cpl_id(cpl->id()),
4932 dcp::VerificationNote(
4933 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2018-10-02T12:25:14+02:00"}
4934 ).set_cpl_id(cpl->id())
4939 /** Check a DCP with a 3D asset marked as 2D */
4940 BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod)
4942 auto const path = private_test / "data" / "xm";
4944 auto cpl = std::make_shared<dcp::CPL>(find_prefix(path, "CPL_"));
4947 check_verify_result (
4951 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4952 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4953 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd_j2c.mxf"), cpl),
4954 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
4955 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
4956 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4957 dcp::VerificationNote(
4958 dcp::VerificationNote::Type::WARNING,
4959 dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(path, "j2c"))
4961 dcp::VerificationNote(
4962 dcp::VerificationNote::Type::BV21_ERROR,
4963 dcp::VerificationNote::Code::INVALID_STANDARD
4970 BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers)
4972 path dir = "build/test/verify_unexpected_things_in_main_markers";
4973 prepare_directory (dir);
4974 auto dcp = make_simple (dir, 1, 24);
4977 HashCalculator calc(find_cpl(dir));
4980 Editor e (find_cpl(dir));
4982 " <IntrinsicDuration>24</IntrinsicDuration>",
4983 "<EntryPoint>0</EntryPoint><Duration>24</Duration>"
4987 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
4989 check_verify_result (
4993 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
4994 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
4995 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
4996 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
4997 dcp::VerificationNote(
4998 dcp::VerificationNote::Type::OK,
4999 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5000 string{"1998x1080"},
5001 canonical(cpl->file().get())
5002 ).set_cpl_id(cpl->id()),
5003 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5004 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5005 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5006 dcp::VerificationNote(
5007 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5008 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5009 dcp::VerificationNote(
5010 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_ENTRY_POINT
5011 ).set_cpl_id(cpl->id()),
5012 dcp::VerificationNote(
5013 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_DURATION
5014 ).set_cpl_id(cpl->id())
5019 BOOST_AUTO_TEST_CASE(verify_invalid_content_kind)
5021 path dir = "build/test/verify_invalid_content_kind";
5022 prepare_directory (dir);
5023 auto dcp = make_simple (dir, 1, 24);
5026 HashCalculator calc(find_cpl(dir));
5029 Editor e(find_cpl(dir));
5030 e.replace("trailer", "trip");
5033 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5035 check_verify_result (
5039 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5040 dcp::VerificationNote(
5041 dcp::VerificationNote::Type::OK,
5042 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5043 string{"1998x1080"},
5044 canonical(cpl->file().get())
5045 ).set_cpl_id(cpl->id()),
5046 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5047 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5048 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5049 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5050 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5051 dcp::VerificationNote(
5052 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5053 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5054 dcp::VerificationNote(
5055 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip")
5056 ).set_cpl_id(cpl->id()),
5062 BOOST_AUTO_TEST_CASE(verify_valid_content_kind)
5064 path dir = "build/test/verify_valid_content_kind";
5065 prepare_directory (dir);
5066 auto dcp = make_simple (dir, 1, 24);
5069 HashCalculator calc(find_cpl(dir));
5072 Editor e(find_cpl(dir));
5073 e.replace("<ContentKind>trailer</ContentKind>", "<ContentKind scope=\"http://bobs.contents/\">trip</ContentKind>");
5076 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5078 check_verify_result (
5082 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5083 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5084 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5085 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5086 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5087 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5088 dcp::VerificationNote(
5089 dcp::VerificationNote::Type::OK,
5090 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5091 string{"1998x1080"},
5092 canonical(cpl->file().get())
5093 ).set_cpl_id(cpl->id()),
5094 dcp::VerificationNote(
5095 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5096 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5101 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1)
5103 path dir = "build/test/verify_invalid_main_picture_active_area_1";
5104 prepare_directory(dir);
5105 auto dcp = make_simple(dir, 1, 24);
5108 auto constexpr area = "<meta:MainPictureActiveArea>";
5110 HashCalculator calc(find_cpl(dir));
5113 Editor e(find_cpl(dir));
5114 e.delete_lines_after(area, 2);
5115 e.insert(area, "<meta:Height>4080</meta:Height>");
5116 e.insert(area, "<meta:Width>1997</meta:Width>");
5119 dcp::PKL pkl(find_pkl(dir));
5120 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5122 check_verify_result(
5126 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5127 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5128 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5129 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5130 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5131 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5132 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5133 dcp::VerificationNote(
5134 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5135 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5136 dcp::VerificationNote(
5137 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 1997 is not a multiple of 2", canonical(find_cpl(dir))
5138 ).set_cpl_id(cpl->id()),
5139 dcp::VerificationNote(
5140 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))
5141 ).set_cpl_id(cpl->id()),
5146 BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2)
5148 path dir = "build/test/verify_invalid_main_picture_active_area_2";
5149 prepare_directory(dir);
5150 auto dcp = make_simple(dir, 1, 24);
5153 auto constexpr area = "<meta:MainPictureActiveArea>";
5155 HashCalculator calc(find_cpl(dir));
5158 Editor e(find_cpl(dir));
5159 e.delete_lines_after(area, 2);
5160 e.insert(area, "<meta:Height>5125</meta:Height>");
5161 e.insert(area, "<meta:Width>9900</meta:Width>");
5164 dcp::PKL pkl(find_pkl(dir));
5165 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5167 check_verify_result(
5171 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5172 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5173 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5174 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5175 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5176 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5177 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5178 dcp::VerificationNote(
5179 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, canonical(find_cpl(dir))
5180 ).set_cpl_id(cpl->id()).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()),
5181 dcp::VerificationNote(
5182 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is not a multiple of 2", canonical(find_cpl(dir))
5183 ).set_cpl_id(cpl->id()),
5184 dcp::VerificationNote(
5185 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))
5186 ).set_cpl_id(cpl->id()),
5187 dcp::VerificationNote(
5188 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))
5189 ).set_cpl_id(cpl->id())
5194 BOOST_AUTO_TEST_CASE(verify_duplicate_pkl_asset_ids)
5198 path dir = "build/test/verify_duplicate_pkl_asset_ids";
5199 prepare_directory(dir);
5200 auto dcp = make_simple(dir, 1, 24);
5204 Editor e(find_pkl(dir));
5205 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:6affb8ee-0020-4dff-a53c-17652f6358ab");
5208 dcp::PKL pkl(find_pkl(dir));
5209 auto cpl = std::make_shared<dcp::CPL>(find_cpl(dir));
5211 check_verify_result(
5215 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5216 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5217 dcp::VerificationNote(
5218 dcp::VerificationNote::Type::OK,
5219 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5220 string{"1998x1080"},
5221 canonical(cpl->file().get())
5222 ).set_cpl_id(cpl->id()),
5223 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5224 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5225 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5226 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5227 { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl.id(), canonical(find_pkl(dir)) },
5232 BOOST_AUTO_TEST_CASE(verify_duplicate_assetmap_asset_ids)
5236 path dir = "build/test/verify_duplicate_assetmap_asset_ids";
5237 prepare_directory(dir);
5238 auto dcp = make_simple(dir, 1, 24);
5242 Editor e(find_asset_map(dir));
5243 e.replace("urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54", "urn:uuid:97f0f352-5b77-48ee-a558-9df37717f4fa");
5246 dcp::PKL pkl(find_pkl(dir));
5247 dcp::AssetMap asset_map(find_asset_map(dir));
5248 auto cpl = make_shared<dcp::CPL>(find_cpl(dir));
5250 check_verify_result(
5254 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5255 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5256 dcp::VerificationNote(
5257 dcp::VerificationNote::Type::OK,
5258 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5259 string{"1998x1080"},
5260 canonical(cpl->file().get())
5261 ).set_cpl_id(cpl->id()),
5262 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5263 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5264 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5265 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5266 dcp::VerificationNote(
5267 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map.id(), canonical(find_asset_map(dir))
5269 dcp::VerificationNote(
5270 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, string("5407b210-4441-4e97-8b16-8bdc7c12da54")
5276 BOOST_AUTO_TEST_CASE(verify_mismatched_sound_channel_counts)
5278 boost::filesystem::path const path = "build/test/verify_mismatched_sound_channel_counts";
5280 dcp::MXFMetadata mxf_meta;
5281 mxf_meta.company_name = "OpenDCP";
5282 mxf_meta.product_name = "OpenDCP";
5283 mxf_meta.product_version = "0.0.25";
5285 auto constexpr sample_rate = 48000;
5286 auto constexpr frames = 240;
5288 boost::filesystem::remove_all(path);
5289 boost::filesystem::create_directories(path);
5290 auto dcp = make_shared<dcp::DCP>(path);
5291 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5292 cpl->set_annotation_text("hello");
5293 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R"));
5294 cpl->set_main_sound_sample_rate(sample_rate);
5295 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5296 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5297 cpl->set_version_number(1);
5301 /* Reel with 2 channels of audio */
5303 auto mp = simple_picture(path, "1", frames, {});
5304 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5306 auto reel = make_shared<dcp::Reel>(
5307 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5308 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5311 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5312 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5319 /* Reel with 6 channels of audio */
5321 auto mp = simple_picture(path, "2", frames, {});
5322 auto ms = simple_sound(path, "2", mxf_meta, "en-US", frames, sample_rate, {}, 6);
5324 auto reel = make_shared<dcp::Reel>(
5325 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5326 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5329 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5330 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 0, frames - 1, 24));
5337 dcp->set_annotation_text("hello");
5340 check_verify_result(
5344 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5345 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5346 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5347 dcp::VerificationNote(
5348 dcp::VerificationNote::Type::OK,
5349 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5350 string{"1998x1080"},
5352 ).set_cpl_id(cpl->id()),
5353 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5354 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5355 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5356 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5357 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video2.mxf"), cpl),
5358 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video2.mxf"), cpl),
5359 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5360 dcp::VerificationNote(
5361 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, canonical(find_file(path, "audio2"))
5362 ).set_cpl_id(cpl->id())
5367 BOOST_AUTO_TEST_CASE(verify_invalid_main_sound_configuration)
5369 boost::filesystem::path const path = "build/test/verify_invalid_main_sound_configuration";
5371 dcp::MXFMetadata mxf_meta;
5372 mxf_meta.company_name = "OpenDCP";
5373 mxf_meta.product_name = "OpenDCP";
5374 mxf_meta.product_version = "0.0.25";
5376 auto constexpr sample_rate = 48000;
5377 auto constexpr frames = 240;
5379 boost::filesystem::remove_all(path);
5380 boost::filesystem::create_directories(path);
5381 auto dcp = make_shared<dcp::DCP>(path);
5382 auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5383 cpl->set_annotation_text("hello");
5384 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5385 cpl->set_main_sound_sample_rate(sample_rate);
5386 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5387 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5388 cpl->set_version_number(1);
5390 auto mp = simple_picture(path, "1", frames, {});
5391 auto ms = simple_sound(path, "1", mxf_meta, "en-US", frames, sample_rate, {}, 2);
5393 auto reel = make_shared<dcp::Reel>(
5394 std::make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5395 std::make_shared<dcp::ReelSoundAsset>(ms, 0)
5398 auto markers = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), frames);
5399 markers->set(dcp::Marker::FFOC, dcp::Time(0, 0, 0, 1, 24));
5400 markers->set(dcp::Marker::LFOC, dcp::Time(0, 0, 9, 23, 24));
5406 dcp->set_annotation_text("hello");
5409 check_verify_result(
5413 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5414 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5415 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5416 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5417 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5418 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video1.mxf"), cpl),
5419 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(path / "video1.mxf"), cpl),
5420 dcp::VerificationNote(
5421 dcp::VerificationNote::Type::OK,
5422 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5423 string{"1998x1080"},
5425 ).set_cpl_id(cpl->id()),
5426 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5427 dcp::VerificationNote(
5428 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))
5429 ).set_cpl_id(cpl->id())
5434 BOOST_AUTO_TEST_CASE(verify_invalid_tile_part_size)
5436 boost::filesystem::path const path = "build/test/verify_invalid_tile_part_size";
5437 auto constexpr video_frames = 24;
5438 auto constexpr sample_rate = 48000;
5440 boost::filesystem::remove_all(path);
5441 boost::filesystem::create_directories(path);
5443 auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
5444 auto picture_writer = mp->start_write(path / "video.mxf", dcp::PictureAsset::Behaviour::MAKE_NEW);
5446 dcp::Size const size(1998, 1080);
5447 auto image = make_shared<dcp::OpenJPEGImage>(size);
5448 boost::random::mt19937 rng(1);
5449 boost::random::uniform_int_distribution<> dist(0, 4095);
5450 for (int c = 0; c < 3; ++c) {
5451 for (int p = 0; p < (1998 * 1080); ++p) {
5452 image->data(c)[p] = dist(rng);
5455 auto j2c = dcp::compress_j2k(image, 750000000, video_frames, false, false);
5456 for (int i = 0; i < 24; ++i) {
5457 picture_writer->write(j2c.data(), j2c.size());
5459 picture_writer->finalize();
5461 auto dcp = make_shared<dcp::DCP>(path);
5462 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
5463 cpl->set_content_version(
5464 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11", "content-version-label-text")
5466 cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,R,C,LFE,Ls,Rs"));
5467 cpl->set_main_sound_sample_rate(sample_rate);
5468 cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
5469 cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
5470 cpl->set_version_number(1);
5472 auto ms = simple_sound(path, "", dcp::MXFMetadata(), "en-US", video_frames, sample_rate, {});
5474 auto reel = make_shared<dcp::Reel>(
5475 make_shared<dcp::ReelMonoPictureAsset>(mp, 0),
5476 make_shared<dcp::ReelSoundAsset>(ms, 0)
5481 dcp->set_annotation_text("A Test DCP");
5484 vector<dcp::VerificationNote> expected = {
5485 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5486 dcp::VerificationNote(
5487 dcp::VerificationNote::Type::OK,
5488 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5489 string{"1998x1080"},
5491 ).set_cpl_id(cpl->id()),
5492 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(path / "video.mxf"), cpl),
5493 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5494 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5495 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5496 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5497 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5498 dcp::VerificationNote(
5499 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC
5500 ).set_cpl_id(cpl->id()),
5501 dcp::VerificationNote(
5502 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC
5503 ).set_cpl_id(cpl->id())
5506 for (auto frame = 0; frame < 24; frame++) {
5508 dcp::VerificationNote(
5509 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(path / "video.mxf")
5510 ).set_frame(frame).set_frame_rate(24).set_cpl_id(cpl->id())
5514 int component_sizes[] = {
5520 for (auto frame = 0; frame < 24; frame++) {
5521 for (auto component = 0; component < 3; component++) {
5523 dcp::VerificationNote(
5524 dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE
5525 ).set_frame(frame).set_component(component).set_size(component_sizes[component]).set_cpl_id(cpl->id())
5530 check_verify_result({ path }, {}, expected);
5534 BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces)
5536 boost::filesystem::path const dir = "test/ref/DCP/subtitle_namespace_test";
5539 BOOST_REQUIRE(!dcp.cpls().empty());
5540 auto cpl = dcp.cpls()[0];
5542 check_verify_result(
5546 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5547 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5548 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5549 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"feature"}, cpl),
5550 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"Dcp_FTR-1_F_XX-XX_MOS_2K_20230407_SMPTE_OV"}, cpl),
5551 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5552 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "j2c_42b34dcd-caa5-4c7b-aa0f-66a590947ba1.mxf"), cpl),
5553 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5554 dcp::VerificationNote(
5555 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE
5556 ).set_cpl_id(cpl->id()),
5557 dcp::VerificationNote(
5558 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE
5559 ).set_cpl_id(cpl->id()),
5560 dcp::VerificationNote(
5561 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
5562 ).set_cpl_id(cpl->id()),
5563 dcp::VerificationNote(
5564 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(find_file(dir, "sub_"))
5565 ).set_cpl_id(cpl->id()),
5566 dcp::VerificationNote(
5567 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(find_file(dir, "cpl_"))
5568 ).set_cpl_id(cpl->id()),
5569 dcp::VerificationNote(
5570 dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, std::string{"315de731-1173-484c-9a35-bdacf5a9d99d"}
5571 ).set_cpl_id(cpl->id()),
5576 BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font)
5578 path const dir("build/test/verify_missing_load_font");
5579 prepare_directory (dir);
5580 copy_file ("test/data/subs1.xml", dir / "subs.xml");
5582 Editor editor(dir / "subs.xml");
5583 editor.delete_first_line_containing("LoadFont");
5585 auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml");
5586 auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
5587 auto cpl = write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP);
5589 check_verify_result (
5593 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5594 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5595 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5596 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5597 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5598 { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
5599 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id("theFontId").set_cpl_id(cpl->id())
5605 BOOST_AUTO_TEST_CASE(verify_missing_load_font)
5607 boost::filesystem::path const dir = "build/test/verify_missing_load_font";
5608 prepare_directory(dir);
5609 auto dcp = make_simple (dir, 1, 202);
5612 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
5613 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
5614 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
5615 "<ContentTitleText>Content</ContentTitleText>"
5616 "<AnnotationText>Annotation</AnnotationText>"
5617 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
5618 "<ReelNumber>1</ReelNumber>"
5619 "<EditRate>24 1</EditRate>"
5620 "<TimeCodeRate>24</TimeCodeRate>"
5621 "<StartTime>00:00:00:00</StartTime>"
5622 "<Language>de-DE</Language>"
5624 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
5625 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:06:00\" TimeOut=\"00:00:08:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
5626 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
5632 dcp::File xml_file(dir / "subs.xml", "w");
5633 BOOST_REQUIRE(xml_file);
5634 xml_file.write(xml.c_str(), xml.size(), 1);
5636 auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
5637 subs->write(dir / "subs.mxf");
5639 auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 202, 0);
5640 auto cpl = dcp->cpls()[0];
5641 cpl->reels()[0]->add(reel_subs);
5644 check_verify_result (
5648 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5649 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5650 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5651 dcp::VerificationNote(
5652 dcp::VerificationNote::Type::OK,
5653 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5654 string{"1998x1080"},
5656 ).set_cpl_id(cpl->id()),
5657 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5658 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5659 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5660 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5661 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5662 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id(reel_subs->id()).set_cpl_id(cpl->id())
5667 BOOST_AUTO_TEST_CASE(verify_spots_wrong_asset)
5669 boost::filesystem::path const dir = "build/test/verify_spots_wrong_asset";
5670 boost::filesystem::remove_all(dir);
5672 auto dcp1 = make_simple(dir / "1");
5674 auto cpl = dcp1->cpls()[0];
5676 auto const asset_1 = dcp::MonoPictureAsset(dir / "1" / "video.mxf").id();
5678 auto dcp2 = make_simple(dir / "2");
5680 auto const asset_2 = dcp::MonoPictureAsset(dir / "2" / "video.mxf").id();
5682 boost::filesystem::remove(dir / "1" / "video.mxf");
5683 boost::filesystem::copy_file(dir / "2" / "video.mxf", dir / "1" / "video.mxf");
5685 check_verify_result(
5689 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5690 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5691 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5692 dcp::VerificationNote(
5693 dcp::VerificationNote::Type::OK,
5694 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5695 string{"1998x1080"},
5697 ).set_cpl_id(cpl->id()),
5698 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5699 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5700 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5701 dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_MAP_ID).set_id(asset_1).set_other_id(asset_2)
5706 BOOST_AUTO_TEST_CASE(verify_cpl_content_version_label_text_empty)
5708 boost::filesystem::path const dir = "build/test/verify_cpl_content_version_label_text_empty";
5709 boost::filesystem::remove_all(dir);
5711 auto dcp = make_simple(dir);
5712 BOOST_REQUIRE(dcp->cpls().size() == 1);
5713 auto cpl = dcp->cpls()[0];
5714 cpl->set_content_version(dcp::ContentVersion(""));
5717 check_verify_result(
5721 dcp::VerificationNote(
5722 dcp::VerificationNote::Type::OK,
5723 dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA,
5724 string{"1998x1080"},
5726 ).set_cpl_id(cpl->id()),
5727 ok(dcp::VerificationNote::Code::NONE_ENCRYPTED, cpl),
5728 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5729 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5730 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5731 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"A Test DCP"}, cpl),
5732 ok(dcp::VerificationNote::Code::CORRECT_PICTURE_HASH, canonical(dir / "video.mxf"), cpl),
5733 ok(dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, canonical(dir / "video.mxf"), cpl),
5734 dcp::VerificationNote(dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get()).set_cpl_id(cpl->id())
5739 /** Check that we don't get any strange errors when verifying encrypted DCPs (DoM #2659) */
5740 BOOST_AUTO_TEST_CASE(verify_encrypted_smpte_dcp)
5742 auto const dir = path("build/test/verify_encrypted_smpte_dcp");
5744 auto key_id = dcp::make_uuid();
5745 auto cpl = dcp_with_text<dcp::ReelSMPTESubtitleAsset>(dir, {{ 4 * 24, 5 * 24 }}, key, key_id);
5747 dcp::DecryptedKDM kdm(dcp::LocalTime(), dcp::LocalTime(), "", "", "");
5748 kdm.add_key(dcp::DecryptedKDMKey(string{"MDIK"}, key_id, key, cpl->id(), dcp::Standard::SMPTE));
5750 path const pkl_file = find_file(dir, "pkl_");
5751 path const cpl_file = find_file(dir, "cpl_");
5753 check_verify_result(
5757 ok(dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl),
5758 ok(dcp::VerificationNote::Code::MATCHING_CPL_HASHES, cpl),
5759 ok(dcp::VerificationNote::Code::VALID_CONTENT_KIND, string{"trailer"}, cpl),
5760 ok(dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, cpl->content_version()->label_text, cpl),
5761 ok(dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, string{"hello"}, cpl),
5762 ok(dcp::VerificationNote::Code::ALL_ENCRYPTED, cpl),
5763 dcp::VerificationNote(
5764 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, canonical(cpl_file)
5765 ).set_cpl_id(cpl->id()),
5766 dcp::VerificationNote(
5767 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, canonical(cpl_file)
5768 ).set_cpl_id(cpl->id()),
5769 dcp::VerificationNote(
5770 dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, filename_to_id(pkl_file.filename()), canonical(pkl_file)