2 Copyright (C) 2013-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.
37 #include "mono_picture_asset.h"
38 #include "stereo_picture_asset.h"
39 #include "picture_asset_writer.h"
40 #include "reel_picture_asset.h"
41 #include "sound_asset_writer.h"
42 #include "sound_asset.h"
43 #include "atmos_asset.h"
46 #include "reel_mono_picture_asset.h"
47 #include "reel_stereo_picture_asset.h"
48 #include "reel_sound_asset.h"
49 #include "reel_atmos_asset.h"
50 #include <asdcp/KM_util.h>
52 #include <boost/test/unit_test.hpp>
56 using std::dynamic_pointer_cast;
57 using std::shared_ptr;
58 #if BOOST_VERSION >= 106100
59 using namespace boost::placeholders;
63 /** Test creation of a 2D SMPTE DCP from very simple inputs */
64 BOOST_AUTO_TEST_CASE (dcp_test1)
68 make_simple("build/test/DCP/dcp_test1")->write_xml(
69 dcp::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "Created by libdcp"
72 /* build/test/DCP/dcp_test1 is checked against test/ref/DCP/dcp_test1 by run/tests */
75 /** Test creation of a 3D DCP from very simple inputs */
76 BOOST_AUTO_TEST_CASE (dcp_test2)
80 /* Some known metadata */
81 dcp::MXFMetadata mxf_meta;
82 mxf_meta.company_name = "OpenDCP";
83 mxf_meta.product_name = "OpenDCP";
84 mxf_meta.product_version = "0.0.25";
86 /* We're making build/test/DCP/dcp_test2 */
87 boost::filesystem::remove_all ("build/test/DCP/dcp_test2");
88 boost::filesystem::create_directories ("build/test/DCP/dcp_test2");
89 dcp::DCP d ("build/test/DCP/dcp_test2");
90 shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
91 cpl->set_content_version (
92 dcp::ContentVersion("urn:uri:81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00", "81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00")
94 cpl->set_issuer ("OpenDCP 0.0.25");
95 cpl->set_creator ("OpenDCP 0.0.25");
96 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
97 cpl->set_annotation_text ("A Test DCP");
99 shared_ptr<dcp::StereoPictureAsset> mp (new dcp::StereoPictureAsset (dcp::Fraction (24, 1), dcp::SMPTE));
100 mp->set_metadata (mxf_meta);
101 shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write ("build/test/DCP/dcp_test2/video.mxf", false);
102 dcp::ArrayData j2c ("test/data/flat_red.j2c");
103 for (int i = 0; i < 24; ++i) {
105 picture_writer->write (j2c.data (), j2c.size ());
107 picture_writer->write (j2c.data (), j2c.size ());
109 picture_writer->finalize ();
111 shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset(dcp::Fraction(24, 1), 48000, 1, dcp::LanguageTag("en-GB"), dcp::SMPTE));
112 ms->set_metadata (mxf_meta);
113 shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write ("build/test/DCP/dcp_test2/audio.mxf", vector<dcp::Channel>());
117 SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info);
118 BOOST_CHECK (sndfile);
119 float buffer[4096*6];
121 channels[0] = buffer;
123 sf_count_t N = sf_readf_float (sndfile, buffer, 4096);
124 sound_writer->write (channels, N);
130 sound_writer->finalize ();
132 cpl->add (shared_ptr<dcp::Reel> (
134 shared_ptr<dcp::ReelStereoPictureAsset> (new dcp::ReelStereoPictureAsset (mp, 0)),
135 shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (ms, 0))
141 d.write_xml (dcp::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "Created by libdcp");
143 /* build/test/DCP/dcp_test2 is checked against test/ref/DCP/dcp_test2 by run/tests */
147 note (dcp::NoteType, string)
152 /** Test comparison of a DCP with itself */
153 BOOST_AUTO_TEST_CASE (dcp_test3)
155 dcp::DCP A ("test/ref/DCP/dcp_test1");
157 dcp::DCP B ("test/ref/DCP/dcp_test1");
160 BOOST_CHECK (A.equals (B, dcp::EqualityOptions(), boost::bind (¬e, _1, _2)));
163 /** Test comparison of a DCP with a different DCP */
164 BOOST_AUTO_TEST_CASE (dcp_test4)
166 dcp::DCP A ("test/ref/DCP/dcp_test1");
168 dcp::DCP B ("test/ref/DCP/dcp_test2");
171 BOOST_CHECK (!A.equals (B, dcp::EqualityOptions(), boost::bind (¬e, _1, _2)));
176 test_rewriting_sound(string name, bool modify)
178 dcp::DCP A ("test/ref/DCP/dcp_test1");
181 BOOST_REQUIRE (!A.cpls().empty());
182 BOOST_REQUIRE (!A.cpls().front()->reels().empty());
183 shared_ptr<dcp::ReelMonoPictureAsset> A_picture = dynamic_pointer_cast<dcp::ReelMonoPictureAsset>(A.cpls().front()->reels().front()->main_picture());
184 BOOST_REQUIRE (A_picture);
185 shared_ptr<dcp::ReelSoundAsset> A_sound = dynamic_pointer_cast<dcp::ReelSoundAsset>(A.cpls().front()->reels().front()->main_sound());
187 boost::filesystem::remove_all ("build/test/" + name);
188 dcp::DCP B ("build/test/" + name);
189 shared_ptr<dcp::Reel> reel(new dcp::Reel());
191 BOOST_REQUIRE (A_picture->mono_asset());
192 BOOST_REQUIRE (A_picture->mono_asset()->file());
193 boost::filesystem::copy_file (A_picture->mono_asset()->file().get(), "build/test/" +name + "/picture.mxf");
195 shared_ptr<dcp::ReelMonoPictureAsset>(
196 new dcp::ReelMonoPictureAsset(shared_ptr<dcp::MonoPictureAsset>(new dcp::MonoPictureAsset("build/test/" + name + "/picture.mxf")), 0)
200 shared_ptr<dcp::SoundAssetReader> reader = A_sound->asset()->start_read();
201 shared_ptr<dcp::SoundAsset> sound(new dcp::SoundAsset(A_sound->asset()->edit_rate(), A_sound->asset()->sampling_rate(), A_sound->asset()->channels(), dcp::LanguageTag("en-US"), dcp::SMPTE));
202 shared_ptr<dcp::SoundAssetWriter> writer = sound->start_write("build/test/" + name + "/sound.mxf", vector<dcp::Channel>());
204 bool need_to_modify = modify;
205 for (int i = 0; i < A_sound->asset()->intrinsic_duration(); ++i) {
206 shared_ptr<const dcp::SoundFrame> sf = reader->get_frame (i);
207 float* out[sf->channels()];
208 for (int j = 0; j < sf->channels(); ++j) {
209 out[j] = new float[sf->samples()];
211 for (int j = 0; j < sf->samples(); ++j) {
212 for (int k = 0; k < sf->channels(); ++k) {
213 out[k][j] = static_cast<float>(sf->get(k, j)) / (1 << 23);
214 if (need_to_modify) {
215 out[k][j] += 1.0 / (1 << 23);
216 need_to_modify = false;
220 writer->write (out, sf->samples());
221 for (int j = 0; j < sf->channels(); ++j) {
227 reel->add(shared_ptr<dcp::ReelSoundAsset>(new dcp::ReelSoundAsset(sound, 0)));
229 shared_ptr<dcp::CPL> cpl(new dcp::CPL("A Test DCP", dcp::FEATURE));
233 B.write_xml (dcp::SMPTE);
235 dcp::EqualityOptions eq;
236 eq.reel_hashes_can_differ = true;
237 eq.max_audio_sample_error = 0;
239 BOOST_CHECK (!A.equals(B, eq, boost::bind(¬e, _1, _2)));
241 BOOST_CHECK (A.equals(B, eq, boost::bind(¬e, _1, _2)));
245 /** Test comparison of a DCP with another that has the same picture and the same (but re-written) sound */
246 BOOST_AUTO_TEST_CASE (dcp_test9)
248 test_rewriting_sound ("dcp_test9", false);
251 /** Test comparison of a DCP with another that has the same picture and very slightly modified sound */
252 BOOST_AUTO_TEST_CASE (dcp_test10)
254 test_rewriting_sound ("dcp_test10", true);
257 /** Test creation of a 2D DCP with an Atmos track */
258 BOOST_AUTO_TEST_CASE (dcp_test5)
262 /* Some known metadata */
263 dcp::MXFMetadata mxf_meta;
264 mxf_meta.company_name = "OpenDCP";
265 mxf_meta.product_name = "OpenDCP";
266 mxf_meta.product_version = "0.0.25";
268 /* We're making build/test/DCP/dcp_test5 */
269 boost::filesystem::remove_all ("build/test/DCP/dcp_test5");
270 boost::filesystem::create_directories ("build/test/DCP/dcp_test5");
271 dcp::DCP d ("build/test/DCP/dcp_test5");
272 shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
273 cpl->set_content_version (
274 dcp::ContentVersion("urn:uri:81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00", "81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00")
276 cpl->set_issuer ("OpenDCP 0.0.25");
277 cpl->set_creator ("OpenDCP 0.0.25");
278 cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
279 cpl->set_annotation_text ("A Test DCP");
281 shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1), dcp::SMPTE));
282 mp->set_metadata (mxf_meta);
283 shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write ("build/test/DCP/dcp_test5/video.mxf", false);
284 dcp::ArrayData j2c ("test/data/flat_red.j2c");
285 for (int i = 0; i < 24; ++i) {
286 picture_writer->write (j2c.data (), j2c.size ());
288 picture_writer->finalize ();
290 shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset(dcp::Fraction(24, 1), 48000, 1, dcp::LanguageTag("en-GB"), dcp::SMPTE));
291 ms->set_metadata (mxf_meta);
292 shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write ("build/test/DCP/dcp_test5/audio.mxf", vector<dcp::Channel>());
296 SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info);
297 BOOST_CHECK (sndfile);
298 float buffer[4096*6];
300 channels[0] = buffer;
302 sf_count_t N = sf_readf_float (sndfile, buffer, 4096);
303 sound_writer->write (channels, N);
309 sound_writer->finalize ();
311 shared_ptr<dcp::AtmosAsset> am (new dcp::AtmosAsset (private_test / "20160218_NameOfFilm_FTR_OV_EN_A_dcs_r01.mxf"));
313 cpl->add (shared_ptr<dcp::Reel> (
315 shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)),
316 shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (ms, 0)),
317 shared_ptr<dcp::ReelSubtitleAsset> (),
318 shared_ptr<dcp::ReelMarkersAsset> (),
319 shared_ptr<dcp::ReelAtmosAsset> (new dcp::ReelAtmosAsset (am, 0))
325 d.write_xml (dcp::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "Created by libdcp");
327 /* build/test/DCP/dcp_test5 is checked against test/ref/DCP/dcp_test5 by run/tests */
330 /** Basic tests of reading a 2D DCP with an Atmos track */
331 BOOST_AUTO_TEST_CASE (dcp_test6)
333 dcp::DCP dcp ("test/ref/DCP/dcp_test5");
336 BOOST_REQUIRE_EQUAL (dcp.cpls().size(), 1);
337 BOOST_REQUIRE_EQUAL (dcp.cpls().front()->reels().size(), 1);
338 BOOST_CHECK (dcp.cpls().front()->reels().front()->main_picture());
339 BOOST_CHECK (dcp.cpls().front()->reels().front()->main_sound());
340 BOOST_CHECK (!dcp.cpls().front()->reels().front()->main_subtitle());
341 BOOST_CHECK (dcp.cpls().front()->reels().front()->atmos());
344 /** Test creation of a 2D Interop DCP from very simple inputs */
345 BOOST_AUTO_TEST_CASE (dcp_test7)
349 make_simple("build/test/DCP/dcp_test7")->write_xml(
350 dcp::INTEROP, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "Created by libdcp"
353 /* build/test/DCP/dcp_test7 is checked against test/ref/DCP/dcp_test7 by run/tests */
356 /** Test reading of a DCP with multiple CPLs */
357 BOOST_AUTO_TEST_CASE (dcp_test8)
359 dcp::DCP dcp (private_test / "data/SMPTE_TST-B1PB2P_S_EN-EN-CCAP_5171-HI-VI_2K_ISDCF_20151123_DPPT_SMPTE_combo/");
362 BOOST_REQUIRE_EQUAL (dcp.cpls().size(), 2);
366 /** Test reading a DCP whose ASSETMAP contains assets not used by any PKL */
367 BOOST_AUTO_TEST_CASE (dcp_things_in_assetmap_not_in_pkl)
369 dcp::DCP dcp ("test/data/extra_assetmap");
370 BOOST_CHECK_NO_THROW (dcp.read());