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 auto second = make_simple ("build/test/combine_input2");
179 second->write_xml ();
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_one_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_one_with_interop_subs_test";
198 auto first = make_simple("build/test/combine_input1", 1, 24, dcp::Standard::INTEROP);
201 auto second = make_simple_with_interop_subs("build/test/combine_input2");
202 second->write_xml ();
205 vector<path> inputs = {"build/test/combine_input1", "build/test/combine_input2"};
206 dcp::combine (inputs, out);
208 check_no_errors (out);
209 check_combined (inputs, out);
213 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_subs_test)
215 using namespace boost::algorithm;
216 using namespace boost::filesystem;
217 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_subs_test";
219 auto first = make_simple_with_interop_subs ("build/test/combine_input1");
222 auto second = make_simple_with_interop_subs ("build/test/combine_input2");
223 second->write_xml ();
226 vector<path> inputs = {"build/test/combine_input1", "build/test/combine_input2"};
227 dcp::combine (inputs, out);
229 check_no_errors (out);
230 check_combined (inputs, out);
234 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_subs_test)
236 using namespace boost::algorithm;
237 using namespace boost::filesystem;
238 boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test";
240 auto first = make_simple_with_smpte_subs ("build/test/combine_input1");
243 auto second = make_simple_with_smpte_subs ("build/test/combine_input2");
244 second->write_xml ();
248 inputs.push_back ("build/test/combine_input1");
249 inputs.push_back ("build/test/combine_input2");
250 dcp::combine (inputs, out);
252 check_no_errors (out);
253 check_combined (inputs, out);
257 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test)
259 using namespace boost::algorithm;
260 using namespace boost::filesystem;
261 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
263 auto first = make_simple_with_interop_ccaps ("build/test/combine_input1");
266 auto second = make_simple_with_interop_ccaps ("build/test/combine_input2");
267 second->write_xml ();
271 inputs.push_back ("build/test/combine_input1");
272 inputs.push_back ("build/test/combine_input2");
273 dcp::combine (inputs, out);
275 check_no_errors (out);
276 check_combined (inputs, out);
280 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test)
282 using namespace boost::algorithm;
283 using namespace boost::filesystem;
284 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
286 auto first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
289 auto second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
290 second->write_xml ();
294 inputs.push_back ("build/test/combine_input1");
295 inputs.push_back ("build/test/combine_input2");
296 dcp::combine (inputs, out);
298 check_no_errors (out);
299 check_combined (inputs, out);
303 BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps)
305 using namespace boost::algorithm;
306 using namespace boost::filesystem;
307 boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps";
309 auto first = make_simple ("build/test/combine_input1", 4);
312 auto second = make_simple ("build/test/combine_input2", 4);
313 second->write_xml ();
317 inputs.push_back ("build/test/combine_input1");
318 inputs.push_back ("build/test/combine_input2");
319 dcp::combine (inputs, out);
321 check_no_errors (out);
322 check_combined (inputs, out);
326 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
328 using namespace boost::filesystem;
329 boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset";
331 auto first = make_simple ("build/test/combine_input1", 1);
334 remove_all ("build/test/combine_input2");
335 auto second = make_shared<dcp::DCP>("build/test/combine_input2");
337 dcp::MXFMetadata mxf_meta;
338 mxf_meta.company_name = "OpenDCP";
339 mxf_meta.product_version = "0.0.25";
341 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
342 cpl->set_content_version (
343 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
345 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
346 cpl->set_main_sound_sample_rate (48000);
347 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
348 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
349 cpl->set_version_number(1);
351 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
352 auto sound = make_shared<dcp::ReelSoundAsset>(first->cpls().front()->reels().front()->main_sound()->asset(), 0);
353 auto reel = make_shared<dcp::Reel>(pic, sound);
354 reel->add (simple_markers());
357 second->write_xml ();
361 inputs.push_back ("build/test/combine_input1");
362 inputs.push_back ("build/test/combine_input2");
363 dcp::combine (inputs, out);
365 check_no_errors (out);
366 check_combined (inputs, out);
370 /** Two DCPs each with a copy of the exact same asset */
371 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_duplicated_asset)
373 using namespace boost::filesystem;
374 boost::filesystem::path const out = "build/test/combine_two_dcps_with_duplicated_asset";
376 auto first = make_simple ("build/test/combine_input1", 1);
379 remove_all ("build/test/combine_input2");
380 auto second = make_shared<dcp::DCP>("build/test/combine_input2");
382 dcp::MXFMetadata mxf_meta;
383 mxf_meta.company_name = "OpenDCP";
384 mxf_meta.product_version = "0.0.25";
386 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
387 cpl->set_content_version (
388 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
390 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
391 cpl->set_main_sound_sample_rate (48000);
392 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
393 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
394 cpl->set_version_number(1);
396 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
397 auto first_sound_asset = first->cpls()[0]->reels()[0]->main_sound()->asset()->file();
398 BOOST_REQUIRE (first_sound_asset);
399 boost::filesystem::path second_sound_asset = "build/test/combine_input2/my_great_audio.mxf";
400 boost::filesystem::copy_file (*first_sound_asset, second_sound_asset);
401 auto sound = make_shared<dcp::ReelSoundAsset>(make_shared<dcp::SoundAsset>(second_sound_asset), 0);
402 auto reel = make_shared<dcp::Reel>(pic, sound);
403 reel->add (simple_markers());
406 second->write_xml ();
410 inputs.push_back ("build/test/combine_input1");
411 inputs.push_back ("build/test/combine_input2");
412 dcp::combine (inputs, out);
414 check_no_errors (out);
415 check_combined (inputs, out);
417 BOOST_REQUIRE (!boost::filesystem::exists(out / "my_great_audio.mxf"));
421 BOOST_AUTO_TEST_CASE (check_cpls_unchanged_after_combine)
423 boost::filesystem::path in = "build/test/combine_one_dcp_with_composition_metadata_in";
424 boost::filesystem::path out = "build/test/combine_one_dcp_with_composition_metadata_out";
425 auto dcp = make_simple (in);
428 dcp::combine ({in}, out);
430 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
431 auto cpl = dcp->cpls()[0]->file();
433 check_file (*cpl, out / cpl->filename());
437 /* XXX: same CPL names */
438 /* XXX: Interop PNG subs */