diff options
| author | Carl Hetherington <cth@carlh.net> | 2018-04-20 23:41:21 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2018-08-17 00:46:19 +0100 |
| commit | 2f6087e528c1a48fed0ac7166b1ff8704684c87a (patch) | |
| tree | dcffc9da0bc8ec3341a7e8679284531836f7192f | |
| parent | b1a47060818175bf222da2ab11f7caec73f5a70c (diff) | |
Read PKL when reading DCP.
| -rw-r--r-- | src/asset.cc | 13 | ||||
| -rw-r--r-- | src/asset.h | 7 | ||||
| -rw-r--r-- | src/dcp.cc | 65 | ||||
| -rw-r--r-- | src/dcp.h | 20 | ||||
| -rw-r--r-- | src/pkl.cc | 114 | ||||
| -rw-r--r-- | src/pkl.h | 101 | ||||
| -rw-r--r-- | src/wscript | 1 |
7 files changed, 258 insertions, 63 deletions
diff --git a/src/asset.cc b/src/asset.cc index 7d3a9813..24fdfe6c 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -41,11 +41,13 @@ #include "exceptions.h" #include "dcp_assert.h" #include "compose.hpp" +#include "pkl.h" #include <libxml++/libxml++.h> #include <boost/algorithm/string.hpp> using std::string; using boost::function; +using boost::shared_ptr; using boost::optional; using namespace dcp; @@ -76,7 +78,7 @@ Asset::Asset (string id, boost::filesystem::path file) } void -Asset::write_to_pkl (xmlpp::Node* node, boost::filesystem::path root, Standard standard) const +Asset::add_to_pkl (shared_ptr<PKL> pkl, boost::filesystem::path root) const { DCP_ASSERT (_file); @@ -92,12 +94,7 @@ Asset::write_to_pkl (xmlpp::Node* node, boost::filesystem::path root, Standard s return; } - xmlpp::Node* asset = node->add_child ("Asset"); - asset->add_child("Id")->add_child_text ("urn:uuid:" + _id); - asset->add_child("AnnotationText")->add_child_text (_id); - asset->add_child("Hash")->add_child_text (hash ()); - asset->add_child("Size")->add_child_text (raw_convert<string> (boost::filesystem::file_size (_file.get()))); - asset->add_child("Type")->add_child_text (pkl_type (standard)); + pkl->add_asset (_id, _id, hash(), boost::filesystem::file_size (_file.get()), pkl_type (pkl->standard())); } void diff --git a/src/asset.h b/src/asset.h index 143c6296..f69be5a1 100644 --- a/src/asset.h +++ b/src/asset.h @@ -40,6 +40,7 @@ #include "object.h" #include "types.h" +#include "pkl.h" #include <boost/filesystem.hpp> #include <boost/function.hpp> #include <boost/bind.hpp> @@ -77,11 +78,7 @@ public: */ void write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const; - /** Write details of the asset to a PKL AssetList node. - * @param node Parent node. - * @param standard Standard to use. - */ - void write_to_pkl (xmlpp::Node* node, boost::filesystem::path root, Standard standard) const; + void add_to_pkl (boost::shared_ptr<PKL> pkl, boost::filesystem::path root) const; /** @return the most recent disk file used to read or write this asset, if there is one */ boost::optional<boost::filesystem::path> file () const { @@ -56,6 +56,7 @@ #include "dcp_assert.h" #include "reel_asset.h" #include "font_asset.h" +#include "pkl.h" #include <asdcp/AS_DCP.h> #include <xmlsec/xmldsig.h> #include <xmlsec/app.h> @@ -74,13 +75,15 @@ using std::cerr; using std::exception; using boost::shared_ptr; using boost::dynamic_pointer_cast; +using boost::optional; using boost::algorithm::starts_with; using namespace dcp; static string const assetmap_interop_ns = "http://www.digicine.com/PROTO-ASDCP-AM-20040311#"; static string const assetmap_smpte_ns = "http://www.smpte-ra.org/schemas/429-9/2007/AM"; -static string const pkl_interop_ns = "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#"; -static string const pkl_smpte_ns = "http://www.smpte-ra.org/schemas/429-8/2007/PKL"; +/* XXX: these can be removed when PKL is all in pkl.cc */ +static string const pkl_interop_ns = "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#"; +static string const pkl_smpte_ns = "http://www.smpte-ra.org/schemas/429-8/2007/PKL"; static string const volindex_interop_ns = "http://www.digicine.com/PROTO-ASDCP-VL-20040311#"; static string const volindex_smpte_ns = "http://www.smpte-ra.org/schemas/429-9/2007/AM"; @@ -134,6 +137,7 @@ DCP::read (bool keep_going, ReadErrors* errors, bool ignore_incorrect_picture_mx list<shared_ptr<cxml::Node> > asset_nodes = asset_map.node_child("AssetList")->node_children ("Asset"); map<string, boost::filesystem::path> paths; + optional<boost::filesystem::path> pkl_path; BOOST_FOREACH (shared_ptr<cxml::Node> i, asset_nodes) { if (i->node_child("ChunkList")->node_children("Chunk").size() != 1) { boost::throw_exception (XMLError ("unsupported asset chunk count")); @@ -143,8 +147,18 @@ DCP::read (bool keep_going, ReadErrors* errors, bool ignore_incorrect_picture_mx p = p.substr (7); } paths.insert (make_pair (remove_urn_uuid (i->string_child ("Id")), p)); + optional<string> pkl_bool = i->optional_string_child("PackingList"); + if (pkl_bool && *pkl_bool == "true") { + pkl_path = p; + } + } + + if (!pkl_path) { + boost::throw_exception (XMLError ("No packing list found in asset map")); } + _pkl.reset (new PKL (_directory / *pkl_path)); + /* Read all the assets from the asset map */ /* XXX: I think we should be looking at the PKL here to decide type, not the extension of the file. @@ -310,40 +324,6 @@ DCP::add (DecryptedKDM const & kdm) } } -/** @return full pathname of PKL file that was written */ -boost::filesystem::path -DCP::write_pkl (string file, Standard standard, string pkl_uuid, XMLMetadata metadata, shared_ptr<const CertificateChain> signer) const -{ - boost::filesystem::path p = _directory; - p /= file; - - xmlpp::Document doc; - xmlpp::Element* pkl; - if (standard == INTEROP) { - pkl = doc.create_root_node("PackingList", pkl_interop_ns); - } else { - pkl = doc.create_root_node("PackingList", pkl_smpte_ns); - } - - pkl->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid); - pkl->add_child("AnnotationText")->add_child_text (metadata.annotation_text); - pkl->add_child("IssueDate")->add_child_text (metadata.issue_date); - pkl->add_child("Issuer")->add_child_text (metadata.issuer); - pkl->add_child("Creator")->add_child_text (metadata.creator); - - xmlpp::Element* asset_list = pkl->add_child("AssetList"); - BOOST_FOREACH (shared_ptr<Asset> i, assets ()) { - i->write_to_pkl (asset_list, _directory, standard); - } - - if (signer) { - signer->sign (pkl, standard); - } - - doc.write_to_file (p.string (), "UTF-8"); - return p.string (); -} - /** Write the VOLINDEX file. * @param standard DCP standard to use (INTEROP or SMPTE) */ @@ -469,13 +449,20 @@ DCP::write_xml ( i->write_xml (_directory / (name_format.get(values, "_" + i->id() + ".xml")), standard, signer); } - string const pkl_uuid = make_uuid (); + if (!_pkl) { + _pkl.reset (new PKL (standard, metadata.annotation_text, metadata.issue_date, metadata.issuer, metadata.creator)); + BOOST_FOREACH (shared_ptr<Asset> i, assets ()) { + i->add_to_pkl (_pkl, _directory); + } + } + NameFormat::Map values; values['t'] = "pkl"; - boost::filesystem::path const pkl_path = write_pkl (name_format.get(values, "_" + pkl_uuid + ".xml"), standard, pkl_uuid, metadata, signer); + boost::filesystem::path pkl_path = _directory / name_format.get(values, "_" + _pkl->id() + ".xml"); + _pkl->write (pkl_path, signer); write_volindex (standard); - write_assetmap (standard, pkl_uuid, pkl_path, metadata); + write_assetmap (standard, _pkl->id(), pkl_path, metadata); } list<shared_ptr<CPL> > @@ -57,6 +57,7 @@ namespace xmlpp { namespace dcp { +class PKL; class Content; class Reel; class CPL; @@ -128,21 +129,17 @@ public: return _directory; } + /** @return PKL if this DCP was read from an existing one, or if write_xml() has been called on it. + * If neither is true, this method returns 0. + */ + boost::shared_ptr<PKL> pkl () const { + return _pkl; + } + static std::vector<boost::filesystem::path> directories_from_files (std::vector<boost::filesystem::path> files); private: - /** Write the PKL file. - * @param pkl_uuid UUID to use. - */ - boost::filesystem::path write_pkl ( - std::string file, - Standard standard, - std::string pkl_uuid, - XMLMetadata metadata, - boost::shared_ptr<const CertificateChain> signer - ) const; - void write_volindex (Standard standard) const; /** Write the ASSETMAP file. @@ -155,6 +152,7 @@ private: boost::filesystem::path _directory; /** the CPLs that make up this DCP */ std::list<boost::shared_ptr<CPL> > _cpls; + boost::shared_ptr<PKL> _pkl; /** Standard of DCP that was read in */ boost::optional<Standard> _standard; diff --git a/src/pkl.cc b/src/pkl.cc new file mode 100644 index 00000000..236313aa --- /dev/null +++ b/src/pkl.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2018 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 "pkl.h" +#include "exceptions.h" +#include "util.h" +#include "raw_convert.h" +#include <libxml++/libxml++.h> +#include <boost/foreach.hpp> + +using std::string; +using boost::shared_ptr; +using namespace dcp; + +static string const pkl_interop_ns = "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#"; +static string const pkl_smpte_ns = "http://www.smpte-ra.org/schemas/429-8/2007/PKL"; + +PKL::PKL (boost::filesystem::path file) +{ + cxml::Document pkl ("PackingList"); + pkl.read_file (file); + + if (pkl.namespace_uri() == pkl_interop_ns) { + _standard = INTEROP; + } else if (pkl.namespace_uri() == pkl_smpte_ns) { + _standard = SMPTE; + } else { + boost::throw_exception (XMLError ("Unrecognised packing list namesapce " + pkl.namespace_uri())); + } + + _id = remove_urn_uuid (pkl.string_child ("Id")); + _annotation_text = pkl.optional_string_child ("AnnotationText"); + _issue_date = pkl.string_child ("IssueDate"); + _issuer = pkl.string_child ("Issuer"); + _creator = pkl.string_child ("Creator"); + + BOOST_FOREACH (cxml::ConstNodePtr i, pkl.node_child("AssetList")->node_children("Asset")) { + _asset_list.push_back (shared_ptr<Asset> (new Asset (i))); + } +} + +void +PKL::add_asset (std::string id, boost::optional<std::string> annotation_text, std::string hash, int64_t size, std::string type) +{ + _asset_list.push_back (shared_ptr<Asset> (new Asset (id, annotation_text, hash, size, type))); +} + +void +PKL::write (boost::filesystem::path file, shared_ptr<const CertificateChain> signer) const +{ + xmlpp::Document doc; + xmlpp::Element* pkl; + if (_standard == INTEROP) { + pkl = doc.create_root_node("PackingList", pkl_interop_ns); + } else { + pkl = doc.create_root_node("PackingList", pkl_smpte_ns); + } + + pkl->add_child("Id")->add_child_text ("urn:uuid:" + _id); + if (_annotation_text) { + pkl->add_child("AnnotationText")->add_child_text (*_annotation_text); + } + pkl->add_child("IssueDate")->add_child_text (_issue_date); + pkl->add_child("Issuer")->add_child_text (_issuer); + pkl->add_child("Creator")->add_child_text (_creator); + + xmlpp::Element* asset_list = pkl->add_child("AssetList"); + BOOST_FOREACH (shared_ptr<Asset> i, _asset_list) { + xmlpp::Element* asset = asset_list->add_child("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + i->id()); + if (i->annotation_text) { + asset->add_child("AnnotationText")->add_child_text (*i->annotation_text); + } + asset->add_child("Hash")->add_child_text (i->hash); + asset->add_child("Size")->add_child_text (raw_convert<string> (i->size)); + asset->add_child("Type")->add_child_text (i->type); + } + + if (signer) { + signer->sign (pkl, _standard); + } + + doc.write_to_file (file.string(), "UTF-8"); +} diff --git a/src/pkl.h b/src/pkl.h new file mode 100644 index 00000000..3b960ddf --- /dev/null +++ b/src/pkl.h @@ -0,0 +1,101 @@ +/* + Copyright (C) 2018 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. +*/ + +#ifndef LIBDCP_PKL_H +#define LIBDCP_PKL_H + +#include "object.h" +#include "types.h" +#include "certificate_chain.h" +#include <libcxml/cxml.h> +#include <boost/filesystem.hpp> + +namespace dcp { + +class PKL : public Object +{ +public: + PKL (Standard standard, boost::optional<std::string> annotation_text, std::string issue_date, std::string issuer, std::string creator) + : _standard (standard) + , _annotation_text (annotation_text) + , _issue_date (issue_date) + , _issuer (issuer) + , _creator (creator) + {} + + explicit PKL (boost::filesystem::path file); + + Standard standard () const { + return _standard; + } + + void add_asset (std::string id, boost::optional<std::string> annotation_text, std::string hash, int64_t size, std::string type); + void write (boost::filesystem::path file, boost::shared_ptr<const CertificateChain> signer) const; + +private: + + class Asset : public Object + { + public: + Asset (cxml::ConstNodePtr node) + : annotation_text (node->optional_string_child("AnnotationText")) + , hash (node->string_child("Hash")) + , size (node->number_child<int64_t>("Size")) + , type (node->string_child("Type")) + {} + + Asset (std::string id_, boost::optional<std::string> annotation_text_, std::string hash_, int64_t size_, std::string type_) + : Object (id_) + , annotation_text (annotation_text_) + , hash (hash_) + , size (size_) + , type (type_) + {} + + boost::optional<std::string> annotation_text; + std::string hash; + int64_t size; + std::string type; + }; + + Standard _standard; + boost::optional<std::string> _annotation_text; + std::string _issue_date; + std::string _issuer; + std::string _creator; + std::list<boost::shared_ptr<Asset> > _asset_list; +}; + +} + +#endif diff --git a/src/wscript b/src/wscript index 93415b4d..180b7b49 100644 --- a/src/wscript +++ b/src/wscript @@ -71,6 +71,7 @@ def build(bld): openjpeg_image.cc picture_asset.cc picture_asset_writer.cc + pkl.cc raw_convert.cc reel.cc reel_asset.cc |
