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_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");
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_smpte_subs_test)
215 using namespace boost::algorithm;
216 using namespace boost::filesystem;
217 boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test";
219 auto first = make_simple_with_smpte_subs ("build/test/combine_input1");
222 auto second = make_simple_with_smpte_subs ("build/test/combine_input2");
223 second->write_xml ();
227 inputs.push_back ("build/test/combine_input1");
228 inputs.push_back ("build/test/combine_input2");
229 dcp::combine (inputs, out);
231 check_no_errors (out);
232 check_combined (inputs, out);
236 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test)
238 using namespace boost::algorithm;
239 using namespace boost::filesystem;
240 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
242 auto first = make_simple_with_interop_ccaps ("build/test/combine_input1");
245 auto second = make_simple_with_interop_ccaps ("build/test/combine_input2");
246 second->write_xml ();
250 inputs.push_back ("build/test/combine_input1");
251 inputs.push_back ("build/test/combine_input2");
252 dcp::combine (inputs, out);
254 check_no_errors (out);
255 check_combined (inputs, out);
259 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test)
261 using namespace boost::algorithm;
262 using namespace boost::filesystem;
263 boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
265 auto first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
268 auto second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
269 second->write_xml ();
273 inputs.push_back ("build/test/combine_input1");
274 inputs.push_back ("build/test/combine_input2");
275 dcp::combine (inputs, out);
277 check_no_errors (out);
278 check_combined (inputs, out);
282 BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps)
284 using namespace boost::algorithm;
285 using namespace boost::filesystem;
286 boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps";
288 auto first = make_simple ("build/test/combine_input1", 4);
291 auto second = make_simple ("build/test/combine_input2", 4);
292 second->write_xml ();
296 inputs.push_back ("build/test/combine_input1");
297 inputs.push_back ("build/test/combine_input2");
298 dcp::combine (inputs, out);
300 check_no_errors (out);
301 check_combined (inputs, out);
305 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
307 using namespace boost::filesystem;
308 boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset";
310 auto first = make_simple ("build/test/combine_input1", 1);
313 remove_all ("build/test/combine_input2");
314 auto second = make_shared<dcp::DCP>("build/test/combine_input2");
316 dcp::MXFMetadata mxf_meta;
317 mxf_meta.company_name = "OpenDCP";
318 mxf_meta.product_version = "0.0.25";
320 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
321 cpl->set_content_version (
322 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
324 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
325 cpl->set_main_sound_sample_rate (48000);
326 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
327 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
328 cpl->set_version_number(1);
330 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
331 auto sound = make_shared<dcp::ReelSoundAsset>(first->cpls().front()->reels().front()->main_sound()->asset(), 0);
332 auto reel = make_shared<dcp::Reel>(pic, sound);
333 reel->add (simple_markers());
336 second->write_xml ();
340 inputs.push_back ("build/test/combine_input1");
341 inputs.push_back ("build/test/combine_input2");
342 dcp::combine (inputs, out);
344 check_no_errors (out);
345 check_combined (inputs, out);
349 /** Two DCPs each with a copy of the exact same asset */
350 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_duplicated_asset)
352 using namespace boost::filesystem;
353 boost::filesystem::path const out = "build/test/combine_two_dcps_with_duplicated_asset";
355 auto first = make_simple ("build/test/combine_input1", 1);
358 remove_all ("build/test/combine_input2");
359 auto second = make_shared<dcp::DCP>("build/test/combine_input2");
361 dcp::MXFMetadata mxf_meta;
362 mxf_meta.company_name = "OpenDCP";
363 mxf_meta.product_version = "0.0.25";
365 auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
366 cpl->set_content_version (
367 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
369 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
370 cpl->set_main_sound_sample_rate (48000);
371 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
372 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
373 cpl->set_version_number(1);
375 auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
376 auto first_sound_asset = first->cpls()[0]->reels()[0]->main_sound()->asset()->file();
377 BOOST_REQUIRE (first_sound_asset);
378 boost::filesystem::path second_sound_asset = "build/test/combine_input2/my_great_audio.mxf";
379 boost::filesystem::copy_file (*first_sound_asset, second_sound_asset);
380 auto sound = make_shared<dcp::ReelSoundAsset>(make_shared<dcp::SoundAsset>(second_sound_asset), 0);
381 auto reel = make_shared<dcp::Reel>(pic, sound);
382 reel->add (simple_markers());
385 second->write_xml ();
389 inputs.push_back ("build/test/combine_input1");
390 inputs.push_back ("build/test/combine_input2");
391 dcp::combine (inputs, out);
393 check_no_errors (out);
394 check_combined (inputs, out);
396 BOOST_REQUIRE (!boost::filesystem::exists(out / "my_great_audio.mxf"));
400 BOOST_AUTO_TEST_CASE (check_cpls_unchanged_after_combine)
402 boost::filesystem::path in = "build/test/combine_one_dcp_with_composition_metadata_in";
403 boost::filesystem::path out = "build/test/combine_one_dcp_with_composition_metadata_out";
404 auto dcp = make_simple (in);
407 dcp::combine ({in}, out);
409 BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
410 auto cpl = dcp->cpls()[0]->file();
412 check_file (*cpl, out / cpl->filename());
416 /* XXX: same CPL names */
417 /* XXX: Interop PNG subs */