2 Copyright (C) 2020-2021 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 "interop_subtitle_asset.h"
39 #include "reel_subtitle_asset.h"
40 #include "reel_mono_picture_asset.h"
41 #include "reel_sound_asset.h"
45 #include "reel_markers_asset.h"
46 #include <boost/algorithm/string.hpp>
47 #include <boost/optional.hpp>
48 #include <boost/test/unit_test.hpp>
54 using std::make_shared;
56 using std::shared_ptr;
57 using boost::optional;
61 stage (string, optional<boost::filesystem::path>)
74 dump_notes (vector<dcp::VerificationNote> const & notes)
77 std::cout << dcp::note_to_string(i) << "\n";
84 check_no_errors (boost::filesystem::path path)
86 vector<boost::filesystem::path> directories;
87 directories.push_back (path);
88 auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
89 vector<dcp::VerificationNote> filtered_notes;
90 std::copy_if (notes.begin(), notes.end(), std::back_inserter(filtered_notes), [](dcp::VerificationNote const& i) {
91 return i.code() != dcp::VerificationNote::Code::INVALID_STANDARD && i.code() != dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION;
93 dump_notes (filtered_notes);
94 BOOST_CHECK (filtered_notes.empty());
100 pointer_to_id_in_vector (shared_ptr<T> needle, vector<shared_ptr<T> > haystack)
102 for (auto i: haystack) {
103 if (i->id() == needle->id()) {
108 return shared_ptr<T>();
114 note_handler (dcp::NoteType, std::string)
116 // std::cout << "> " << n << "\n";
122 check_combined (vector<boost::filesystem::path> inputs, boost::filesystem::path output)
124 dcp::DCP output_dcp (output);
127 dcp::EqualityOptions options;
128 options.load_font_nodes_can_differ = true;
130 for (auto i: inputs) {
131 dcp::DCP input_dcp (i);
134 BOOST_REQUIRE (input_dcp.cpls().size() == 1);
135 auto input_cpl = input_dcp.cpls().front();
137 auto output_cpl = pointer_to_id_in_vector (input_cpl, output_dcp.cpls());
138 BOOST_REQUIRE (output_cpl);
140 for (auto i: input_dcp.assets(true)) {
141 auto o = pointer_to_id_in_vector(i, output_dcp.assets());
142 BOOST_REQUIRE_MESSAGE (o, "Could not find " << i->id() << " in combined DCP.");
143 BOOST_CHECK (i->equals(o, options, note_handler));
149 BOOST_AUTO_TEST_CASE (combine_single_dcp_test)
151 using namespace boost::algorithm;
152 using namespace boost::filesystem;
153 boost::filesystem::path const out = "build/test/combine_single_dcp_test";
157 inputs.push_back ("test/ref/DCP/dcp_test1");
161 dcp::String::compose("libdcp %1", dcp::version),
162 dcp::String::compose("libdcp %1", dcp::version),
163 dcp::LocalTime().as_string(),
167 check_no_errors (out);
168 check_combined (inputs, out);
172 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_same_asset_filenames_test)
174 using namespace boost::algorithm;
175 using namespace boost::filesystem;
176 boost::filesystem::path const out = "build/test/combine_two_dcps_with_same_asset_filenames_test";
178 shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2");
179 second->write_xml (dcp::Standard::SMPTE);
183 inputs.push_back ("test/ref/DCP/dcp_test1");
184 inputs.push_back ("build/test/combine_input2");
185 dcp::combine (inputs, out);
187 check_no_errors (out);
188 check_combined (inputs, out);
192 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_subs_test)
194 using namespace boost::algorithm;
195 using namespace boost::filesystem;
196 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_subs_test";
198 auto first = make_simple_with_interop_subs ("build/test/combine_input1");
199 first->write_xml (dcp::Standard::INTEROP);
201 auto second = make_simple_with_interop_subs ("build/test/combine_input2");
202 second->write_xml (dcp::Standard::INTEROP);
206 inputs.push_back ("build/test/combine_input1");
207 inputs.push_back ("build/test/combine_input2");
208 dcp::combine (inputs, out);
210 check_no_errors (out);
211 check_combined (inputs, out);
215 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_subs_test)
217 using namespace boost::algorithm;
218 using namespace boost::filesystem;
219 boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test";
221 shared_ptr<dcp::DCP> first = make_simple_with_smpte_subs ("build/test/combine_input1");
222 first->write_xml (dcp::Standard::SMPTE);
224 shared_ptr<dcp::DCP> second = make_simple_with_smpte_subs ("build/test/combine_input2");
225 second->write_xml (dcp::Standard::SMPTE);
229 inputs.push_back ("build/test/combine_input1");
230 inputs.push_back ("build/test/combine_input2");
231 dcp::combine (inputs, out);
233 check_no_errors (out);
234 check_combined (inputs, out);
238 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test)
240 using namespace boost::algorithm;
241 using namespace boost::filesystem;
242 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
244 shared_ptr<dcp::DCP> first = make_simple_with_interop_ccaps ("build/test/combine_input1");
245 first->write_xml (dcp::Standard::INTEROP);
247 shared_ptr<dcp::DCP> second = make_simple_with_interop_ccaps ("build/test/combine_input2");
248 second->write_xml (dcp::Standard::INTEROP);
252 inputs.push_back ("build/test/combine_input1");
253 inputs.push_back ("build/test/combine_input2");
254 dcp::combine (inputs, out);
256 check_no_errors (out);
257 check_combined (inputs, out);
261 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test)
263 using namespace boost::algorithm;
264 using namespace boost::filesystem;
265 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
267 shared_ptr<dcp::DCP> first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
268 first->write_xml (dcp::Standard::SMPTE);
270 shared_ptr<dcp::DCP> second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
271 second->write_xml (dcp::Standard::SMPTE);
275 inputs.push_back ("build/test/combine_input1");
276 inputs.push_back ("build/test/combine_input2");
277 dcp::combine (inputs, out);
279 check_no_errors (out);
280 check_combined (inputs, out);
284 BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps)
286 using namespace boost::algorithm;
287 using namespace boost::filesystem;
288 boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps";
290 shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 4);
291 first->write_xml (dcp::Standard::SMPTE);
293 shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2", 4);
294 second->write_xml (dcp::Standard::SMPTE);
298 inputs.push_back ("build/test/combine_input1");
299 inputs.push_back ("build/test/combine_input2");
300 dcp::combine (inputs, out);
302 check_no_errors (out);
303 check_combined (inputs, out);
307 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
309 using namespace boost::filesystem;
310 boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset";
312 shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 1);
313 first->write_xml (dcp::Standard::SMPTE);
315 remove_all ("build/test/combine_input2");
316 shared_ptr<dcp::DCP> second(new dcp::DCP("build/test/combine_input2"));
318 dcp::MXFMetadata mxf_meta;
319 mxf_meta.company_name = "OpenDCP";
320 mxf_meta.product_version = "0.0.25";
322 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
323 cpl->set_content_version (
324 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
326 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
327 cpl->set_main_sound_sample_rate (48000);
328 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
329 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
330 cpl->set_version_number(1);
332 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
333 auto sound = make_shared<dcp::ReelSoundAsset>(first->cpls().front()->reels().front()->main_sound()->asset(), 0);
334 auto reel = make_shared<dcp::Reel>(pic, sound);
335 reel->add (simple_markers());
338 second->write_xml (dcp::Standard::SMPTE);
342 inputs.push_back ("build/test/combine_input1");
343 inputs.push_back ("build/test/combine_input2");
344 dcp::combine (inputs, out);
346 check_no_errors (out);
347 check_combined (inputs, out);
351 /** Two DCPs each with a copy of the exact same asset */
352 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_duplicated_asset)
354 using namespace boost::filesystem;
355 boost::filesystem::path const out = "build/test/combine_two_dcps_with_duplicated_asset";
357 auto first = make_simple ("build/test/combine_input1", 1);
358 first->write_xml (dcp::Standard::SMPTE);
360 remove_all ("build/test/combine_input2");
361 auto second = make_shared<dcp::DCP>("build/test/combine_input2");
363 dcp::MXFMetadata mxf_meta;
364 mxf_meta.company_name = "OpenDCP";
365 mxf_meta.product_version = "0.0.25";
367 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
368 cpl->set_content_version (
369 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
371 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
372 cpl->set_main_sound_sample_rate (48000);
373 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
374 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
375 cpl->set_version_number(1);
377 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
378 auto first_sound_asset = first->cpls()[0]->reels()[0]->main_sound()->asset()->file();
379 BOOST_REQUIRE (first_sound_asset);
380 boost::filesystem::path second_sound_asset = "build/test/combine_input2/my_great_audio.mxf";
381 boost::filesystem::copy_file (*first_sound_asset, second_sound_asset);
382 auto sound = make_shared<dcp::ReelSoundAsset>(make_shared<dcp::SoundAsset>(second_sound_asset), 0);
383 auto reel = make_shared<dcp::Reel>(pic, sound);
384 reel->add (simple_markers());
387 second->write_xml (dcp::Standard::SMPTE);
391 inputs.push_back ("build/test/combine_input1");
392 inputs.push_back ("build/test/combine_input2");
393 dcp::combine (inputs, out);
395 check_no_errors (out);
396 check_combined (inputs, out);
398 BOOST_REQUIRE (!boost::filesystem::exists(out / "my_great_audio.mxf"));
402 /* XXX: same CPL names */
403 /* XXX: Interop PNG subs */