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;
65 static int next_verify_test_number = 1;
68 stage (string s, optional<boost::filesystem::path> p)
70 stages.push_back (make_pair (s, p));
79 static vector<boost::filesystem::path>
80 setup (int reference_number, int verify_test_number)
82 boost::filesystem::remove_all (dcp::String::compose("build/test/verify_test%1", verify_test_number));
83 boost::filesystem::create_directory (dcp::String::compose("build/test/verify_test%1", verify_test_number));
84 for (boost::filesystem::directory_iterator i(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number)); i != boost::filesystem::directory_iterator(); ++i) {
85 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", verify_test_number) / i->path().filename());
88 vector<boost::filesystem::path> directories;
89 directories.push_back (dcp::String::compose("build/test/verify_test%1", verify_test_number));
95 /** Class that can alter a file by searching and replacing strings within it.
96 * On destruction modifies the file whose name was given to the constructor.
101 Editor (boost::filesystem::path path)
104 _content = dcp::file_to_string (_path);
109 FILE* f = fopen(_path.string().c_str(), "w");
111 fwrite (_content.c_str(), _content.length(), 1, f);
115 void replace (string a, string b)
117 boost::algorithm::replace_all (_content, a, b);
121 boost::filesystem::path _path;
122 std::string _content;
127 dump_notes (list<dcp::VerificationNote> const & notes)
129 BOOST_FOREACH (dcp::VerificationNote i, notes) {
130 std::cout << dcp::note_to_string(i) << "\n";
134 /* Check DCP as-is (should be OK) */
135 BOOST_AUTO_TEST_CASE (verify_test1)
138 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number);
139 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
141 boost::filesystem::path const cpl_file = dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", next_verify_test_number);
142 boost::filesystem::path const pkl_file = dcp::String::compose("build/test/verify_test1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", next_verify_test_number);
143 boost::filesystem::path const assetmap_file = dcp::String::compose("build/test/verify_test1/ASSETMAP.xml", next_verify_test_number);
145 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
146 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
147 BOOST_REQUIRE (st->second);
148 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1", next_verify_test_number)));
150 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
151 BOOST_REQUIRE (st->second);
152 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
154 BOOST_CHECK_EQUAL (st->first, "Checking reel");
155 BOOST_REQUIRE (!st->second);
157 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
158 BOOST_REQUIRE (st->second);
159 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/video.mxf", next_verify_test_number)));
161 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
162 BOOST_REQUIRE (st->second);
163 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/video.mxf", next_verify_test_number)));
165 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
166 BOOST_REQUIRE (st->second);
167 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/audio.mxf", next_verify_test_number)));
169 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
170 BOOST_REQUIRE (st->second);
171 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
173 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
174 BOOST_REQUIRE (st->second);
175 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
177 BOOST_REQUIRE (st == stages.end());
181 BOOST_CHECK_EQUAL (notes.size(), 0);
183 next_verify_test_number++;
186 /* Corrupt the MXFs and check that this is spotted */
187 BOOST_AUTO_TEST_CASE (verify_test2)
189 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
191 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
193 fseek (mod, 4096, SEEK_SET);
195 fwrite (&x, sizeof(x), 1, mod);
198 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
200 fseek (mod, 4096, SEEK_SET);
201 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
204 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
206 BOOST_REQUIRE_EQUAL (notes.size(), 2);
207 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
208 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
209 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
210 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
213 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
214 BOOST_AUTO_TEST_CASE (verify_test3)
216 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
219 Editor e ("build/test/verify_test3/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml");
220 e.replace ("<Hash>", "<Hash>x");
223 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
227 BOOST_REQUIRE_EQUAL (notes.size(), 6);
228 list<dcp::VerificationNote>::const_iterator i = notes.begin();
229 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
230 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
232 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
233 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
235 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
236 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
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);
244 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
245 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
249 /* Corrupt the ContentKind in the CPL */
250 BOOST_AUTO_TEST_CASE (verify_test4)
252 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
255 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
256 e.replace ("<ContentKind>", "<ContentKind>x");
259 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
261 BOOST_REQUIRE_EQUAL (notes.size(), 1);
262 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
263 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
267 boost::filesystem::path
270 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
274 boost::filesystem::path
277 return dcp::String::compose("build/test/verify_test%1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", n);
281 boost::filesystem::path
284 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
288 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
290 vector<boost::filesystem::path> directories = setup (1, n);
294 e.replace (from, to);
297 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
301 BOOST_REQUIRE_EQUAL (notes.size(), 1);
302 BOOST_CHECK_EQUAL (notes.front().code(), code1);
306 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)
308 vector<boost::filesystem::path> directories = setup (1, n);
312 e.replace (from, to);
315 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
319 BOOST_REQUIRE_EQUAL (notes.size(), 2);
320 BOOST_CHECK_EQUAL (notes.front().code(), code1);
321 BOOST_CHECK_EQUAL (notes.back().code(), code2);
325 void check_after_replace (
326 int n, boost::function<boost::filesystem::path (int)> file,
329 dcp::VerificationNote::Code code1,
330 dcp::VerificationNote::Code code2,
331 dcp::VerificationNote::Code code3
334 vector<boost::filesystem::path> directories = setup (1, n);
338 e.replace (from, to);
341 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
345 BOOST_REQUIRE_EQUAL (notes.size(), 3);
346 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
347 BOOST_CHECK_EQUAL (i->code(), code1);
349 BOOST_CHECK_EQUAL (i->code(), code2);
351 BOOST_CHECK_EQUAL (i->code(), code3);
355 BOOST_AUTO_TEST_CASE (verify_test5)
357 check_after_replace (
358 next_verify_test_number++, &cpl,
359 "<FrameRate>24 1", "<FrameRate>99 1",
360 dcp::VerificationNote::CPL_HASH_INCORRECT,
361 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
366 BOOST_AUTO_TEST_CASE (verify_test6)
368 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
370 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
371 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
373 BOOST_REQUIRE_EQUAL (notes.size(), 1);
374 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
375 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
379 boost::filesystem::path
382 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
385 /* Empty asset filename in ASSETMAP */
386 BOOST_AUTO_TEST_CASE (verify_test7)
388 check_after_replace (
389 next_verify_test_number++, &assetmap,
390 "<Path>video.mxf</Path>", "<Path></Path>",
391 dcp::VerificationNote::EMPTY_ASSET_PATH
395 /* Mismatched standard */
396 BOOST_AUTO_TEST_CASE (verify_test8)
398 check_after_replace (
399 next_verify_test_number++, &cpl,
400 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
401 dcp::VerificationNote::MISMATCHED_STANDARD,
402 dcp::VerificationNote::XML_VALIDATION_ERROR,
403 dcp::VerificationNote::CPL_HASH_INCORRECT
407 /* Badly formatted <Id> in CPL */
408 BOOST_AUTO_TEST_CASE (verify_test9)
410 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
411 check_after_replace (
412 next_verify_test_number++, &cpl,
413 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
414 dcp::VerificationNote::XML_VALIDATION_ERROR
418 /* Badly formatted <IssueDate> in CPL */
419 BOOST_AUTO_TEST_CASE (verify_test10)
421 check_after_replace (
422 next_verify_test_number++, &cpl,
423 "<IssueDate>", "<IssueDate>x",
424 dcp::VerificationNote::XML_VALIDATION_ERROR,
425 dcp::VerificationNote::CPL_HASH_INCORRECT
429 /* Badly-formatted <Id> in PKL */
430 BOOST_AUTO_TEST_CASE (verify_test11)
432 check_after_replace (
433 next_verify_test_number++, &pkl,
434 "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
435 dcp::VerificationNote::XML_VALIDATION_ERROR
439 /* Badly-formatted <Id> in ASSETMAP */
440 BOOST_AUTO_TEST_CASE (verify_test12)
442 check_after_replace (
443 next_verify_test_number++, &asset_map,
444 "<Id>urn:uuid:74e", "<Id>urn:uuid:x4e",
445 dcp::VerificationNote::XML_VALIDATION_ERROR
449 /* Basic test of an Interop DCP */
450 BOOST_AUTO_TEST_CASE (verify_test13)
453 vector<boost::filesystem::path> directories = setup (3, next_verify_test_number);
454 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
456 boost::filesystem::path const cpl_file = dcp::String::compose("build/test/verify_test%1/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml", next_verify_test_number);
457 boost::filesystem::path const pkl_file = dcp::String::compose("build/test/verify_test%1/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml", next_verify_test_number);
458 boost::filesystem::path const assetmap_file = dcp::String::compose("build/test/verify_test%1/ASSETMAP", next_verify_test_number);
460 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
461 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
462 BOOST_REQUIRE (st->second);
463 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1", next_verify_test_number)));
465 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
466 BOOST_REQUIRE (st->second);
467 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
469 BOOST_CHECK_EQUAL (st->first, "Checking reel");
470 BOOST_REQUIRE (!st->second);
472 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
473 BOOST_REQUIRE (st->second);
474 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf", next_verify_test_number)));
476 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
477 BOOST_REQUIRE (st->second);
478 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf", next_verify_test_number)));
480 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
481 BOOST_REQUIRE (st->second);
482 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf", next_verify_test_number)));
484 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
485 BOOST_REQUIRE (st->second);
486 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
488 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
489 BOOST_REQUIRE (st->second);
490 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
492 BOOST_REQUIRE (st == stages.end());
496 BOOST_CHECK_EQUAL (notes.size(), 0);
498 next_verify_test_number++;
501 /* DCP with a short asset */
502 BOOST_AUTO_TEST_CASE (verify_test14)
504 vector<boost::filesystem::path> directories = setup (8, next_verify_test_number);
505 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
509 BOOST_REQUIRE_EQUAL (notes.size(), 4);
510 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
511 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
513 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
515 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
517 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
519 next_verify_test_number++;
524 shared_ptr<dcp::OpenJPEGImage>
527 shared_ptr<dcp::OpenJPEGImage> image(new dcp::OpenJPEGImage(dcp::Size(1998, 1080)));
528 int const pixels = 1998 * 1080;
529 for (int i = 0; i < 3; ++i) {
530 memset (image->data(i), 0, pixels * sizeof(int));
538 dcp_from_frame (dcp::Data const& frame, boost::filesystem::path dir)
540 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
541 boost::filesystem::create_directories (dir);
542 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
543 for (int i = 0; i < 24; ++i) {
544 writer->write (frame.data().get(), frame.size());
548 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
549 shared_ptr<dcp::Reel> reel(new dcp::Reel());
550 reel->add (reel_asset);
551 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
553 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
555 dcp->write_xml (dcp::SMPTE);
559 /* DCP with an over-sized JPEG2000 frame */
560 BOOST_AUTO_TEST_CASE (verify_test15)
562 int const too_big = 1302083 * 2;
564 /* Compress a black image */
565 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
566 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
567 BOOST_REQUIRE (frame.size() < too_big);
569 /* Place it in a bigger block with some zero padding at the end */
570 dcp::Data oversized_frame(too_big);
571 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
572 memset (oversized_frame.data().get() + frame.size(), 0, too_big - frame.size());
574 boost::filesystem::path const dir("build/test/verify_test15");
575 boost::filesystem::remove_all (dir);
576 dcp_from_frame (oversized_frame, dir);
578 vector<boost::filesystem::path> dirs;
579 dirs.push_back (dir);
580 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
581 BOOST_REQUIRE_EQUAL (notes.size(), 1);
582 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
586 /* DCP with a nearly over-sized JPEG2000 frame */
587 BOOST_AUTO_TEST_CASE (verify_test16)
589 int const nearly_too_big = 1302083 * 0.98;
591 /* Compress a black image */
592 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
593 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
594 BOOST_REQUIRE (frame.size() < nearly_too_big);
596 /* Place it in a bigger block with some zero padding at the end */
597 dcp::Data oversized_frame(nearly_too_big);
598 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
599 memset (oversized_frame.data().get() + frame.size(), 0, nearly_too_big - frame.size());
601 boost::filesystem::path const dir("build/test/verify_test16");
602 boost::filesystem::remove_all (dir);
603 dcp_from_frame (oversized_frame, dir);
605 vector<boost::filesystem::path> dirs;
606 dirs.push_back (dir);
607 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
608 BOOST_REQUIRE_EQUAL (notes.size(), 1);
609 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
613 /* DCP with a within-range JPEG2000 frame */
614 BOOST_AUTO_TEST_CASE (verify_test17)
616 /* Compress a black image */
617 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
618 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
619 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
621 boost::filesystem::path const dir("build/test/verify_test17");
622 boost::filesystem::remove_all (dir);
623 dcp_from_frame (frame, dir);
625 vector<boost::filesystem::path> dirs;
626 dirs.push_back (dir);
627 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
628 BOOST_REQUIRE_EQUAL (notes.size(), 0);
632 /* DCP with valid Interop subtitles */
633 BOOST_AUTO_TEST_CASE (verify_test18)
635 boost::filesystem::path const dir("build/test/verify_test18");
636 boost::filesystem::remove_all (dir);
637 boost::filesystem::create_directories (dir);
638 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
639 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
640 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
641 shared_ptr<dcp::Reel> reel(new dcp::Reel());
642 reel->add (reel_asset);
643 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
645 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
647 dcp->write_xml (dcp::INTEROP);
649 vector<boost::filesystem::path> dirs;
650 dirs.push_back (dir);
651 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
652 BOOST_REQUIRE_EQUAL (notes.size(), 0);
656 /* DCP with broken Interop subtitles */
657 BOOST_AUTO_TEST_CASE (verify_test19)
659 boost::filesystem::path const dir("build/test/verify_test19");
660 boost::filesystem::remove_all (dir);
661 boost::filesystem::create_directories (dir);
662 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
663 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
664 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
665 shared_ptr<dcp::Reel> reel(new dcp::Reel());
666 reel->add (reel_asset);
667 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
669 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
671 dcp->write_xml (dcp::INTEROP);
674 Editor e (dir / "subs.xml");
675 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
678 vector<boost::filesystem::path> dirs;
679 dirs.push_back (dir);
680 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
682 BOOST_REQUIRE_EQUAL (notes.size(), 2);
683 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
684 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
688 /* DCP with valid SMPTE subtitles */
689 BOOST_AUTO_TEST_CASE (verify_test20)
691 boost::filesystem::path const dir("build/test/verify_test20");
692 boost::filesystem::remove_all (dir);
693 boost::filesystem::create_directories (dir);
694 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
695 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
696 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
697 shared_ptr<dcp::Reel> reel(new dcp::Reel());
698 reel->add (reel_asset);
699 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
701 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
703 dcp->write_xml (dcp::SMPTE);
705 vector<boost::filesystem::path> dirs;
706 dirs.push_back (dir);
707 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
709 BOOST_REQUIRE_EQUAL (notes.size(), 0);
713 /* DCP with broken SMPTE subtitles */
714 BOOST_AUTO_TEST_CASE (verify_test21)
716 boost::filesystem::path const dir("build/test/verify_test21");
717 boost::filesystem::remove_all (dir);
718 boost::filesystem::create_directories (dir);
719 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
720 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
721 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
722 shared_ptr<dcp::Reel> reel(new dcp::Reel());
723 reel->add (reel_asset);
724 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
726 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
728 dcp->write_xml (dcp::SMPTE);
730 vector<boost::filesystem::path> dirs;
731 dirs.push_back (dir);
732 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
734 BOOST_REQUIRE_EQUAL (notes.size(), 2);
735 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
736 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
741 BOOST_AUTO_TEST_CASE (verify_test22)
743 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
744 boost::filesystem::remove_all (ov_dir);
745 boost::filesystem::create_directories (ov_dir);
747 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
748 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
749 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
750 dcp_from_frame (frame, ov_dir);
752 dcp::DCP ov (ov_dir);
755 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
756 boost::filesystem::remove_all (vf_dir);
757 boost::filesystem::create_directories (vf_dir);
759 shared_ptr<dcp::Reel> reel(new dcp::Reel());
760 reel->add (ov.cpls().front()->reels().front()->main_picture());
761 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
763 dcp::DCP vf (vf_dir);
765 vf.write_xml (dcp::SMPTE);
767 vector<boost::filesystem::path> dirs;
768 dirs.push_back (vf_dir);
769 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
771 BOOST_REQUIRE_EQUAL (notes.size(), 1);
772 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);