2 Copyright (C) 2018-2020 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
38 #include "reel_mono_picture_asset.h"
41 #include "openjpeg_image.h"
42 #include "mono_picture_asset.h"
43 #include "mono_picture_asset_writer.h"
44 #include "interop_subtitle_asset.h"
45 #include "smpte_subtitle_asset.h"
46 #include "reel_subtitle_asset.h"
47 #include "compose.hpp"
49 #include <boost/test/unit_test.hpp>
50 #include <boost/foreach.hpp>
51 #include <boost/algorithm/string.hpp>
60 using boost::optional;
61 using boost::shared_ptr;
64 static list<pair<string, optional<boost::filesystem::path> > > stages;
67 stage (string s, optional<boost::filesystem::path> p)
69 stages.push_back (make_pair (s, p));
78 static vector<boost::filesystem::path>
79 setup (int reference_number, int verify_test_number)
81 boost::filesystem::remove_all (dcp::String::compose("build/test/verify_test%1", verify_test_number));
82 boost::filesystem::create_directory (dcp::String::compose("build/test/verify_test%1", verify_test_number));
83 for (boost::filesystem::directory_iterator i(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number)); i != boost::filesystem::directory_iterator(); ++i) {
84 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", verify_test_number) / i->path().filename());
87 vector<boost::filesystem::path> directories;
88 directories.push_back (dcp::String::compose("build/test/verify_test%1", verify_test_number));
94 /** Class that can alter a file by searching and replacing strings within it.
95 * On destruction modifies the file whose name was given to the constructor.
100 Editor (boost::filesystem::path path)
103 _content = dcp::file_to_string (_path);
108 FILE* f = fopen(_path.string().c_str(), "w");
110 fwrite (_content.c_str(), _content.length(), 1, f);
114 void replace (string a, string b)
116 boost::algorithm::replace_all (_content, a, b);
120 boost::filesystem::path _path;
121 std::string _content;
126 dump_notes (list<dcp::VerificationNote> const & notes)
128 BOOST_FOREACH (dcp::VerificationNote i, notes) {
129 std::cout << dcp::note_to_string(i) << "\n";
133 /* Check DCP as-is (should be OK) */
134 BOOST_AUTO_TEST_CASE (verify_test1)
137 vector<boost::filesystem::path> directories = setup (1, 1);
138 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
140 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
141 boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml";
142 boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
144 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
145 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
146 BOOST_REQUIRE (st->second);
147 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
149 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
150 BOOST_REQUIRE (st->second);
151 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
153 BOOST_CHECK_EQUAL (st->first, "Checking reel");
154 BOOST_REQUIRE (!st->second);
156 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
157 BOOST_REQUIRE (st->second);
158 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
160 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
161 BOOST_REQUIRE (st->second);
162 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
164 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
165 BOOST_REQUIRE (st->second);
166 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
168 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
169 BOOST_REQUIRE (st->second);
170 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
172 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
173 BOOST_REQUIRE (st->second);
174 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
176 BOOST_REQUIRE (st == stages.end());
180 BOOST_CHECK_EQUAL (notes.size(), 0);
183 /* Corrupt the MXFs and check that this is spotted */
184 BOOST_AUTO_TEST_CASE (verify_test2)
186 vector<boost::filesystem::path> directories = setup (1, 2);
188 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
190 fseek (mod, 4096, SEEK_SET);
192 fwrite (&x, sizeof(x), 1, mod);
195 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
197 fseek (mod, 4096, SEEK_SET);
198 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
201 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
203 BOOST_REQUIRE_EQUAL (notes.size(), 2);
204 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
205 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
206 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
207 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
210 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
211 BOOST_AUTO_TEST_CASE (verify_test3)
213 vector<boost::filesystem::path> directories = setup (1, 3);
216 Editor e ("build/test/verify_test3/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml");
217 e.replace ("<Hash>", "<Hash>x");
220 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
224 BOOST_REQUIRE_EQUAL (notes.size(), 6);
225 list<dcp::VerificationNote>::const_iterator i = notes.begin();
226 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
227 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
229 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
230 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
232 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
233 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
235 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
236 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
238 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
239 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
241 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
242 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
246 /* Corrupt the ContentKind in the CPL */
247 BOOST_AUTO_TEST_CASE (verify_test4)
249 vector<boost::filesystem::path> directories = setup (1, 4);
252 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
253 e.replace ("<ContentKind>", "<ContentKind>x");
256 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
258 BOOST_REQUIRE_EQUAL (notes.size(), 1);
259 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
260 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
264 boost::filesystem::path
267 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
271 boost::filesystem::path
274 return dcp::String::compose("build/test/verify_test%1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", n);
278 boost::filesystem::path
281 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
285 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
287 vector<boost::filesystem::path> directories = setup (1, n);
291 e.replace (from, to);
294 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
298 BOOST_REQUIRE_EQUAL (notes.size(), 1);
299 BOOST_CHECK_EQUAL (notes.front().code(), code1);
303 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1, dcp::VerificationNote::Code code2)
305 vector<boost::filesystem::path> directories = setup (1, n);
309 e.replace (from, to);
312 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
316 BOOST_REQUIRE_EQUAL (notes.size(), 2);
317 BOOST_CHECK_EQUAL (notes.front().code(), code1);
318 BOOST_CHECK_EQUAL (notes.back().code(), code2);
322 void check_after_replace (
323 int n, boost::function<boost::filesystem::path (int)> file,
326 dcp::VerificationNote::Code code1,
327 dcp::VerificationNote::Code code2,
328 dcp::VerificationNote::Code code3
331 vector<boost::filesystem::path> directories = setup (1, n);
335 e.replace (from, to);
338 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
342 BOOST_REQUIRE_EQUAL (notes.size(), 3);
343 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
344 BOOST_CHECK_EQUAL (i->code(), code1);
346 BOOST_CHECK_EQUAL (i->code(), code2);
348 BOOST_CHECK_EQUAL (i->code(), code3);
352 BOOST_AUTO_TEST_CASE (verify_test5)
354 check_after_replace (
356 "<FrameRate>24 1", "<FrameRate>99 1",
357 dcp::VerificationNote::CPL_HASH_INCORRECT,
358 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
363 BOOST_AUTO_TEST_CASE (verify_test6)
365 vector<boost::filesystem::path> directories = setup (1, 6);
367 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
368 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
370 BOOST_REQUIRE_EQUAL (notes.size(), 1);
371 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
372 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
376 boost::filesystem::path
379 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
382 /* Empty asset filename in ASSETMAP */
383 BOOST_AUTO_TEST_CASE (verify_test7)
385 check_after_replace (
387 "<Path>video.mxf</Path>", "<Path></Path>",
388 dcp::VerificationNote::EMPTY_ASSET_PATH
392 /* Mismatched standard */
393 BOOST_AUTO_TEST_CASE (verify_test8)
395 check_after_replace (
397 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
398 dcp::VerificationNote::MISMATCHED_STANDARD,
399 dcp::VerificationNote::XML_VALIDATION_ERROR,
400 dcp::VerificationNote::CPL_HASH_INCORRECT
404 /* Badly formatted <Id> in CPL */
405 BOOST_AUTO_TEST_CASE (verify_test9)
407 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
408 check_after_replace (
410 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
411 dcp::VerificationNote::XML_VALIDATION_ERROR
415 /* Badly formatted <IssueDate> in CPL */
416 BOOST_AUTO_TEST_CASE (verify_test10)
418 check_after_replace (
420 "<IssueDate>", "<IssueDate>x",
421 dcp::VerificationNote::XML_VALIDATION_ERROR,
422 dcp::VerificationNote::CPL_HASH_INCORRECT
426 /* Badly-formatted <Id> in PKL */
427 BOOST_AUTO_TEST_CASE (verify_test11)
429 check_after_replace (
431 "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
432 dcp::VerificationNote::XML_VALIDATION_ERROR
436 /* Badly-formatted <Id> in ASSETMAP */
437 BOOST_AUTO_TEST_CASE (verify_test12)
439 check_after_replace (
441 "<Id>urn:uuid:74e", "<Id>urn:uuid:x4e",
442 dcp::VerificationNote::XML_VALIDATION_ERROR
446 /* Basic test of an Interop DCP */
447 BOOST_AUTO_TEST_CASE (verify_test13)
450 vector<boost::filesystem::path> directories = setup (3, 13);
451 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
453 boost::filesystem::path const cpl_file = "build/test/verify_test13/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
454 boost::filesystem::path const pkl_file = "build/test/verify_test13/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
455 boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
457 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
458 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
459 BOOST_REQUIRE (st->second);
460 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13"));
462 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
463 BOOST_REQUIRE (st->second);
464 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
466 BOOST_CHECK_EQUAL (st->first, "Checking reel");
467 BOOST_REQUIRE (!st->second);
469 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
470 BOOST_REQUIRE (st->second);
471 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
473 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
474 BOOST_REQUIRE (st->second);
475 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
477 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
478 BOOST_REQUIRE (st->second);
479 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
481 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
482 BOOST_REQUIRE (st->second);
483 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
485 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
486 BOOST_REQUIRE (st->second);
487 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
489 BOOST_REQUIRE (st == stages.end());
493 BOOST_CHECK_EQUAL (notes.size(), 0);
496 /* DCP with a short asset */
497 BOOST_AUTO_TEST_CASE (verify_test14)
499 vector<boost::filesystem::path> directories = setup (8, 14);
500 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
504 BOOST_REQUIRE_EQUAL (notes.size(), 4);
505 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
506 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
508 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
510 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
512 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
518 shared_ptr<dcp::OpenJPEGImage>
521 shared_ptr<dcp::OpenJPEGImage> image(new dcp::OpenJPEGImage(dcp::Size(1998, 1080)));
522 int const pixels = 1998 * 1080;
523 for (int i = 0; i < 3; ++i) {
524 memset (image->data(i), 0, pixels * sizeof(int));
532 dcp_from_frame (dcp::Data const& frame, boost::filesystem::path dir)
534 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
535 boost::filesystem::create_directories (dir);
536 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
537 for (int i = 0; i < 24; ++i) {
538 writer->write (frame.data().get(), frame.size());
542 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
543 shared_ptr<dcp::Reel> reel(new dcp::Reel());
544 reel->add (reel_asset);
545 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
547 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
549 dcp->write_xml (dcp::SMPTE);
553 /* DCP with an over-sized JPEG2000 frame */
554 BOOST_AUTO_TEST_CASE (verify_test15)
556 int const too_big = 1302083 * 2;
558 /* Compress a black image */
559 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
560 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
561 BOOST_REQUIRE (frame.size() < too_big);
563 /* Place it in a bigger block with some zero padding at the end */
564 dcp::Data oversized_frame(too_big);
565 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
566 memset (oversized_frame.data().get() + frame.size(), 0, too_big - frame.size());
568 boost::filesystem::path const dir("build/test/verify_test15");
569 boost::filesystem::remove_all (dir);
570 dcp_from_frame (oversized_frame, dir);
572 vector<boost::filesystem::path> dirs;
573 dirs.push_back (dir);
574 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
575 BOOST_REQUIRE_EQUAL (notes.size(), 1);
576 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
580 /* DCP with a nearly over-sized JPEG2000 frame */
581 BOOST_AUTO_TEST_CASE (verify_test16)
583 int const nearly_too_big = 1302083 * 0.98;
585 /* Compress a black image */
586 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
587 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
588 BOOST_REQUIRE (frame.size() < nearly_too_big);
590 /* Place it in a bigger block with some zero padding at the end */
591 dcp::Data oversized_frame(nearly_too_big);
592 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
593 memset (oversized_frame.data().get() + frame.size(), 0, nearly_too_big - frame.size());
595 boost::filesystem::path const dir("build/test/verify_test16");
596 boost::filesystem::remove_all (dir);
597 dcp_from_frame (oversized_frame, dir);
599 vector<boost::filesystem::path> dirs;
600 dirs.push_back (dir);
601 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
602 BOOST_REQUIRE_EQUAL (notes.size(), 1);
603 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
607 /* DCP with a within-range JPEG2000 frame */
608 BOOST_AUTO_TEST_CASE (verify_test17)
610 /* Compress a black image */
611 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
612 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
613 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
615 boost::filesystem::path const dir("build/test/verify_test17");
616 boost::filesystem::remove_all (dir);
617 dcp_from_frame (frame, dir);
619 vector<boost::filesystem::path> dirs;
620 dirs.push_back (dir);
621 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
622 BOOST_REQUIRE_EQUAL (notes.size(), 0);
626 /* DCP with valid Interop subtitles */
627 BOOST_AUTO_TEST_CASE (verify_test18)
629 boost::filesystem::path const dir("build/test/verify_test18");
630 boost::filesystem::remove_all (dir);
631 boost::filesystem::create_directories (dir);
632 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
633 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
634 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
635 shared_ptr<dcp::Reel> reel(new dcp::Reel());
636 reel->add (reel_asset);
637 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
639 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
641 dcp->write_xml (dcp::INTEROP);
643 vector<boost::filesystem::path> dirs;
644 dirs.push_back (dir);
645 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
646 BOOST_REQUIRE_EQUAL (notes.size(), 0);
650 /* DCP with broken Interop subtitles */
651 BOOST_AUTO_TEST_CASE (verify_test19)
653 boost::filesystem::path const dir("build/test/verify_test19");
654 boost::filesystem::remove_all (dir);
655 boost::filesystem::create_directories (dir);
656 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
657 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
658 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
659 shared_ptr<dcp::Reel> reel(new dcp::Reel());
660 reel->add (reel_asset);
661 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
663 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
665 dcp->write_xml (dcp::INTEROP);
668 Editor e (dir / "subs.xml");
669 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
672 vector<boost::filesystem::path> dirs;
673 dirs.push_back (dir);
674 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
676 BOOST_REQUIRE_EQUAL (notes.size(), 2);
677 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
678 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
682 /* DCP with valid SMPTE subtitles */
683 BOOST_AUTO_TEST_CASE (verify_test20)
685 boost::filesystem::path const dir("build/test/verify_test20");
686 boost::filesystem::remove_all (dir);
687 boost::filesystem::create_directories (dir);
688 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
689 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
690 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
691 shared_ptr<dcp::Reel> reel(new dcp::Reel());
692 reel->add (reel_asset);
693 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
695 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
697 dcp->write_xml (dcp::SMPTE);
699 vector<boost::filesystem::path> dirs;
700 dirs.push_back (dir);
701 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
703 BOOST_REQUIRE_EQUAL (notes.size(), 0);
707 /* DCP with broken SMPTE subtitles */
708 BOOST_AUTO_TEST_CASE (verify_test21)
710 boost::filesystem::path const dir("build/test/verify_test21");
711 boost::filesystem::remove_all (dir);
712 boost::filesystem::create_directories (dir);
713 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
714 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
715 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
716 shared_ptr<dcp::Reel> reel(new dcp::Reel());
717 reel->add (reel_asset);
718 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
720 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
722 dcp->write_xml (dcp::SMPTE);
724 vector<boost::filesystem::path> dirs;
725 dirs.push_back (dir);
726 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
728 BOOST_REQUIRE_EQUAL (notes.size(), 2);
729 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
730 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
735 BOOST_AUTO_TEST_CASE (verify_test22)
737 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
738 boost::filesystem::remove_all (ov_dir);
739 boost::filesystem::create_directories (ov_dir);
741 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
742 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
743 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
744 dcp_from_frame (frame, ov_dir);
746 dcp::DCP ov (ov_dir);
749 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
750 boost::filesystem::remove_all (vf_dir);
751 boost::filesystem::create_directories (vf_dir);
753 shared_ptr<dcp::Reel> reel(new dcp::Reel());
754 reel->add (ov.cpls().front()->reels().front()->main_picture());
755 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
757 dcp::DCP vf (vf_dir);
759 vf.write_xml (dcp::SMPTE);
761 vector<boost::filesystem::path> dirs;
762 dirs.push_back (vf_dir);
763 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
765 BOOST_REQUIRE_EQUAL (notes.size(), 1);
766 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);