From: Carl Hetherington Date: Tue, 30 May 2023 15:21:24 +0000 (+0200) Subject: Fix errors when mapping DCPs referring to the same asset multiple times (#2542). X-Git-Tag: v2.16.58~14 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=debc0ef69468530ba482c8ed0fc6a1ac1f26b26e Fix errors when mapping DCPs referring to the same asset multiple times (#2542). --- diff --git a/src/lib/map_cli.cc b/src/lib/map_cli.cc index c95d7f1a1..c49964f80 100644 --- a/src/lib/map_cli.cc +++ b/src/lib/map_cli.cc @@ -196,13 +196,20 @@ map_cli(int argc, char* argv[], std::function out) CopyError(std::string message) : std::runtime_error(message) {} }; - auto maybe_copy = [&assets, output_dir]( + vector already_copied; + + auto maybe_copy = [&assets, &already_copied, output_dir]( string asset_id, bool rename, bool hard_link, bool soft_link, boost::optional extra = boost::none ) { + + if (std::find(already_copied.begin(), already_copied.end(), asset_id) != already_copied.end()) { + return; + } + auto iter = std::find_if(assets.begin(), assets.end(), [asset_id](shared_ptr a) { return a->id() == asset_id; }); if (iter != assets.end()) { DCP_ASSERT((*iter)->file()); @@ -240,6 +247,7 @@ map_cli(int argc, char* argv[], std::function out) } } (*iter)->set_file(output_path); + already_copied.push_back(asset_id); } else { boost::system::error_code ec; boost::filesystem::remove_all(*output_dir, ec); diff --git a/test/map_cli_test.cc b/test/map_cli_test.cc index 59d88386b..387e04c8c 100644 --- a/test/map_cli_test.cc +++ b/test/map_cli_test.cc @@ -261,6 +261,53 @@ BOOST_AUTO_TEST_CASE(map_ov_vf_copy) test_map_ov_vf_copy({"-l"}); } + +/** Map an OV and VF into a single DCP, where the VF refers to the OV's assets multiple times */ +BOOST_AUTO_TEST_CASE(map_ov_vf_copy_multiple_reference) +{ + string const name = "map_ov_vf_copy_multiple_reference"; + string const out = String::compose("build/test/%1_out", name); + + auto ov_content = content_factory("test/data/flat_red.png"); + auto ov_film = new_test_film2(name + "_ov", ov_content); + make_and_verify_dcp(ov_film); + + auto const ov_dir = ov_film->dir(ov_film->dcp_name()); + + auto vf_ov1 = make_shared(ov_dir); + auto vf_ov2 = make_shared(ov_dir); + auto vf_sound = content_factory("test/data/sine_440.wav").front(); + auto vf_film = new_test_film2(name + "_vf", { vf_ov1, vf_ov2, vf_sound }); + vf_film->set_reel_type(ReelType::BY_VIDEO_CONTENT); + vf_ov2->set_position(vf_film, vf_ov1->end(vf_film)); + vf_ov1->set_reference_video(true); + vf_ov2->set_reference_video(true); + make_and_verify_dcp(vf_film, {dcp::VerificationNote::Code::EXTERNAL_ASSET}); + + auto const vf_dir = vf_film->dir(vf_film->dcp_name()); + + vector const args = { + "map_cli", + "-o", out, + "-d", ov_dir.string(), + "-d", vf_dir.string(), + "-l", + find_cpl(vf_dir).string() + }; + + boost::filesystem::remove_all(out); + + vector output_messages; + auto error = run(args, output_messages); + BOOST_CHECK(!error); + + verify_dcp(out, {}); + + check_file(find_file(out, "cpl_"), find_file(vf_dir, "cpl_")); + check_file(find_file(out, "j2c_"), find_file(ov_dir, "j2c_")); +} + + /** Map a single DCP into a new DCP using the rename option */ BOOST_AUTO_TEST_CASE(map_simple_dcp_copy_with_rename) {