diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-09-09 23:55:49 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-09-17 23:07:19 +0200 |
| commit | c19f63dd173e5497070b26528dbac240d5595583 (patch) | |
| tree | 6a2f3760005a1ef8a613ffec5d3df82b1574a61f /src | |
| parent | 62757708dd14df8806eb6482e83afb06a6160f0a (diff) | |
Add dcp::combine().
Diffstat (limited to 'src')
| -rw-r--r-- | src/combine.cc | 165 | ||||
| -rw-r--r-- | src/combine.h | 45 | ||||
| -rw-r--r-- | src/dcp.cc | 2 | ||||
| -rw-r--r-- | src/exceptions.cc | 6 | ||||
| -rw-r--r-- | src/exceptions.h | 7 | ||||
| -rw-r--r-- | src/wscript | 2 |
6 files changed, 226 insertions, 1 deletions
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 <cth@carlh.net> + + 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 <http://www.gnu.org/licenses/>. + + 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 <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <set> +#include <string> +#include <vector> + + +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<string>(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<boost::filesystem::path> inputs, boost::filesystem::path output, shared_ptr<const CertificateChain> signer) +{ + using namespace boost::filesystem; + + DCP_ASSERT (!inputs.empty()); + + DCP output_dcp (output); + optional<dcp::Standard> 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<path> paths; + list<shared_ptr<dcp::Asset> > assets; + + BOOST_FOREACH (path i, inputs) { + DCP dcp (i); + dcp.read (); + + BOOST_FOREACH (shared_ptr<dcp::CPL> j, dcp.cpls()) { + output_dcp.add (j); + } + + BOOST_FOREACH (shared_ptr<dcp::Asset> j, dcp.assets(true)) { + if (dynamic_pointer_cast<dcp::CPL>(j)) { + continue; + } + + optional<path> file = j->file(); + DCP_ASSERT (file); + path new_path = make_unique(output / file->filename()); + + shared_ptr<dcp::InteropSubtitleAsset> sub = dynamic_pointer_cast<dcp::InteropSubtitleAsset>(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<string, path> fonts = sub->font_filenames (); + for (map<string, path>::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<dcp::FontAsset>(j)) { + /* Take care of everything else that's not a Interop subtitle asset, Interop font file + * or CPL. + */ + optional<path> 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 <cth@carlh.net> + + 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 <http://www.gnu.org/licenses/>. + + 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 <boost/filesystem.hpp> + + +namespace dcp { + +class CertificateChain; + +void combine (std::vector<boost::filesystem::path> inputs, boost::filesystem::path output, boost::shared_ptr<const CertificateChain> signer = boost::shared_ptr<CertificateChain>()); + +} + @@ -117,7 +117,7 @@ DCP::read (list<dcp::VerificationNote>* 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<int> 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<int> _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 |
