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"
39 #include "reel_sound_asset.h"
42 #include "openjpeg_image.h"
43 #include "mono_picture_asset.h"
44 #include "stereo_picture_asset.h"
45 #include "mono_picture_asset_writer.h"
46 #include "interop_subtitle_asset.h"
47 #include "smpte_subtitle_asset.h"
48 #include "reel_closed_caption_asset.h"
49 #include "reel_stereo_picture_asset.h"
50 #include "reel_subtitle_asset.h"
51 #include "compose.hpp"
53 #include <boost/test/unit_test.hpp>
54 #include <boost/foreach.hpp>
55 #include <boost/algorithm/string.hpp>
64 using boost::optional;
65 using std::shared_ptr;
68 static list<pair<string, optional<boost::filesystem::path> > > stages;
71 stage (string s, optional<boost::filesystem::path> p)
73 stages.push_back (make_pair (s, p));
83 prepare_directory (boost::filesystem::path path)
85 using namespace boost::filesystem;
87 create_directories (path);
91 static vector<boost::filesystem::path>
92 setup (int reference_number, int verify_test_number)
94 prepare_directory (dcp::String::compose("build/test/verify_test%1", verify_test_number));
95 for (boost::filesystem::directory_iterator i(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number)); i != boost::filesystem::directory_iterator(); ++i) {
96 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", verify_test_number) / i->path().filename());
99 vector<boost::filesystem::path> directories;
100 directories.push_back (dcp::String::compose("build/test/verify_test%1", verify_test_number));
106 /** Class that can alter a file by searching and replacing strings within it.
107 * On destruction modifies the file whose name was given to the constructor.
112 Editor (boost::filesystem::path path)
115 _content = dcp::file_to_string (_path);
120 FILE* f = fopen(_path.string().c_str(), "w");
122 fwrite (_content.c_str(), _content.length(), 1, f);
126 void replace (string a, string b)
128 boost::algorithm::replace_all (_content, a, b);
132 boost::filesystem::path _path;
133 std::string _content;
139 dump_notes (list<dcp::VerificationNote> const & notes)
141 BOOST_FOREACH (dcp::VerificationNote i, notes) {
142 std::cout << dcp::note_to_string(i) << "\n";
146 /* Check DCP as-is (should be OK) */
147 BOOST_AUTO_TEST_CASE (verify_test1)
150 vector<boost::filesystem::path> directories = setup (1, 1);
151 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
153 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
154 boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml";
155 boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
157 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
158 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
159 BOOST_REQUIRE (st->second);
160 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
162 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
163 BOOST_REQUIRE (st->second);
164 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
166 BOOST_CHECK_EQUAL (st->first, "Checking reel");
167 BOOST_REQUIRE (!st->second);
169 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
170 BOOST_REQUIRE (st->second);
171 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
173 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
174 BOOST_REQUIRE (st->second);
175 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
177 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
178 BOOST_REQUIRE (st->second);
179 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
181 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
182 BOOST_REQUIRE (st->second);
183 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
185 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
186 BOOST_REQUIRE (st->second);
187 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
189 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
190 BOOST_REQUIRE (st->second);
191 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
193 BOOST_REQUIRE (st == stages.end());
195 BOOST_CHECK_EQUAL (notes.size(), 0);
198 /* Corrupt the MXFs and check that this is spotted */
199 BOOST_AUTO_TEST_CASE (verify_test2)
201 vector<boost::filesystem::path> directories = setup (1, 2);
203 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
205 fseek (mod, 4096, SEEK_SET);
207 fwrite (&x, sizeof(x), 1, mod);
210 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
212 BOOST_REQUIRE_EQUAL (fseek(mod, -64, SEEK_END), 0);
213 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
216 list<dcp::VerificationNote> notes;
218 dcp::ASDCPErrorSuspender sus;
219 notes = dcp::verify (directories, &stage, &progress, xsd_test);
222 BOOST_REQUIRE_EQUAL (notes.size(), 2);
223 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
224 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
225 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
226 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
229 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
230 BOOST_AUTO_TEST_CASE (verify_test3)
232 vector<boost::filesystem::path> directories = setup (1, 3);
235 Editor e ("build/test/verify_test3/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml");
236 e.replace ("<Hash>", "<Hash>x");
239 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
241 BOOST_REQUIRE_EQUAL (notes.size(), 6);
242 list<dcp::VerificationNote>::const_iterator i = notes.begin();
243 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
244 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
246 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
247 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DIFFER);
249 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
250 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DIFFER);
252 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
253 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
255 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
256 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
258 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
259 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
263 /* Corrupt the ContentKind in the CPL */
264 BOOST_AUTO_TEST_CASE (verify_test4)
266 vector<boost::filesystem::path> directories = setup (1, 4);
269 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
270 e.replace ("<ContentKind>", "<ContentKind>x");
273 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
275 BOOST_REQUIRE_EQUAL (notes.size(), 1);
276 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
277 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
281 boost::filesystem::path
284 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
288 boost::filesystem::path
291 return dcp::String::compose("build/test/verify_test%1/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml", n);
295 boost::filesystem::path
298 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
302 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
304 vector<boost::filesystem::path> directories = setup (1, n);
308 e.replace (from, to);
311 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
313 BOOST_REQUIRE_EQUAL (notes.size(), 1);
314 BOOST_CHECK_EQUAL (notes.front().code(), code1);
318 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)
320 vector<boost::filesystem::path> directories = setup (1, n);
324 e.replace (from, to);
327 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
329 BOOST_REQUIRE_EQUAL (notes.size(), 2);
330 BOOST_CHECK_EQUAL (notes.front().code(), code1);
331 BOOST_CHECK_EQUAL (notes.back().code(), code2);
335 void check_after_replace (
336 int n, boost::function<boost::filesystem::path (int)> file,
339 dcp::VerificationNote::Code code1,
340 dcp::VerificationNote::Code code2,
341 dcp::VerificationNote::Code code3
344 vector<boost::filesystem::path> directories = setup (1, n);
348 e.replace (from, to);
351 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
353 BOOST_REQUIRE_EQUAL (notes.size(), 3);
354 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
355 BOOST_CHECK_EQUAL (i->code(), code1);
357 BOOST_CHECK_EQUAL (i->code(), code2);
359 BOOST_CHECK_EQUAL (i->code(), code3);
363 BOOST_AUTO_TEST_CASE (verify_test5)
365 check_after_replace (
367 "<FrameRate>24 1", "<FrameRate>99 1",
368 dcp::VerificationNote::CPL_HASH_INCORRECT,
369 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
374 BOOST_AUTO_TEST_CASE (verify_test6)
376 vector<boost::filesystem::path> directories = setup (1, 6);
378 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
379 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
381 BOOST_REQUIRE_EQUAL (notes.size(), 1);
382 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
383 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
387 boost::filesystem::path
390 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
393 /* Empty asset filename in ASSETMAP */
394 BOOST_AUTO_TEST_CASE (verify_test7)
396 check_after_replace (
398 "<Path>video.mxf</Path>", "<Path></Path>",
399 dcp::VerificationNote::EMPTY_ASSET_PATH
403 /* Mismatched standard */
404 BOOST_AUTO_TEST_CASE (verify_test8)
406 check_after_replace (
408 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
409 dcp::VerificationNote::MISMATCHED_STANDARD,
410 dcp::VerificationNote::XML_VALIDATION_ERROR,
411 dcp::VerificationNote::CPL_HASH_INCORRECT
415 /* Badly formatted <Id> in CPL */
416 BOOST_AUTO_TEST_CASE (verify_test9)
418 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
419 check_after_replace (
421 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
422 dcp::VerificationNote::XML_VALIDATION_ERROR
426 /* Badly formatted <IssueDate> in CPL */
427 BOOST_AUTO_TEST_CASE (verify_test10)
429 check_after_replace (
431 "<IssueDate>", "<IssueDate>x",
432 dcp::VerificationNote::XML_VALIDATION_ERROR,
433 dcp::VerificationNote::CPL_HASH_INCORRECT
437 /* Badly-formatted <Id> in PKL */
438 BOOST_AUTO_TEST_CASE (verify_test11)
440 check_after_replace (
442 "<Id>urn:uuid:cd4", "<Id>urn:uuid:xd4",
443 dcp::VerificationNote::XML_VALIDATION_ERROR
447 /* Badly-formatted <Id> in ASSETMAP */
448 BOOST_AUTO_TEST_CASE (verify_test12)
450 check_after_replace (
452 "<Id>urn:uuid:63c", "<Id>urn:uuid:x3c",
453 dcp::VerificationNote::XML_VALIDATION_ERROR
457 /* Basic test of an Interop DCP */
458 BOOST_AUTO_TEST_CASE (verify_test13)
461 vector<boost::filesystem::path> directories = setup (3, 13);
462 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
464 boost::filesystem::path const cpl_file = "build/test/verify_test13/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
465 boost::filesystem::path const pkl_file = "build/test/verify_test13/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
466 boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
468 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
469 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
470 BOOST_REQUIRE (st->second);
471 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13"));
473 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
474 BOOST_REQUIRE (st->second);
475 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
477 BOOST_CHECK_EQUAL (st->first, "Checking reel");
478 BOOST_REQUIRE (!st->second);
480 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
481 BOOST_REQUIRE (st->second);
482 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
484 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
485 BOOST_REQUIRE (st->second);
486 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
488 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
489 BOOST_REQUIRE (st->second);
490 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
492 BOOST_CHECK_EQUAL (st->first, "Checking sound asset metadata");
493 BOOST_REQUIRE (st->second);
494 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
496 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
497 BOOST_REQUIRE (st->second);
498 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
500 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
501 BOOST_REQUIRE (st->second);
502 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
504 BOOST_REQUIRE (st == stages.end());
506 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
507 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
508 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
509 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
512 /* DCP with a short asset */
513 BOOST_AUTO_TEST_CASE (verify_test14)
515 vector<boost::filesystem::path> directories = setup (8, 14);
516 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
518 BOOST_REQUIRE_EQUAL (notes.size(), 5);
519 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
520 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
522 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
524 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
526 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
528 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
535 dcp_from_frame (dcp::ArrayData const& frame, boost::filesystem::path dir)
537 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
538 boost::filesystem::create_directories (dir);
539 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
540 for (int i = 0; i < 24; ++i) {
541 writer->write (frame.data(), frame.size());
545 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
546 shared_ptr<dcp::Reel> reel(new dcp::Reel());
547 reel->add (reel_asset);
548 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
550 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
552 dcp->write_xml (dcp::SMPTE);
556 /* DCP with an over-sized JPEG2000 frame */
557 BOOST_AUTO_TEST_CASE (verify_test15)
559 int const too_big = 1302083 * 2;
561 /* Compress a black image */
562 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
563 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
564 BOOST_REQUIRE (frame.size() < too_big);
566 /* Place it in a bigger block with some zero padding at the end */
567 dcp::ArrayData oversized_frame(too_big);
568 memcpy (oversized_frame.data(), frame.data(), frame.size());
569 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
571 boost::filesystem::path const dir("build/test/verify_test15");
572 boost::filesystem::remove_all (dir);
573 dcp_from_frame (oversized_frame, dir);
575 vector<boost::filesystem::path> dirs;
576 dirs.push_back (dir);
577 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
578 BOOST_REQUIRE_EQUAL (notes.size(), 1);
579 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE_IN_BYTES);
583 /* DCP with a nearly over-sized JPEG2000 frame */
584 BOOST_AUTO_TEST_CASE (verify_test16)
586 int const nearly_too_big = 1302083 * 0.98;
588 /* Compress a black image */
589 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
590 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
591 BOOST_REQUIRE (frame.size() < nearly_too_big);
593 /* Place it in a bigger block with some zero padding at the end */
594 dcp::ArrayData oversized_frame(nearly_too_big);
595 memcpy (oversized_frame.data(), frame.data(), frame.size());
596 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
598 boost::filesystem::path const dir("build/test/verify_test16");
599 boost::filesystem::remove_all (dir);
600 dcp_from_frame (oversized_frame, dir);
602 vector<boost::filesystem::path> dirs;
603 dirs.push_back (dir);
604 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
605 BOOST_REQUIRE_EQUAL (notes.size(), 1);
606 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE_IN_BYTES);
610 /* DCP with a within-range JPEG2000 frame */
611 BOOST_AUTO_TEST_CASE (verify_test17)
613 /* Compress a black image */
614 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
615 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
616 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
618 boost::filesystem::path const dir("build/test/verify_test17");
619 boost::filesystem::remove_all (dir);
620 dcp_from_frame (frame, dir);
622 vector<boost::filesystem::path> dirs;
623 dirs.push_back (dir);
624 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
625 BOOST_REQUIRE_EQUAL (notes.size(), 0);
629 /* DCP with valid Interop subtitles */
630 BOOST_AUTO_TEST_CASE (verify_test18)
632 boost::filesystem::path const dir("build/test/verify_test18");
633 prepare_directory (dir);
634 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
635 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
636 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
637 shared_ptr<dcp::Reel> reel(new dcp::Reel());
638 reel->add (reel_asset);
639 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
641 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
643 dcp->write_xml (dcp::INTEROP);
645 vector<boost::filesystem::path> dirs;
646 dirs.push_back (dir);
647 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
648 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
649 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
650 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
654 /* DCP with broken Interop subtitles */
655 BOOST_AUTO_TEST_CASE (verify_test19)
657 boost::filesystem::path const dir("build/test/verify_test19");
658 prepare_directory (dir);
659 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
660 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
661 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
662 shared_ptr<dcp::Reel> reel(new dcp::Reel());
663 reel->add (reel_asset);
664 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
666 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
668 dcp->write_xml (dcp::INTEROP);
671 Editor e (dir / "subs.xml");
672 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
675 vector<boost::filesystem::path> dirs;
676 dirs.push_back (dir);
677 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
678 BOOST_REQUIRE_EQUAL (notes.size(), 3);
679 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
680 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
682 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
684 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
689 /* DCP with valid SMPTE subtitles */
690 BOOST_AUTO_TEST_CASE (verify_test20)
692 boost::filesystem::path const dir("build/test/verify_test20");
693 prepare_directory (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 prepare_directory (dir);
718 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
719 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
720 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
721 shared_ptr<dcp::Reel> reel(new dcp::Reel());
722 reel->add (reel_asset);
723 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
725 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
727 dcp->write_xml (dcp::SMPTE);
729 vector<boost::filesystem::path> dirs;
730 dirs.push_back (dir);
731 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
732 BOOST_REQUIRE_EQUAL (notes.size(), 2);
733 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
734 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
739 BOOST_AUTO_TEST_CASE (verify_test22)
741 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
742 prepare_directory (ov_dir);
744 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
745 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
746 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
747 dcp_from_frame (frame, ov_dir);
749 dcp::DCP ov (ov_dir);
752 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
753 prepare_directory (vf_dir);
755 shared_ptr<dcp::Reel> reel(new dcp::Reel());
756 reel->add (ov.cpls().front()->reels().front()->main_picture());
757 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
759 dcp::DCP vf (vf_dir);
761 vf.write_xml (dcp::SMPTE);
763 vector<boost::filesystem::path> dirs;
764 dirs.push_back (vf_dir);
765 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
766 BOOST_REQUIRE_EQUAL (notes.size(), 1);
767 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);
771 /* DCP with valid CompositionMetadataAsset */
772 BOOST_AUTO_TEST_CASE (verify_test23)
774 boost::filesystem::path const dir("build/test/verify_test23");
775 prepare_directory (dir);
777 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
778 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
779 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
781 shared_ptr<dcp::Reel> reel(new dcp::Reel());
782 reel->add (reel_asset);
783 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
785 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
786 cpl->set_main_sound_sample_rate (48000);
787 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
788 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
792 dcp.write_xml (dcp::SMPTE);
794 vector<boost::filesystem::path> dirs;
795 dirs.push_back (dir);
796 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
800 boost::filesystem::path find_cpl (boost::filesystem::path dir)
802 for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); i++) {
803 if (boost::starts_with(i->path().filename().string(), "cpl_")) {
808 BOOST_REQUIRE (false);
809 return boost::filesystem::path();
813 /* DCP with invalid CompositionMetadataAsset */
814 BOOST_AUTO_TEST_CASE (verify_test24)
816 boost::filesystem::path const dir("build/test/verify_test24");
817 prepare_directory (dir);
819 shared_ptr<dcp::Reel> reel(new dcp::Reel());
820 reel->add (black_picture_asset(dir));
821 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
823 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
824 cpl->set_main_sound_sample_rate (48000);
825 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
826 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
830 dcp.write_xml (dcp::SMPTE);
833 Editor e (find_cpl("build/test/verify_test24"));
834 e.replace ("MainSound", "MainSoundX");
837 vector<boost::filesystem::path> dirs;
838 dirs.push_back (dir);
839 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
840 BOOST_REQUIRE_EQUAL (notes.size(), 4);
842 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
843 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
845 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
847 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
849 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
854 /* DCP with invalid CompositionMetadataAsset */
855 BOOST_AUTO_TEST_CASE (verify_test25)
857 boost::filesystem::path const dir("build/test/verify_test25");
858 prepare_directory (dir);
860 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
861 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
862 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
864 shared_ptr<dcp::Reel> reel(new dcp::Reel());
865 reel->add (reel_asset);
866 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
868 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
869 cpl->set_main_sound_sample_rate (48000);
870 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
871 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
875 dcp.write_xml (dcp::SMPTE);
878 Editor e (find_cpl("build/test/verify_test25"));
879 e.replace ("</MainPictureActiveArea>", "</MainPictureActiveArea><BadTag></BadTag>");
882 vector<boost::filesystem::path> dirs;
883 dirs.push_back (dir);
884 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
888 /* SMPTE DCP with invalid <Language> in the MainSubtitle reel and also in the XML within the MXF */
889 BOOST_AUTO_TEST_CASE (verify_test26)
891 boost::filesystem::path const dir("build/test/verify_test26");
892 prepare_directory (dir);
893 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
894 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
895 asset->_language = "wrong-andbad";
896 asset->write (dir / "subs.mxf");
897 shared_ptr<dcp::ReelSubtitleAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
898 reel_asset->_language = "badlang";
899 shared_ptr<dcp::Reel> reel(new dcp::Reel());
900 reel->add (reel_asset);
901 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
903 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
905 dcp->write_xml (dcp::SMPTE);
907 vector<boost::filesystem::path> dirs;
908 dirs.push_back (dir);
909 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
910 BOOST_REQUIRE_EQUAL (notes.size(), 2U);
911 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
912 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
913 BOOST_REQUIRE (i->note());
914 BOOST_CHECK_EQUAL (*i->note(), "badlang");
916 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
917 BOOST_REQUIRE (i->note());
918 BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
922 /* SMPTE DCP with invalid <Language> in the MainClosedCaption reel and also in the XML within the MXF */
923 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_languages)
925 boost::filesystem::path const dir("build/test/verify_invalid_closed_caption_languages");
926 prepare_directory (dir);
927 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
928 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
929 asset->_language = "wrong-andbad";
930 asset->write (dir / "subs.mxf");
931 shared_ptr<dcp::ReelClosedCaptionAsset> reel_asset(new dcp::ReelClosedCaptionAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
932 reel_asset->_language = "badlang";
933 shared_ptr<dcp::Reel> reel(new dcp::Reel());
934 reel->add (reel_asset);
935 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
937 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
939 dcp->write_xml (dcp::SMPTE);
941 vector<boost::filesystem::path> dirs;
942 dirs.push_back (dir);
943 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
944 BOOST_REQUIRE_EQUAL (notes.size(), 2U);
945 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
946 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
947 BOOST_REQUIRE (i->note());
948 BOOST_CHECK_EQUAL (*i->note(), "badlang");
950 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
951 BOOST_REQUIRE (i->note());
952 BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
956 /* SMPTE DCP with invalid <Language> in the MainSound reel, the CPL additional subtitles languages and
957 * the release territory.
959 BOOST_AUTO_TEST_CASE (verify_various_invalid_languages)
961 boost::filesystem::path const dir("build/test/verify_various_invalid_languages");
962 prepare_directory (dir);
964 shared_ptr<dcp::MonoPictureAsset> picture = simple_picture (dir, "foo");
965 shared_ptr<dcp::ReelPictureAsset> reel_picture(new dcp::ReelMonoPictureAsset(picture, 0));
966 shared_ptr<dcp::Reel> reel(new dcp::Reel());
967 reel->add (reel_picture);
968 shared_ptr<dcp::SoundAsset> sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "frobozz");
969 shared_ptr<dcp::ReelSoundAsset> reel_sound(new dcp::ReelSoundAsset(sound, 0));
970 reel->add (reel_sound);
971 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
973 cpl->_additional_subtitle_languages.push_back("this-is-wrong");
974 cpl->_additional_subtitle_languages.push_back("andso-is-this");
975 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
976 cpl->set_main_sound_sample_rate (48000);
977 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
978 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
979 cpl->_release_territory = "fred-jim";
980 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
982 dcp->write_xml (dcp::SMPTE);
984 vector<boost::filesystem::path> dirs;
985 dirs.push_back (dir);
986 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
987 BOOST_REQUIRE_EQUAL (notes.size(), 4U);
988 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
989 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
990 BOOST_REQUIRE (i->note());
991 BOOST_CHECK_EQUAL (*i->note(), "this-is-wrong");
993 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
994 BOOST_REQUIRE (i->note());
995 BOOST_CHECK_EQUAL (*i->note(), "andso-is-this");
997 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
998 BOOST_REQUIRE (i->note());
999 BOOST_CHECK_EQUAL (*i->note(), "fred-jim");
1001 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
1002 BOOST_REQUIRE (i->note());
1003 BOOST_CHECK_EQUAL (*i->note(), "frobozz");
1009 list<dcp::VerificationNote>
1010 check_picture_size (int width, int height, int frame_rate, bool three_d)
1012 using namespace boost::filesystem;
1014 path dcp_path = "build/test/verify_picture_test";
1015 remove_all (dcp_path);
1016 create_directories (dcp_path);
1018 shared_ptr<dcp::PictureAsset> mp;
1020 mp.reset (new dcp::StereoPictureAsset(dcp::Fraction(frame_rate, 1), dcp::SMPTE));
1022 mp.reset (new dcp::MonoPictureAsset(dcp::Fraction(frame_rate, 1), dcp::SMPTE));
1024 shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (dcp_path / "video.mxf", false);
1026 shared_ptr<dcp::OpenJPEGImage> image = black_image (dcp::Size(width, height));
1027 dcp::ArrayData j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048);
1028 int const length = three_d ? frame_rate * 2 : frame_rate;
1029 for (int i = 0; i < length; ++i) {
1030 picture_writer->write (j2c.data(), j2c.size());
1032 picture_writer->finalize ();
1034 shared_ptr<dcp::DCP> d (new dcp::DCP(dcp_path));
1035 shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::FEATURE));
1036 cpl->set_annotation_text ("A Test DCP");
1037 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
1039 shared_ptr<dcp::Reel> reel(new dcp::Reel());
1043 shared_ptr<dcp::ReelPictureAsset>(
1044 new dcp::ReelStereoPictureAsset(
1045 std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp),
1051 shared_ptr<dcp::ReelPictureAsset>(
1052 new dcp::ReelMonoPictureAsset(
1053 std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp),
1062 d->write_xml (dcp::SMPTE);
1064 vector<boost::filesystem::path> dirs;
1065 dirs.push_back (dcp_path);
1066 return dcp::verify (dirs, &stage, &progress, xsd_test);
1072 check_picture_size_ok (int width, int height, int frame_rate, bool three_d)
1074 list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d);
1076 BOOST_CHECK_EQUAL (notes.size(), 0U);
1082 check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d)
1084 list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d);
1085 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1086 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1087 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_SIZE_IN_PIXELS);
1093 check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d)
1095 list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d);
1096 BOOST_REQUIRE_EQUAL (notes.size(), 2U);
1097 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1098 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K);
1104 check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d)
1106 list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d);
1107 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1108 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1109 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K);
1113 BOOST_AUTO_TEST_CASE (verify_picture_size)
1115 using namespace boost::filesystem;
1118 check_picture_size_ok (2048, 858, 24, false);
1119 check_picture_size_ok (2048, 858, 25, false);
1120 check_picture_size_ok (2048, 858, 48, false);
1121 check_picture_size_ok (2048, 858, 24, true);
1122 check_picture_size_ok (2048, 858, 25, true);
1123 check_picture_size_ok (2048, 858, 48, true);
1126 check_picture_size_ok (1998, 1080, 24, false);
1127 check_picture_size_ok (1998, 1080, 25, false);
1128 check_picture_size_ok (1998, 1080, 48, false);
1129 check_picture_size_ok (1998, 1080, 24, true);
1130 check_picture_size_ok (1998, 1080, 25, true);
1131 check_picture_size_ok (1998, 1080, 48, true);
1134 check_picture_size_ok (4096, 1716, 24, false);
1137 check_picture_size_ok (3996, 2160, 24, false);
1139 /* Bad frame size */
1140 check_picture_size_bad_frame_size (2050, 858, 24, false);
1141 check_picture_size_bad_frame_size (2048, 658, 25, false);
1142 check_picture_size_bad_frame_size (1920, 1080, 48, true);
1143 check_picture_size_bad_frame_size (4000, 3000, 24, true);
1145 /* Bad 2K frame rate */
1146 check_picture_size_bad_2k_frame_rate (2048, 858, 26, false);
1147 check_picture_size_bad_2k_frame_rate (2048, 858, 31, false);
1148 check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true);
1150 /* Bad 4K frame rate */
1151 check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false);
1152 check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false);
1155 list<dcp::VerificationNote> notes = check_picture_size(3996, 2160, 24, true);
1156 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1157 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1158 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_4K_3D);
1162 BOOST_AUTO_TEST_CASE (verify_closed_caption_xml_too_large)
1164 boost::filesystem::path const dir("build/test/verify_closed_caption_xml_too_large");
1165 prepare_directory (dir);
1167 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset());
1168 for (int i = 0; i < 2048; ++i) {
1170 shared_ptr<dcp::Subtitle>(
1171 new dcp::SubtitleString(
1179 dcp::Time(i * 24, 24, 24),
1180 dcp::Time(i * 24 + 20, 24, 24),
1195 asset->set_language (dcp::LanguageTag("de-DE"));
1196 asset->write (dir / "subs.mxf");
1197 shared_ptr<dcp::ReelClosedCaptionAsset> reel_asset(new dcp::ReelClosedCaptionAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
1198 shared_ptr<dcp::Reel> reel(new dcp::Reel());
1199 reel->add (reel_asset);
1200 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
1202 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
1204 dcp->write_xml (dcp::SMPTE);
1206 vector<boost::filesystem::path> dirs;
1207 dirs.push_back (dir);
1208 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
1209 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1210 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1211 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES);
1216 shared_ptr<dcp::SMPTESubtitleAsset>
1217 make_large_subtitle_asset (boost::filesystem::path font_file)
1219 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset());
1220 dcp::ArrayData big_fake_font(1024 * 1024);
1221 big_fake_font.write (font_file);
1222 for (int i = 0; i < 116; ++i) {
1223 asset->add_font (dcp::String::compose("big%1", i), big_fake_font);
1231 verify_timed_text_asset_too_large (string name)
1233 boost::filesystem::path const dir = boost::filesystem::path("build/test") / name;
1234 prepare_directory (dir);
1235 shared_ptr<dcp::SMPTESubtitleAsset> asset = make_large_subtitle_asset (dir / "font.ttf");
1237 shared_ptr<dcp::Subtitle>(
1238 new dcp::SubtitleString(
1246 dcp::Time(0, 24, 24),
1247 dcp::Time(20, 24, 24),
1261 asset->set_language (dcp::LanguageTag("de-DE"));
1262 asset->write (dir / "subs.mxf");
1264 shared_ptr<T> reel_asset(new T(asset, dcp::Fraction(24, 1), 16 * 24, 0));
1265 shared_ptr<dcp::Reel> reel(new dcp::Reel());
1266 reel->add (reel_asset);
1267 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
1269 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
1271 dcp->write_xml (dcp::SMPTE);
1273 vector<boost::filesystem::path> dirs;
1274 dirs.push_back (dir);
1275 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
1276 BOOST_REQUIRE_EQUAL (notes.size(), 2U);
1277 list<dcp::VerificationNote>::const_iterator i = notes.begin();
1278 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1279 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::TIMED_TEXT_ASSET_TOO_LARGE_IN_BYTES);
1281 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1282 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES);
1286 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
1288 verify_timed_text_asset_too_large<dcp::ReelSubtitleAsset>("verify_subtitle_asset_too_large");
1289 verify_timed_text_asset_too_large<dcp::ReelClosedCaptionAsset>("verify_closed_caption_asset_too_large");
1293 BOOST_AUTO_TEST_CASE (verify_missing_language_tag_in_subtitle_xml)
1295 boost::filesystem::path dir = "build/test/verify_missing_language_tag_in_subtitle_xml";
1296 prepare_directory (dir);
1297 shared_ptr<dcp::DCP> dcp = make_simple (dir, 1);
1300 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
1301 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
1302 "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
1303 "<ContentTitleText>Content</ContentTitleText>"
1304 "<AnnotationText>Annotation</AnnotationText>"
1305 "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
1306 "<ReelNumber>1</ReelNumber>"
1307 "<EditRate>25 1</EditRate>"
1308 "<TimeCodeRate>25</TimeCodeRate>"
1309 "<StartTime>00:00:00:00</StartTime>"
1310 "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
1312 "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
1313 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
1314 "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
1320 FILE* xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
1321 BOOST_REQUIRE (xml_file);
1322 fwrite (xml.c_str(), xml.size(), 1, xml_file);
1324 shared_ptr<dcp::SMPTESubtitleAsset> subs (new dcp::SMPTESubtitleAsset(dir / "subs.xml"));
1325 subs->write (dir / "subs.mxf");
1327 shared_ptr<dcp::ReelSubtitleAsset> reel_subs (new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 100, 0));
1328 dcp->cpls().front()->reels().front()->add (reel_subs);
1329 dcp->write_xml (dcp::SMPTE);
1331 vector<boost::filesystem::path> dirs;
1332 dirs.push_back (dir);
1333 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
1334 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
1335 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
1336 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_SUBTITLE_LANGUAGE);