2 Copyright (C) 2012-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.
34 #define BOOST_TEST_DYN_LINK
35 #define BOOST_TEST_MODULE libdcp_test
36 #include "compose.hpp"
40 #include "interop_subtitle_asset.h"
41 #include "mono_picture_asset.h"
42 #include "picture_asset_writer.h"
44 #include "reel_mono_picture_asset.h"
45 #include "reel_sound_asset.h"
46 #include "reel_closed_caption_asset.h"
47 #include "reel_subtitle_asset.h"
48 #include "sound_asset.h"
49 #include "sound_asset_writer.h"
50 #include "smpte_subtitle_asset.h"
53 #include <asdcp/KM_util.h>
54 #include <asdcp/KM_prng.h>
56 #include <libxml++/libxml++.h>
57 #include <boost/test/unit_test.hpp>
64 using boost::shared_ptr;
65 using boost::optional;
67 boost::filesystem::path private_test;
68 boost::filesystem::path xsd_test = "build/test/xsd with spaces";
75 if (boost::unit_test::framework::master_test_suite().argc >= 2) {
76 private_test = boost::unit_test::framework::master_test_suite().argv[1];
79 using namespace boost::filesystem;
80 boost::system::error_code ec;
81 remove_all (xsd_test, ec);
82 boost::filesystem::create_directory (xsd_test);
83 for (directory_iterator i = directory_iterator("xsd"); i != directory_iterator(); ++i) {
84 copy_file (*i, xsd_test / i->path().filename());
90 check_xml (xmlpp::Element* ref, xmlpp::Element* test, list<string> ignore)
92 BOOST_CHECK_EQUAL (ref->get_name (), test->get_name ());
93 BOOST_CHECK_EQUAL (ref->get_namespace_prefix (), test->get_namespace_prefix ());
95 if (find (ignore.begin(), ignore.end(), ref->get_name()) != ignore.end ()) {
99 xmlpp::Element::NodeList ref_children = ref->get_children ();
100 xmlpp::Element::NodeList test_children = test->get_children ();
101 BOOST_REQUIRE_MESSAGE (
102 ref_children.size () == test_children.size (),
103 "child counts of " << ref->get_name() << " differ; ref has " << ref_children.size() << ", test has " << test_children.size()
106 xmlpp::Element::NodeList::iterator k = ref_children.begin ();
107 xmlpp::Element::NodeList::iterator l = test_children.begin ();
108 while (k != ref_children.end ()) {
110 /* XXX: should be doing xmlpp::EntityReference, xmlpp::XIncludeEnd, xmlpp::XIncludeStart */
112 xmlpp::Element* ref_el = dynamic_cast<xmlpp::Element*> (*k);
113 xmlpp::Element* test_el = dynamic_cast<xmlpp::Element*> (*l);
114 BOOST_CHECK ((ref_el && test_el) || (!ref_el && !test_el));
115 if (ref_el && test_el) {
116 check_xml (ref_el, test_el, ignore);
119 xmlpp::ContentNode* ref_cn = dynamic_cast<xmlpp::ContentNode*> (*k);
120 xmlpp::ContentNode* test_cn = dynamic_cast<xmlpp::ContentNode*> (*l);
121 BOOST_CHECK ((ref_cn && test_cn) || (!ref_cn && !test_cn));
122 if (ref_cn && test_cn) {
123 BOOST_CHECK_EQUAL (ref_cn->get_content(), test_cn->get_content ());
130 xmlpp::Element::AttributeList ref_attributes = ref->get_attributes ();
131 xmlpp::Element::AttributeList test_attributes = test->get_attributes ();
132 BOOST_CHECK_EQUAL (ref_attributes.size(), test_attributes.size ());
134 xmlpp::Element::AttributeList::const_iterator m = ref_attributes.begin();
135 xmlpp::Element::AttributeList::const_iterator n = test_attributes.begin();
136 while (m != ref_attributes.end ()) {
137 BOOST_CHECK_EQUAL ((*m)->get_name(), (*n)->get_name());
138 BOOST_CHECK_EQUAL ((*m)->get_value(), (*n)->get_value());
146 check_xml (string ref, string test, list<string> ignore)
148 xmlpp::DomParser* ref_parser = new xmlpp::DomParser ();
149 ref_parser->parse_memory (ref);
150 xmlpp::Element* ref_root = ref_parser->get_document()->get_root_node ();
151 xmlpp::DomParser* test_parser = new xmlpp::DomParser ();
152 test_parser->parse_memory (test);
153 xmlpp::Element* test_root = test_parser->get_document()->get_root_node ();
155 check_xml (ref_root, test_root, ignore);
159 check_file (boost::filesystem::path ref, boost::filesystem::path check)
161 uintmax_t N = boost::filesystem::file_size (ref);
162 BOOST_CHECK_EQUAL (N, boost::filesystem::file_size (check));
163 FILE* ref_file = dcp::fopen_boost (ref, "rb");
164 BOOST_CHECK (ref_file);
165 FILE* check_file = dcp::fopen_boost (check, "rb");
166 BOOST_CHECK (check_file);
168 int const buffer_size = 65536;
169 uint8_t* ref_buffer = new uint8_t[buffer_size];
170 uint8_t* check_buffer = new uint8_t[buffer_size];
173 error = "File " + check.string() + " differs from reference " + ref.string();
176 uintmax_t this_time = min (uintmax_t (buffer_size), N);
177 size_t r = fread (ref_buffer, 1, this_time, ref_file);
178 BOOST_CHECK_EQUAL (r, this_time);
179 r = fread (check_buffer, 1, this_time, check_file);
180 BOOST_CHECK_EQUAL (r, this_time);
182 BOOST_CHECK_MESSAGE (memcmp (ref_buffer, check_buffer, this_time) == 0, error);
183 if (memcmp (ref_buffer, check_buffer, this_time)) {
191 delete[] check_buffer;
198 RNGFixer::RNGFixer ()
200 Kumu::cth_test = true;
201 Kumu::FortunaRNG().Reset();
205 RNGFixer::~RNGFixer ()
207 Kumu::cth_test = false;
211 shared_ptr<dcp::MonoPictureAsset>
212 simple_picture (boost::filesystem::path path, string suffix)
214 dcp::MXFMetadata mxf_meta;
215 mxf_meta.company_name = "OpenDCP";
216 mxf_meta.product_name = "OpenDCP";
217 mxf_meta.product_version = "0.0.25";
219 shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1), dcp::SMPTE));
220 mp->set_metadata (mxf_meta);
221 shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (path / dcp::String::compose("video%1.mxf", suffix), false);
222 dcp::File j2c ("test/data/32x32_red_square.j2c");
223 for (int i = 0; i < 24; ++i) {
224 picture_writer->write (j2c.data (), j2c.size ());
226 picture_writer->finalize ();
233 make_simple (boost::filesystem::path path, int reels)
235 /* Some known metadata */
236 dcp::XMLMetadata xml_meta;
237 xml_meta.annotation_text = "A Test DCP";
238 xml_meta.issuer = "OpenDCP 0.0.25";
239 xml_meta.creator = "OpenDCP 0.0.25";
240 xml_meta.issue_date = "2012-07-17T04:45:18+00:00";
241 dcp::MXFMetadata mxf_meta;
242 mxf_meta.company_name = "OpenDCP";
243 mxf_meta.product_name = "OpenDCP";
244 mxf_meta.product_version = "0.0.25";
246 boost::filesystem::remove_all (path);
247 boost::filesystem::create_directories (path);
248 shared_ptr<dcp::DCP> d (new dcp::DCP (path));
249 shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
250 cpl->set_content_version_id ("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11");
251 cpl->set_content_version_label_text ("content-version-label-text");
252 cpl->set_metadata (xml_meta);
254 for (int i = 0; i < reels; ++i) {
255 string suffix = reels == 1 ? "" : dcp::String::compose("%1", i);
257 shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (path, suffix);
259 shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset (dcp::Fraction (24, 1), 48000, 1, dcp::SMPTE));
260 ms->set_metadata (mxf_meta);
261 shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write (path / dcp::String::compose("audio%1.mxf", suffix));
265 SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info);
266 BOOST_CHECK (sndfile);
267 float buffer[4096*6];
269 channels[0] = buffer;
271 sf_count_t N = sf_readf_float (sndfile, buffer, 4096);
272 sound_writer->write (channels, N);
278 sound_writer->finalize ();
280 cpl->add (shared_ptr<dcp::Reel> (
282 shared_ptr<dcp::ReelMonoPictureAsset>(new dcp::ReelMonoPictureAsset(mp, 0)),
283 shared_ptr<dcp::ReelSoundAsset>(new dcp::ReelSoundAsset(ms, 0))
293 shared_ptr<dcp::Subtitle>
296 return shared_ptr<dcp::Subtitle>(
297 new dcp::SubtitleString(
302 dcp::Colour(255, 255, 255),
305 dcp::Time(0, 0, 4, 0, 24),
306 dcp::Time(0, 0, 8, 0, 24),
314 dcp::Colour(255, 255, 255),
323 make_simple_with_interop_subs (boost::filesystem::path path)
325 shared_ptr<dcp::DCP> dcp = make_simple (path);
327 shared_ptr<dcp::InteropSubtitleAsset> subs(new dcp::InteropSubtitleAsset());
328 subs->add (simple_subtitle());
330 boost::filesystem::create_directory (path / "subs");
331 dcp::Data data(4096);
332 data.write (path / "subs" / "font.ttf");
333 subs->add_font ("afont", path / "subs" / "font.ttf");
334 subs->write (path / "subs" / "subs.xml");
336 shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0));
337 dcp->cpls().front()->reels().front()->add (reel_subs);
344 make_simple_with_smpte_subs (boost::filesystem::path path)
346 shared_ptr<dcp::DCP> dcp = make_simple (path);
348 shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
349 subs->add (simple_subtitle());
351 dcp::Data data(4096);
352 subs->write (path / "subs.mxf");
354 shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0));
355 dcp->cpls().front()->reels().front()->add (reel_subs);
362 make_simple_with_interop_ccaps (boost::filesystem::path path)
364 shared_ptr<dcp::DCP> dcp = make_simple (path);
366 shared_ptr<dcp::InteropSubtitleAsset> subs(new dcp::InteropSubtitleAsset());
367 subs->add (simple_subtitle());
368 subs->write (path / "ccap.xml");
370 shared_ptr<dcp::ReelClosedCaptionAsset> reel_caps(new dcp::ReelClosedCaptionAsset(subs, dcp::Fraction(24, 1), 240, 0));
371 dcp->cpls().front()->reels().front()->add (reel_caps);
378 make_simple_with_smpte_ccaps (boost::filesystem::path path)
380 shared_ptr<dcp::DCP> dcp = make_simple (path);
382 shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
383 subs->add (simple_subtitle());
384 subs->write (path / "ccap.mxf");
386 shared_ptr<dcp::ReelClosedCaptionAsset> reel_caps(new dcp::ReelClosedCaptionAsset(subs, dcp::Fraction(24, 1), 240, 0));
387 dcp->cpls().front()->reels().front()->add (reel_caps);
393 BOOST_GLOBAL_FIXTURE (TestConfig);