From c19f63dd173e5497070b26528dbac240d5595583 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 9 Sep 2020 23:55:49 +0200 Subject: Add dcp::combine(). --- src/combine.cc | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/combine.h | 45 +++++++++++++++ src/dcp.cc | 2 +- src/exceptions.cc | 6 ++ src/exceptions.h | 7 +++ src/wscript | 2 + 6 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 src/combine.cc create mode 100644 src/combine.h (limited to 'src') diff --git a/src/combine.cc b/src/combine.cc new file mode 100644 index 00000000..0e262fce --- /dev/null +++ b/src/combine.cc @@ -0,0 +1,165 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include "asset.h" +#include "combine.h" +#include "cpl.h" +#include "dcp.h" +#include "dcp_assert.h" +#include "exceptions.h" +#include "font_asset.h" +#include "interop_subtitle_asset.h" +#include "raw_convert.h" +#include +#include +#include +#include +#include + + +using std::list; +using std::map; +using std::set; +using std::string; +using std::vector; +using boost::dynamic_pointer_cast; +using boost::optional; +using boost::shared_ptr; + + +boost::filesystem::path +make_unique (boost::filesystem::path path) +{ + if (!boost::filesystem::exists(path)) { + return path; + } + + for (int i = 0; i < 10000; ++i) { + boost::filesystem::path p = path.parent_path() / (path.stem().string() + dcp::raw_convert(i) + path.extension().string()); + if (!boost::filesystem::exists(p)) { + return p; + } + } + + DCP_ASSERT (false); + return path; +} + + +static +void +create_hard_link_or_copy (boost::filesystem::path from, boost::filesystem::path to) +{ + try { + create_hard_link (from, to); + } catch (boost::filesystem::filesystem_error& e) { + if (e.code() == boost::system::errc::cross_device_link) { + copy_file (from, to); + } else { + throw; + } + } +} + + +void +dcp::combine (vector inputs, boost::filesystem::path output, shared_ptr signer) +{ + using namespace boost::filesystem; + + DCP_ASSERT (!inputs.empty()); + + DCP output_dcp (output); + optional standard; + + BOOST_FOREACH (path i, inputs) { + DCP dcp (i); + dcp.read (); + if (!standard) { + standard = *dcp.standard(); + } else if (standard != dcp.standard()) { + throw CombineError ("Cannot combine Interop and SMPTE DCPs."); + } + } + + list paths; + list > assets; + + BOOST_FOREACH (path i, inputs) { + DCP dcp (i); + dcp.read (); + + BOOST_FOREACH (shared_ptr j, dcp.cpls()) { + output_dcp.add (j); + } + + BOOST_FOREACH (shared_ptr j, dcp.assets(true)) { + if (dynamic_pointer_cast(j)) { + continue; + } + + optional file = j->file(); + DCP_ASSERT (file); + path new_path = make_unique(output / file->filename()); + + shared_ptr sub = dynamic_pointer_cast(j); + if (sub) { + /* Interop fonts are really fiddly. The font files are assets (in the ASSETMAP) + * and also linked from the font XML by filename. We have to fix both these things, + * and re-write the font XML file since the font URI might have changed if it's a duplicate + * with another DCP. + */ + map fonts = sub->font_filenames (); + for (map::const_iterator k = fonts.begin(); k != fonts.end(); ++k) { + sub->set_font_file (k->first, make_unique(output / k->second.filename())); + } + sub->write (new_path); + } else if (!dynamic_pointer_cast(j)) { + /* Take care of everything else that's not a Interop subtitle asset, Interop font file + * or CPL. + */ + optional file = j->file(); + DCP_ASSERT (file); + path new_path = make_unique(output / file->filename()); + create_hard_link_or_copy (*file, new_path); + j->set_file (new_path); + } + + assets.push_back (j); + } + } + + output_dcp.resolve_refs (assets); + output_dcp.write_xml (*standard, dcp::XMLMetadata(), signer); +} diff --git a/src/combine.h b/src/combine.h new file mode 100644 index 00000000..5d40d4d1 --- /dev/null +++ b/src/combine.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include + + +namespace dcp { + +class CertificateChain; + +void combine (std::vector inputs, boost::filesystem::path output, boost::shared_ptr signer = boost::shared_ptr()); + +} + diff --git a/src/dcp.cc b/src/dcp.cc index 08785e55..b7a0da8b 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -117,7 +117,7 @@ DCP::read (list* notes, bool ignore_incorrect_picture_mxf } else if (boost::filesystem::exists (_directory / "ASSETMAP.xml")) { _asset_map = _directory / "ASSETMAP.xml"; } else { - boost::throw_exception (ReadError (String::compose ("could not find ASSETMAP nor ASSETMAP.xml in `%1'", _directory.string()))); + boost::throw_exception (ReadError(String::compose("Could not find ASSETMAP nor ASSETMAP.xml in '%1'", _directory.string()))); } cxml::Document asset_map ("AssetMap"); diff --git a/src/exceptions.cc b/src/exceptions.cc index 3357ebe9..0256c2b5 100644 --- a/src/exceptions.cc +++ b/src/exceptions.cc @@ -131,3 +131,9 @@ StartCompressionError::StartCompressionError (optional code) , _code (code) {} + + +CombineError::CombineError (string message) + : runtime_error (message) +{} + diff --git a/src/exceptions.h b/src/exceptions.h index 7ed729dd..1fb5e4e7 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -240,6 +240,13 @@ private: boost::optional _code; }; + +class CombineError : public std::runtime_error +{ +public: + explicit CombineError (std::string message); +}; + } #endif diff --git a/src/wscript b/src/wscript index 8dd856c6..fd215d76 100644 --- a/src/wscript +++ b/src/wscript @@ -44,6 +44,7 @@ def build(bld): certificate.cc chromaticity.cc colour_conversion.cc + combine.cc cpl.cc data.cc dcp.cc @@ -122,6 +123,7 @@ def build(bld): certificate.h chromaticity.h colour_conversion.h + combine.h cpl.h crypto_context.h dcp.h -- cgit v1.2.3