summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/argb_frame.cc8
-rw-r--r--src/argb_frame.h18
-rw-r--r--src/asset.cc141
-rw-r--r--src/asset.h149
-rw-r--r--src/certificates.cc57
-rw-r--r--src/certificates.h31
-rw-r--r--src/colour_matrix.cc8
-rw-r--r--src/colour_matrix.h4
-rw-r--r--src/content.cc70
-rw-r--r--src/content.h83
-rw-r--r--src/cpl.cc331
-rw-r--r--src/cpl.h127
-rw-r--r--src/dcp.cc468
-rw-r--r--src/dcp.h101
-rw-r--r--src/dcp_time.cc36
-rw-r--r--src/dcp_time.h8
-rw-r--r--src/exceptions.cc14
-rw-r--r--src/exceptions.h52
-rw-r--r--src/file.cc46
-rw-r--r--src/file.h (renamed from src/rec709_linearised_gamma_lut.cc)45
-rw-r--r--src/font.cc (renamed from src/parse/subtitle.cc)84
-rw-r--r--src/font.h (renamed from src/parse/subtitle.h)65
-rw-r--r--src/gamma_lut.cc31
-rw-r--r--src/gamma_lut.h36
-rw-r--r--src/image.cc6
-rw-r--r--src/image.h4
-rw-r--r--src/kdm.cc58
-rw-r--r--src/kdm.h14
-rw-r--r--src/kdm_smpte_xml.h (renamed from src/xml/kdm_smpte.h)22
-rw-r--r--src/key.cc20
-rw-r--r--src/key.h9
-rw-r--r--src/load_font.cc (renamed from src/rec709_linearised_gamma_lut.h)18
-rw-r--r--src/load_font.h (renamed from src/srgb_linearised_gamma_lut.h)20
-rw-r--r--src/lut_cache.h26
-rw-r--r--src/metadata.cc16
-rw-r--r--src/metadata.h12
-rw-r--r--src/mono_picture_asset.cc200
-rw-r--r--src/mono_picture_asset.h64
-rw-r--r--src/mono_picture_frame.cc26
-rw-r--r--src/mono_picture_frame.h20
-rw-r--r--src/mono_picture_mxf.cc137
-rw-r--r--src/mono_picture_mxf.h62
-rw-r--r--src/mono_picture_mxf_writer.cc (renamed from src/mono_picture_asset_writer.cc)46
-rw-r--r--src/mono_picture_mxf_writer.h (renamed from src/mono_picture_asset_writer.h)31
-rw-r--r--src/mxf.cc (renamed from src/mxf_asset.cc)91
-rw-r--r--src/mxf.h (renamed from src/mxf_asset.h)81
-rw-r--r--src/mxf_writer.cc53
-rw-r--r--src/mxf_writer.h62
-rw-r--r--src/object.cc44
-rw-r--r--src/object.h (renamed from src/srgb_linearised_gamma_lut.cc)44
-rw-r--r--src/parse/asset_map.cc79
-rw-r--r--src/parse/asset_map.h81
-rw-r--r--src/parse/cpl.cc151
-rw-r--r--src/parse/cpl.h163
-rw-r--r--src/parse/pkl.cc52
-rw-r--r--src/picture_asset.h107
-rw-r--r--src/picture_mxf.cc (renamed from src/picture_asset.cc)87
-rw-r--r--src/picture_mxf.h114
-rw-r--r--src/picture_mxf_writer.cc (renamed from src/picture_asset_writer.cc)25
-rw-r--r--src/picture_mxf_writer.h (renamed from src/picture_asset_writer.h)52
-rw-r--r--src/picture_mxf_writer_common.cc (renamed from src/picture_asset_writer_common.cc)17
-rw-r--r--src/reel.cc104
-rw-r--r--src/reel.h61
-rw-r--r--src/reel_asset.cc104
-rw-r--r--src/reel_asset.h113
-rw-r--r--src/reel_mono_picture_asset.cc54
-rw-r--r--src/reel_mono_picture_asset.h49
-rw-r--r--src/reel_picture_asset.cc91
-rw-r--r--src/reel_picture_asset.h59
-rw-r--r--src/reel_sound_asset.cc48
-rw-r--r--src/reel_sound_asset.h53
-rw-r--r--src/reel_stereo_picture_asset.cc67
-rw-r--r--src/reel_stereo_picture_asset.h51
-rw-r--r--src/reel_subtitle_asset.cc48
-rw-r--r--src/reel_subtitle_asset.h52
-rw-r--r--src/ref.h120
-rw-r--r--src/rgb_xyz.cc21
-rw-r--r--src/rgb_xyz.h10
-rw-r--r--src/signer.cc52
-rw-r--r--src/signer.h29
-rw-r--r--src/signer_chain.cc49
-rw-r--r--src/signer_chain.h8
-rw-r--r--src/sound_asset.cc401
-rw-r--r--src/sound_asset.h134
-rw-r--r--src/sound_frame.cc16
-rw-r--r--src/sound_frame.h20
-rw-r--r--src/sound_mxf.cc178
-rw-r--r--src/sound_mxf.h78
-rw-r--r--src/sound_mxf_writer.cc120
-rw-r--r--src/sound_mxf_writer.h55
-rw-r--r--src/stereo_picture_frame.cc20
-rw-r--r--src/stereo_picture_frame.h14
-rw-r--r--src/stereo_picture_mxf.cc (renamed from src/stereo_picture_asset.cc)125
-rw-r--r--src/stereo_picture_mxf.h (renamed from src/stereo_picture_asset.h)33
-rw-r--r--src/stereo_picture_mxf_writer.cc (renamed from src/stereo_picture_asset_writer.cc)54
-rw-r--r--src/stereo_picture_mxf_writer.h (renamed from src/stereo_picture_asset_writer.h)19
-rw-r--r--src/subtitle.cc60
-rw-r--r--src/subtitle.h (renamed from src/lut.h)62
-rw-r--r--src/subtitle_asset.h207
-rw-r--r--src/subtitle_content.cc (renamed from src/subtitle_asset.cc)275
-rw-r--r--src/subtitle_content.h113
-rw-r--r--src/subtitle_string.cc107
-rw-r--r--src/subtitle_string.h129
-rw-r--r--src/text.cc49
-rw-r--r--src/text.h (renamed from src/parse/pkl.h)56
-rw-r--r--src/types.cc54
-rw-r--r--src/types.h42
-rw-r--r--src/util.cc172
-rw-r--r--src/util.h39
-rw-r--r--src/version.h2
-rw-r--r--src/wscript79
-rw-r--r--src/xml.h6
-rw-r--r--src/xyz_frame.cc22
-rw-r--r--src/xyz_frame.h24
114 files changed, 4495 insertions, 3640 deletions
diff --git a/src/argb_frame.cc b/src/argb_frame.cc
index a48f80bb..99d6c814 100644
--- a/src/argb_frame.cc
+++ b/src/argb_frame.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,9 +17,13 @@
*/
+/** @file src/argb_frame.cc
+ * @brief ARGBFrame class.
+ */
+
#include "argb_frame.h"
-using namespace libdcp;
+using namespace dcp;
/** Construct an empty ARGBFrame of a given size and with
* undefined contents.
diff --git a/src/argb_frame.h b/src/argb_frame.h
index f26436cd..419227bb 100644
--- a/src/argb_frame.h
+++ b/src/argb_frame.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,13 +18,13 @@
*/
/** @file src/argb_frame.h
- * @brief Container for a single image from a picture asset.
+ * @brief ARGBFrame class.
*/
-#include <stdint.h>
#include "util.h"
+#include <stdint.h>
-namespace libdcp
+namespace dcp
{
/** @class ARGBFrame
@@ -42,26 +42,28 @@ namespace libdcp
*
* Lines are packed so that the second row directly follows the first.
*/
-class ARGBFrame
+class ARGBFrame : boost::noncopyable
{
public:
ARGBFrame (Size size);
~ARGBFrame ();
+ /** @return pointer to the image data */
uint8_t* data () const {
return _data;
}
- /** Length of one picture row in bytes */
+ /** @return length of one picture row in bytes */
int stride () const;
+ /** @return size of the picture in pixels */
Size size () const {
return _size;
}
private:
- Size _size;
- uint8_t* _data;
+ Size _size; ///< frame size in pixels
+ uint8_t* _data; ///< pointer to image data
};
}
diff --git a/src/asset.cc b/src/asset.cc
index d51b78fd..aaa79dc7 100644
--- a/src/asset.cc
+++ b/src/asset.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,111 +18,106 @@
*/
/** @file src/asset.cc
- * @brief Parent class for assets of DCPs.
+ * @brief Asset class.
*/
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/function.hpp>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
#include "asset.h"
#include "util.h"
-#include "metadata.h"
+#include "exceptions.h"
#include "compose.hpp"
+#include <libxml++/libxml++.h>
+#include <boost/lexical_cast.hpp>
+
+using std::string;
+using boost::lexical_cast;
+using boost::function;
+using boost::optional;
+using namespace dcp;
-using namespace std;
-using namespace boost;
-using namespace libdcp;
-
-Asset::Asset (boost::filesystem::path directory, boost::filesystem::path file_name)
- : _directory (directory)
- , _file_name (file_name)
- , _uuid (make_uuid ())
- , _edit_rate (0)
- , _entry_point (0)
- , _intrinsic_duration (0)
- , _duration (0)
+/** Create an Asset with a randomly-generated ID */
+Asset::Asset ()
{
- if (_file_name.empty ()) {
- _file_name = _uuid + ".xml";
- }
+
+}
+
+/** Create an Asset from a given file. The ID will
+ * be extracted from the file.
+ * @param file File name.
+ */
+Asset::Asset (boost::filesystem::path file)
+ : _file (file)
+{
+
+}
+
+/** Create an Asset with a specified ID.
+ * @param id ID to use.
+ */
+Asset::Asset (string id)
+ : Object (id)
+{
+
}
void
-Asset::write_to_pkl (xmlpp::Node* node, bool interop) const
+Asset::write_to_pkl (xmlpp::Node* node, Standard standard) const
{
+ assert (!_file.empty ());
+
xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid);
- asset->add_child("AnnotationText")->add_child_text (_file_name.string ());
- asset->add_child("Hash")->add_child_text (digest ());
- asset->add_child("Size")->add_child_text (lexical_cast<string> (filesystem::file_size(path())));
- if (interop) {
- asset->add_child("Type")->add_child_text (String::compose ("application/x-smpte-mxf;asdcpKind=%1", asdcp_kind ()));
- } else {
- asset->add_child("Type")->add_child_text ("application/mxf");
- }
+ 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 (lexical_cast<string> (boost::filesystem::file_size (_file)));
+ asset->add_child("Type")->add_child_text (pkl_type (standard));
}
void
-Asset::write_to_assetmap (xmlpp::Node* node) const
+Asset::write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const
{
+ assert (!_file.empty ());
+
xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid);
+ asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
xmlpp::Node* chunk_list = asset->add_child ("ChunkList");
xmlpp::Node* chunk = chunk_list->add_child ("Chunk");
- chunk->add_child("Path")->add_child_text (_file_name.string ());
+ optional<boost::filesystem::path> path = relative_to_root (root, _file);
+ if (!path) {
+ throw MiscError (String::compose ("Asset %1 is not within the directory %2", _file, root));
+ }
+ chunk->add_child("Path")->add_child_text (path.get().string ());
chunk->add_child("VolumeIndex")->add_child_text ("1");
chunk->add_child("Offset")->add_child_text ("0");
- chunk->add_child("Length")->add_child_text (lexical_cast<string> (filesystem::file_size(path())));
-}
-
-filesystem::path
-Asset::path () const
-{
- filesystem::path p;
- p /= _directory;
- p /= _file_name;
- return p;
+ chunk->add_child("Length")->add_child_text (lexical_cast<string> (boost::filesystem::file_size (_file)));
}
string
-Asset::digest () const
-{
- if (_digest.empty ()) {
- _digest = make_digest (path().string(), 0);
- }
-
- return _digest;
-}
-
-void
-Asset::compute_digest (boost::function<void (float)> progress)
+Asset::hash (function<void (float)> progress) const
{
- if (!_digest.empty ()) {
- return;
+ assert (!_file.empty ());
+
+ if (_hash.empty ()) {
+ _hash = make_digest (_file, progress);
}
- _digest = make_digest (path().string(), &progress);
+ return _hash;
}
bool
-Asset::equals (shared_ptr<const Asset> other, EqualityOptions, boost::function<void (NoteType, string)> note) const
+Asset::equals (boost::shared_ptr<const Asset> other, EqualityOptions, function<void (NoteType, string)> note) const
{
- if (_edit_rate != other->_edit_rate) {
- note (ERROR, "asset edit rates differ");
+ if (_hash != other->_hash) {
+ note (ERROR, "Asset hashes differ");
return false;
}
-
- if (_intrinsic_duration != other->_intrinsic_duration) {
- note (ERROR, "asset intrinsic durations differ");
- }
-
- if (_duration != other->_duration) {
- note (ERROR, "asset durations differ");
- }
return true;
}
+
+void
+Asset::set_file (boost::filesystem::path file) const
+{
+ _file = boost::filesystem::absolute (file);
+ _hash.clear ();
+}
+
diff --git a/src/asset.h b/src/asset.h
index 773e3d48..bad982f1 100644
--- a/src/asset.h
+++ b/src/asset.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,141 +18,70 @@
*/
/** @file src/asset.h
- * @brief Parent class for assets of DCPs.
- */
+ * @brief Asset class.
+ */
#ifndef LIBDCP_ASSET_H
#define LIBDCP_ASSET_H
-#include <string>
-#include <list>
+#include "object.h"
+#include "types.h"
#include <boost/filesystem.hpp>
#include <boost/function.hpp>
-#include <libxml++/libxml++.h>
-#include "types.h"
-
-namespace ASDCP {
- class WriterInfo;
-}
+#include <boost/bind.hpp>
namespace xmlpp {
- class Element;
+ class Node;
}
-namespace libdcp
-{
+namespace dcp {
-/** @brief Parent class for assets of DCPs
+/** @class Asset
+ * @brief Parent class for DCP assets, i.e. picture/sound/subtitles and CPLs.
*
- * These are collections of pictures or sound.
+ * Note that this class is not used for ReelAssets; those are just for the metadata
+ * that gets put into &lt;Reel&gt;s.
*/
-class Asset
+class Asset : public Object
{
public:
- /** Construct an Asset.
- * @param directory Directory where our XML or MXF file is.
- * @param file_name Name of our file within directory, or empty to make one up based on UUID.
+ Asset ();
+ Asset (boost::filesystem::path file);
+ Asset (std::string id);
+
+ virtual bool equals (
+ boost::shared_ptr<const Asset> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ /** Write details of the asset to a ASSETMAP.
+ * @param node Parent node.
*/
- Asset (boost::filesystem::path directory, boost::filesystem::path file_name = "");
-
- virtual ~Asset() {}
-
- /** Write details of the asset to a CPL AssetList node.
- * @param p Parent element.
- */
- virtual void write_to_cpl (xmlpp::Element* p) const = 0;
+ void write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const;
/** Write details of the asset to a PKL AssetList node.
- * @param p Parent node.
- */
- void write_to_pkl (xmlpp::Node *, bool interop) const;
-
- /** Write details of the asset to a ASSETMAP stream.
- * @param s Stream.
+ * @param node Parent node.
+ * @param standard Standard to use.
*/
- void write_to_assetmap (xmlpp::Node *) const;
-
- /** Compute the digest for this asset. Calling this is optional: if
- * it is not called, the digest will be computed when required. However,
- * calling this method allows the caller to see the progress of the
- * computation, which can be long for large assets.
- * @param Called with progress between 0 and 1.
- */
- void compute_digest (boost::function<void (float)> progress);
-
- std::string uuid () const {
- return _uuid;
- }
+ void write_to_pkl (xmlpp::Node* node, Standard standard) const;
- boost::filesystem::path path () const;
-
- void set_directory (boost::filesystem::path d) {
- _directory = d;
- }
-
- void set_file_name (boost::filesystem::path f) {
- _file_name = f;
- }
-
- int entry_point () const {
- return _entry_point;
+ boost::filesystem::path file () const {
+ return _file;
}
- int duration () const {
- return _duration;
- }
-
- int intrinsic_duration () const {
- return _intrinsic_duration;
- }
-
- int edit_rate () const {
- return _edit_rate;
- }
-
- void set_entry_point (int e) {
- _entry_point = e;
- }
-
- void set_duration (int d) {
- _duration = d;
- }
-
- void set_intrinsic_duration (int d) {
- _intrinsic_duration = d;
- }
-
- void set_edit_rate (int r) {
- _edit_rate = r;
- }
+ void set_file (boost::filesystem::path file) const;
- virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)>) const;
+ /** @return the hash of this asset's file */
+ std::string hash (boost::function<void (float)> progress = 0) const;
protected:
+ virtual std::string pkl_type (Standard standard) const = 0;
- /** @return Interop PKL asdcpKind for the &lt;Type&gt; tag e.g. Picture, Sound etc. */
- virtual std::string asdcp_kind () const = 0;
-
- std::string digest () const;
-
- /** Directory that our MXF or XML file is in */
- boost::filesystem::path _directory;
- /** Name of our MXF or XML file */
- boost::filesystem::path _file_name;
- /** Our UUID */
- std::string _uuid;
- /** The edit rate; this is normally equal to the number of video frames per second */
- int _edit_rate;
- /** Start point to present in frames */
- int _entry_point;
- /** Total length in frames */
- int _intrinsic_duration;
- /** Length to present in frames */
- int _duration;
-
-private:
- /** Digest of our MXF or XML file */
- mutable std::string _digest;
+ /** The disk file that represents this asset, if one exists */
+ mutable boost::filesystem::path _file;
+ /** Hash of _file, or empty if the hash has not yet been computed */
+ mutable std::string _hash;
};
}
diff --git a/src/certificates.cc b/src/certificates.cc
index 2f5d47fd..0a0393c6 100644
--- a/src/certificates.cc
+++ b/src/certificates.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,27 +17,27 @@
*/
-#include <sstream>
-#include <vector>
-#include <cerrno>
-#include <boost/algorithm/string.hpp>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-#include <openssl/asn1.h>
-#include <openssl/err.h>
-#include <libxml++/nodes/element.h>
+/** @file src/certificates.cc
+ * @brief Certificate and CertificateChain classes.
+ */
+
#include "KM_util.h"
#include "certificates.h"
#include "compose.hpp"
#include "exceptions.h"
#include "util.h"
+#include <libxml++/nodes/element.h>
+#include <openssl/x509.h>
+#include <openssl/ssl.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <boost/algorithm/string.hpp>
+#include <cerrno>
using std::list;
using std::string;
-using std::stringstream;
-using std::vector;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** @param c X509 certificate, which this object will take ownership of */
Certificate::Certificate (X509* c)
@@ -47,6 +47,9 @@ Certificate::Certificate (X509* c)
}
+/** Load an X509 certificate from a file.
+ * @param filename File to load.
+ */
Certificate::Certificate (boost::filesystem::path filename)
: _certificate (0)
, _public_key (0)
@@ -61,6 +64,9 @@ Certificate::Certificate (boost::filesystem::path filename)
}
}
+/** Load an X509 certificate from a string.
+ * @param cert String to read from.
+ */
Certificate::Certificate (string cert)
: _certificate (0)
, _public_key (0)
@@ -68,6 +74,9 @@ Certificate::Certificate (string cert)
read_string (cert);
}
+/** Copy constructor.
+ * @param other Certificate to copy.
+ */
Certificate::Certificate (Certificate const & other)
: _certificate (0)
, _public_key (0)
@@ -75,6 +84,9 @@ Certificate::Certificate (Certificate const & other)
read_string (other.certificate (true));
}
+/** Read a certificate from a string.
+ * @param cert String to read.
+ */
void
Certificate::read_string (string cert)
{
@@ -91,12 +103,16 @@ Certificate::read_string (string cert)
BIO_free (bio);
}
+/** Destructor */
Certificate::~Certificate ()
{
X509_free (_certificate);
RSA_free (_public_key);
}
+/** operator= for Certificate.
+ * @param other Certificate to read from.
+ */
Certificate &
Certificate::operator= (Certificate const & other)
{
@@ -114,6 +130,10 @@ Certificate::operator= (Certificate const & other)
return *this;
}
+/** Return the certificate as a string.
+ * @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
+ * @return Certificate string.
+ */
string
Certificate::certificate (bool with_begin_end) const
{
@@ -143,6 +163,10 @@ Certificate::certificate (bool with_begin_end) const
return s;
}
+/** @return Certificate's issuer, in the form
+ * dnqualifier=&lt;dnQualififer&gt;,CN=&lt;commonName&gt;,OU=&lt;organizationalUnitName&gt,O=&lt;organizationName&gt;
+ * and with + signs escaped to \+
+ */
string
Certificate::issuer () const
{
@@ -244,6 +268,7 @@ Certificate::thumbprint () const
return Kumu::base64encode (digest, 20, digest_base64, 64);
}
+/** @return RSA public key from this Certificate. Caller must not free the returned value. */
RSA *
Certificate::public_key () const
{
@@ -266,6 +291,7 @@ Certificate::public_key () const
return _public_key;
}
+/** @return Root certificate */
shared_ptr<Certificate>
CertificateChain::root () const
{
@@ -273,6 +299,7 @@ CertificateChain::root () const
return _certificates.front ();
}
+/** @return Leaf certificate */
shared_ptr<Certificate>
CertificateChain::leaf () const
{
@@ -280,6 +307,7 @@ CertificateChain::leaf () const
return _certificates.back ();
}
+/** @return Certificates in order from leaf to root */
list<shared_ptr<Certificate> >
CertificateChain::leaf_to_root () const
{
@@ -288,6 +316,9 @@ CertificateChain::leaf_to_root () const
return c;
}
+/** Add a certificate to the end of the chain.
+ * @param c Certificate to add.
+ */
void
CertificateChain::add (shared_ptr<Certificate> c)
{
diff --git a/src/certificates.h b/src/certificates.h
index 2bf8d0db..96a8cbb7 100644
--- a/src/certificates.h
+++ b/src/certificates.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,16 +17,19 @@
*/
+/** @file src/certificates.h
+ * @brief Certificate and CertificateChain classes.
+ */
+
#ifndef LIBDCP_CERTIFICATES_H
#define LIBDCP_CERTIFICATES_H
-#include <string>
-#include <list>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/filesystem.hpp>
#undef X509_NAME
#include <openssl/x509.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <list>
class certificates;
@@ -34,8 +37,13 @@ namespace xmlpp {
class Element;
}
-namespace libdcp {
+namespace dcp {
+/** @class Certificate
+ * @brief A wrapper for an X509 certificate.
+ *
+ * This class can take a Certificate from a file, a string or an OpenSSL X509 object.
+ */
class Certificate
{
public:
@@ -51,16 +59,12 @@ public:
Certificate& operator= (Certificate const &);
- /** @param with_begin_end true to include BEGIN CERTIFICATE / END CERTIFICATE markers
- * @return the whole certificate as a string.
- */
std::string certificate (bool with_begin_end = false) const;
std::string issuer () const;
std::string serial () const;
std::string subject () const;
std::string common_name () const;
- /** @return RSA public key from this Certificate. Caller must not free the returned value. */
RSA* public_key () const;
std::string thumbprint () const;
@@ -76,12 +80,15 @@ private:
mutable RSA* _public_key;
};
+/** @class CertificateChain
+ * @brief A chain of any number of certificates, from root to leaf.
+ */
class CertificateChain
{
public:
CertificateChain () {}
- void add (boost::shared_ptr<Certificate>);
+ void add (boost::shared_ptr<Certificate> c);
boost::shared_ptr<Certificate> root () const;
boost::shared_ptr<Certificate> leaf () const;
diff --git a/src/colour_matrix.cc b/src/colour_matrix.cc
index b633e384..72f952c3 100644
--- a/src/colour_matrix.cc
+++ b/src/colour_matrix.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,19 +23,19 @@
EasyDCP player, I think.
*/
-double const libdcp::colour_matrix::xyz_to_rgb[3][3] = {
+double const dcp::colour_matrix::xyz_to_rgb[3][3] = {
{ 3.24096989631653, -1.5373831987381, -0.498610764741898 },
{ -0.96924364566803, 1.87596750259399, 0.0415550582110882 },
{ 0.0556300804018974, -0.203976958990097, 1.05697154998779 }
};
-double const libdcp::colour_matrix::srgb_to_xyz[3][3] = {
+double const dcp::colour_matrix::srgb_to_xyz[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
-double const libdcp::colour_matrix::rec709_to_xyz[3][3] = {
+double const dcp::colour_matrix::rec709_to_xyz[3][3] = {
{ 0.412390799265959, 0.357584339383878, 0.180480788401834 },
{ 0.21263900587151, 0.715168678767756, 0.0721923153607337 },
{ 0.0193308187155918, 0.119194779794626, 0.950532152249661 }
diff --git a/src/colour_matrix.h b/src/colour_matrix.h
index 615e8b38..ce15051c 100644
--- a/src/colour_matrix.h
+++ b/src/colour_matrix.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
*/
-namespace libdcp {
+namespace dcp {
namespace colour_matrix {
diff --git a/src/content.cc b/src/content.cc
new file mode 100644
index 00000000..50db005a
--- /dev/null
+++ b/src/content.cc
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "content.h"
+#include "util.h"
+#include "metadata.h"
+#include "AS_DCP.h"
+#include "KM_util.h"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+#include <iostream>
+
+/* We need this here for the #undef ERROR for Windows */
+#include "types.h"
+
+using namespace std;
+using namespace boost;
+using namespace dcp;
+
+Content::Content (boost::filesystem::path file)
+ : Asset (file)
+ , _edit_rate (24, 1)
+ , _intrinsic_duration (0)
+{
+
+}
+
+Content::Content (Fraction edit_rate)
+ : _edit_rate (edit_rate)
+ , _intrinsic_duration (0)
+{
+
+}
+
+bool
+Content::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!Asset::equals (other, opt, note)) {
+ return false;
+ }
+
+ if (_edit_rate != other->_edit_rate) {
+ note (ERROR, "content edit rates differ");
+ return false;
+ }
+
+ if (_intrinsic_duration != other->_intrinsic_duration) {
+ note (ERROR, "asset intrinsic durations differ");
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/content.h b/src/content.h
new file mode 100644
index 00000000..2059c8f5
--- /dev/null
+++ b/src/content.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/content.h
+ * @brief Content class.
+ */
+
+#ifndef LIBDCP_CONTENT_H
+#define LIBDCP_CONTENT_H
+
+#include "types.h"
+#include "asset.h"
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+#include <string>
+#include <list>
+
+namespace ASDCP {
+ class WriterInfo;
+}
+
+namespace xmlpp {
+ class Element;
+}
+
+namespace dcp
+{
+
+/** @class Content
+ * @brief An asset that represents a piece of content, i.e. picture, sound or subtitle.
+ *
+ * Such a piece of content will be contained in a file (either MXF or XML) within a DCP.
+ */
+class Content : public Asset
+{
+public:
+ Content (boost::filesystem::path file);
+ Content (Fraction edit_rate);
+ virtual ~Content () {}
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)>
+ ) const;
+
+ Fraction edit_rate () const {
+ return _edit_rate;
+ }
+
+ int64_t intrinsic_duration () const {
+ return _intrinsic_duration;
+ }
+
+protected:
+ friend class MXFWriter;
+
+ virtual std::string asdcp_kind () const = 0;
+
+ Fraction _edit_rate;
+ int64_t _intrinsic_duration;
+};
+
+}
+
+#endif
diff --git a/src/cpl.cc b/src/cpl.cc
index e333df0d..9eae09ad 100644
--- a/src/cpl.cc
+++ b/src/cpl.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,20 +17,22 @@
*/
-#include <libxml/parser.h>
#include "cpl.h"
-#include "parse/cpl.h"
#include "util.h"
-#include "mono_picture_asset.h"
-#include "stereo_picture_asset.h"
-#include "sound_asset.h"
-#include "subtitle_asset.h"
-#include "parse/asset_map.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
#include "reel.h"
#include "metadata.h"
#include "signer.h"
#include "exceptions.h"
+#include "xml.h"
#include "compose.hpp"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
+#include <libxml/parser.h>
using std::string;
using std::stringstream;
@@ -41,167 +43,78 @@ using std::make_pair;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::optional;
-using namespace libdcp;
+using namespace dcp;
-CPL::CPL (boost::filesystem::path directory, string name, ContentKind content_kind, int length, int frames_per_second)
- : _directory (directory)
- , _name (name)
+CPL::CPL (string annotation_text, ContentKind content_kind)
+ : _annotation_text (annotation_text)
+ /* default _content_title_text to _annotation_text */
+ , _content_title_text (annotation_text)
, _content_kind (content_kind)
- , _length (length)
- , _fps (frames_per_second)
+ , _content_version_id ("urn:uuid:" + make_uuid ())
{
- _id = make_uuid ();
+ /* default _content_version_id to and _content_version_label to
+ a random ID and the current time.
+ */
+ time_t now = time (0);
+ struct tm* tm = localtime (&now);
+ _content_version_id = "urn:uuid:" + make_uuid() + tm_to_string (tm);
+ _content_version_label_text = _content_version_id;
}
-/** Construct a CPL object from a XML file.
- * @param directory The directory containing this CPL's DCP.
- * @param file The CPL XML filename.
- * @param asset_maps AssetMaps to look for assets in.
- * @param require_mxfs true to throw an exception if a required MXF file does not exist.
- */
-CPL::CPL (boost::filesystem::path directory, string file, list<PathAssetMap> asset_maps, bool require_mxfs)
- : _directory (directory)
+/** Construct a CPL object from a XML file */
+CPL::CPL (boost::filesystem::path file)
+ : Asset (file)
, _content_kind (FEATURE)
- , _length (0)
- , _fps (0)
{
- /* Read the XML */
- shared_ptr<parse::CPL> cpl;
- try {
- cpl.reset (new parse::CPL (file));
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load CPL file", file, e.number ()));
- }
-
- /* Now cherry-pick the required bits into our own data structure */
-
- _name = cpl->annotation_text;
- _content_kind = cpl->content_kind;
-
- /* Trim urn:uuid: off the front */
- _id = cpl->id.substr (9);
-
- for (list<shared_ptr<parse::Reel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) {
-
- shared_ptr<parse::Picture> p;
-
- if ((*i)->asset_list->main_picture) {
- p = (*i)->asset_list->main_picture;
- } else {
- p = (*i)->asset_list->main_stereoscopic_picture;
- }
-
- _fps = p->edit_rate.numerator;
- _length += p->duration;
-
- shared_ptr<PictureAsset> picture;
- shared_ptr<SoundAsset> sound;
- shared_ptr<SubtitleAsset> subtitle;
-
- /* Some rather twisted logic to decide if we are 3D or not;
- some DCPs give a MainStereoscopicPicture to indicate 3D, others
- just have a FrameRate twice the EditRate and apparently
- expect you to divine the fact that they are hence 3D.
- */
-
- if (!(*i)->asset_list->main_stereoscopic_picture && p->edit_rate == p->frame_rate) {
-
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
-
- picture.reset (new MonoPictureAsset (asset.first, asset.second->chunks.front()->path));
+ cxml::Document f ("CompositionPlaylist");
+ f.read_file (file);
- picture->read ();
- picture->set_edit_rate (_fps);
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
- if (p->key_id.length() > 9) {
- /* Trim urn:uuid: */
- picture->set_key_id (p->key_id.substr (9));
- }
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- } else {
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
-
- picture.reset (new StereoPictureAsset (asset.first, asset.second->chunks.front()->path));
-
- picture->read ();
- picture->set_edit_rate (_fps);
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
- if (p->key_id.length() > 9) {
- /* Trim urn:uuid: */
- picture->set_key_id (p->key_id.substr (9));
- }
-
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- }
-
- if ((*i)->asset_list->main_sound) {
-
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_sound->id);
-
- sound.reset (new SoundAsset (asset.first, asset.second->chunks.front()->path));
- shared_ptr<parse::MainSound> s = (*i)->asset_list->main_sound;
-
- sound->read ();
- sound->set_entry_point (s->entry_point);
- sound->set_duration (s->duration);
- if (s->key_id.length() > 9) {
- /* Trim urn:uuid: */
- sound->set_key_id (s->key_id.substr (9));
- }
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
- }
-
- if ((*i)->asset_list->main_subtitle) {
-
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_subtitle->id);
+ _id = f.string_child ("Id");
+ if (_id.length() > 9) {
+ _id = _id.substr (9);
+ }
+ _annotation_text = f.optional_string_child ("AnnotationText").get_value_or ("");
+ _metadata.issuer = f.optional_string_child ("Issuer").get_value_or ("");
+ _metadata.creator = f.optional_string_child ("Creator").get_value_or ("");
+ _metadata.issue_date = f.string_child ("IssueDate");
+ _content_title_text = f.string_child ("ContentTitleText");
+ _content_kind = content_kind_from_string (f.string_child ("ContentKind"));
+ shared_ptr<cxml::Node> content_version = f.optional_node_child ("ContentVersion");
+ if (content_version) {
+ _content_version_id = content_version->optional_string_child ("Id").get_value_or ("");
+ _content_version_label_text = content_version->string_child ("LabelText");
+ content_version->done ();
+ }
+ f.ignore_child ("RatingList");
+ _reels = type_grand_children<Reel> (f, "ReelList", "Reel");
- subtitle.reset (new SubtitleAsset (asset.first, asset.second->chunks.front()->path));
+ f.ignore_child ("Issuer");
+ f.ignore_child ("Signer");
+ f.ignore_child ("Signature");
- subtitle->set_entry_point ((*i)->asset_list->main_subtitle->entry_point);
- subtitle->set_duration ((*i)->asset_list->main_subtitle->duration);
- }
-
- _reels.push_back (shared_ptr<Reel> (new Reel (picture, sound, subtitle)));
- }
+ f.done ();
}
+/** Add a reel to this CPL.
+ * @param reel Reel to add.
+ */
void
-CPL::add_reel (shared_ptr<Reel> reel)
+CPL::add (boost::shared_ptr<Reel> reel)
{
_reels.push_back (reel);
}
+/** Write an CompositonPlaylist XML file.
+ * @param file Filename to write.
+ * @param standard INTEROP or SMPTE.
+ * @param signer Signer to sign the CPL, or 0 to add no signature.
+ */
void
-CPL::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+CPL::write_xml (boost::filesystem::path file, Standard standard, shared_ptr<const Signer> signer) const
{
- boost::filesystem::path p;
- p /= _directory;
- stringstream s;
- s << _id << "_cpl.xml";
- p /= s.str();
-
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+ if (standard == INTEROP) {
root = doc.create_root_node ("CompositionPlaylist", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#");
} else {
root = doc.create_root_node ("CompositionPlaylist", "http://www.smpte-ra.org/schemas/429-7/2006/CPL");
@@ -212,90 +125,61 @@ CPL::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Sig
}
root->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- root->add_child("AnnotationText")->add_child_text (_name);
- root->add_child("IssueDate")->add_child_text (metadata.issue_date);
- root->add_child("Issuer")->add_child_text (metadata.issuer);
- root->add_child("Creator")->add_child_text (metadata.creator);
- root->add_child("ContentTitleText")->add_child_text (_name);
+ root->add_child("AnnotationText")->add_child_text (_annotation_text);
+ root->add_child("IssueDate")->add_child_text (_metadata.issue_date);
+ root->add_child("Issuer")->add_child_text (_metadata.issuer);
+ root->add_child("Creator")->add_child_text (_metadata.creator);
+ root->add_child("ContentTitleText")->add_child_text (_content_title_text);
root->add_child("ContentKind")->add_child_text (content_kind_to_string (_content_kind));
{
xmlpp::Node* cv = root->add_child ("ContentVersion");
- cv->add_child ("Id")->add_child_text ("urn:uri:" + _id + "_" + metadata.issue_date);
- cv->add_child ("LabelText")->add_child_text (_id + "_" + metadata.issue_date);
+ cv->add_child ("Id")->add_child_text (_content_version_id);
+ cv->add_child ("LabelText")->add_child_text (_content_version_label_text);
}
root->add_child("RatingList");
xmlpp::Element* reel_list = root->add_child ("ReelList");
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->write_to_cpl (reel_list);
+ (*i)->write_to_cpl (reel_list, standard);
}
if (signer) {
- signer->sign (root, interop);
+ signer->sign (root, standard);
}
/* This must not be the _formatted version otherwise signature digests will be wrong */
- doc.write_to_file (p.string (), "UTF-8");
+ doc.write_to_file (file.string (), "UTF-8");
- _digest = make_digest (p.string (), 0);
- _length = boost::filesystem::file_size (p.string ());
+ set_file (file);
}
-void
-CPL::write_to_pkl (xmlpp::Node* node, bool interop) const
+list<shared_ptr<const Content> >
+CPL::content () const
{
- xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- asset->add_child("Hash")->add_child_text (_digest);
- asset->add_child("Size")->add_child_text (lexical_cast<string> (_length));
- if (interop) {
- asset->add_child("Type")->add_child_text ("text/xml;asdcpKind=CPL");
- } else {
- asset->add_child("Type")->add_child_text ("text/xml");
- }
-}
+ list<shared_ptr<const Content> > c;
-list<shared_ptr<const Asset> >
-CPL::assets () const
-{
- list<shared_ptr<const Asset> > a;
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
if ((*i)->main_picture ()) {
- a.push_back ((*i)->main_picture ());
+ c.push_back ((*i)->main_picture()->mxf ());
}
if ((*i)->main_sound ()) {
- a.push_back ((*i)->main_sound ());
+ c.push_back ((*i)->main_sound()->mxf ());
}
if ((*i)->main_subtitle ()) {
- a.push_back ((*i)->main_subtitle ());
+ c.push_back ((*i)->main_subtitle()->subtitle_content ());
}
}
- return a;
-}
-
-void
-CPL::write_to_assetmap (xmlpp::Node* node) const
-{
- xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- xmlpp::Node* chunk_list = asset->add_child ("ChunkList");
- xmlpp::Node* chunk = chunk_list->add_child ("Chunk");
- chunk->add_child("Path")->add_child_text (_id + "_cpl.xml");
- chunk->add_child("VolumeIndex")->add_child_text ("1");
- chunk->add_child("Offset")->add_child_text("0");
- chunk->add_child("Length")->add_child_text(lexical_cast<string> (_length));
+ return c;
}
-
-
bool
CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- if (_name != other._name && !opt.cpl_names_can_differ) {
+ if (_annotation_text != other._annotation_text && !opt.cpl_annotation_texts_can_differ) {
stringstream s;
- s << "names differ: " << _name << " vs " << other._name << "\n";
+ s << "annotation texts differ: " << _annotation_text << " vs " << other._annotation_text << "\n";
note (ERROR, s.str ());
return false;
}
@@ -305,16 +189,6 @@ CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteT
return false;
}
- if (_fps != other._fps) {
- note (ERROR, String::compose ("frames per second differ (%1 vs %2)", _fps, other._fps));
- return false;
- }
-
- if (_length != other._length) {
- stringstream s;
- note (ERROR, String::compose ("lengths differ (%1 vs %2)", _length, other._length));
- }
-
if (_reels.size() != other._reels.size()) {
note (ERROR, String::compose ("reel counts differ (%1 vs %2)", _reels.size(), other._reels.size()));
return false;
@@ -347,31 +221,48 @@ CPL::encrypted () const
return false;
}
+/** Add a KDM to this CPL. If the KDM is for any of this CPLs assets it will be used
+ * to decrypt those assets.
+ * @param kdm KDM.
+ */
void
-CPL::add_kdm (KDM const & kdm)
+CPL::add (KDM const & kdm)
{
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->add_kdm (kdm);
+ (*i)->add (kdm);
}
}
-pair<string, shared_ptr<const parse::AssetMapAsset> >
-CPL::asset_from_id (list<PathAssetMap> asset_maps, string id) const
+/** Set a private key for every MXF referenced by this CPL. This will allow the data
+ * to be decrypted or encrypted.
+ * @param key Key to use.
+ */
+void
+CPL::set_mxf_keys (Key key)
{
- for (list<PathAssetMap>::const_iterator i = asset_maps.begin(); i != asset_maps.end(); ++i) {
- shared_ptr<parse::AssetMapAsset> a = i->second->asset_from_id (id);
- if (a) {
- return make_pair (i->first, a);
- }
+ for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
+ (*i)->set_mxf_keys (key);
}
-
- return make_pair ("", shared_ptr<const parse::AssetMapAsset> ());
}
void
-CPL::set_mxf_keys (Key key)
+CPL::resolve_refs (list<shared_ptr<Object> > objects)
{
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->set_mxf_keys (key);
+ (*i)->resolve_refs (objects);
}
}
+
+string
+CPL::pkl_type (Standard standard) const
+{
+ switch (standard) {
+ case INTEROP:
+ return "text/xml;asdcpKind=CPL";
+ case SMPTE:
+ return "text/xml";
+ default:
+ assert (false);
+ }
+}
+
diff --git a/src/cpl.h b/src/cpl.h
index c50d8f90..8458a028 100644
--- a/src/cpl.h
+++ b/src/cpl.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,45 +20,66 @@
#ifndef LIBDCP_CPL_H
#define LIBDCP_CPL_H
-#include <list>
+#include "types.h"
+#include "certificates.h"
+#include "key.h"
+#include "asset.h"
+#include "metadata.h"
+#include <libxml++/libxml++.h>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/optional.hpp>
#include <boost/filesystem.hpp>
-#include <libxml++/libxml++.h>
-#include "types.h"
-#include "certificates.h"
-#include "key.h"
-
-namespace libdcp {
+#include <list>
-namespace parse {
- class AssetMap;
- class AssetMapAsset;
-}
+namespace dcp {
-class Asset;
+class Content;
class Reel;
class XMLMetadata;
class MXFMetadata;
class Signer;
class KDM;
-/** @brief A CPL within a DCP */
-class CPL
+/** @class CPL
+ * @brief A Composition Playlist.
+ */
+class CPL : public Asset
{
public:
- CPL (boost::filesystem::path directory, std::string name, ContentKind content_kind, int length, int frames_per_second);
- CPL (boost::filesystem::path, std::string file, std::list<PathAssetMap> asset_maps, bool require_mxfs = true);
+ CPL (std::string annotation_text, ContentKind content_kind);
+ CPL (boost::filesystem::path file);
- void add_reel (boost::shared_ptr<Reel> reel);
+ bool equals (
+ CPL const & other,
+ EqualityOptions options,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ void add (boost::shared_ptr<Reel> reel);
+ void add (KDM const &);
+
+ /** @return contents of the &lt;AnnotationText&gt; node */
+ std::string annotation_text () const {
+ return _annotation_text;
+ }
- /** @return the length in frames */
- int length () const {
- return _length;
+ /** @return contents of the &lt;ContentTitleText&gt; node */
+ std::string content_title_text () const {
+ return _content_title_text;
+ }
+
+ /** @return contents of the &lt;Id&gt; node within &lt;ContentVersion&gt; */
+ void set_content_version_id (std::string id) {
+ _content_version_id = id;
}
+ /** @return contents of the &lt;LabelText&gt; node within &lt;ContentVersion&gt; */
+ void set_content_version_label_text (std::string text) {
+ _content_version_label_text = text;
+ }
+
/** @return the type of the content, used by media servers
* to categorise things (e.g. feature, trailer, etc.)
*/
@@ -66,59 +87,43 @@ public:
return _content_kind;
}
+ /** @return the reels in this CPL */
std::list<boost::shared_ptr<Reel> > reels () const {
return _reels;
}
- /** @return the CPL's name, as will be presented on projector
- * media servers and theatre management systems.
+ /** @return the Content in this CPL across all its reels
+ * (Content is picture, sound and subtitles)
*/
- std::string name () const {
- return _name;
- }
-
- /** @return the number of frames per second */
- int frames_per_second () const {
- return _fps;
- }
-
- std::list<boost::shared_ptr<const Asset> > assets () const;
+ std::list<boost::shared_ptr<const Content> > content () const;
bool encrypted () const;
void set_mxf_keys (Key);
- std::string id () const {
- return _id;
- }
-
- bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
-
- void write_xml (bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
- void write_to_assetmap (xmlpp::Node *) const;
- void write_to_pkl (xmlpp::Node *, bool) const;
+ void write_xml (
+ boost::filesystem::path file,
+ Standard standard,
+ boost::shared_ptr<const Signer>
+ ) const;
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
+
+protected:
+ /** @return type string for PKLs for this asset */
+ std::string pkl_type (Standard standard) const;
- void add_kdm (KDM const &);
-
private:
- std::pair<std::string, boost::shared_ptr<const parse::AssetMapAsset> > asset_from_id (std::list<PathAssetMap>, std::string id) const;
-
- boost::filesystem::path _directory;
- /** the name of the DCP */
- std::string _name;
- /** the content kind of the CPL */
- ContentKind _content_kind;
- /** length in frames */
- mutable int _length;
- /** frames per second */
- int _fps;
- /** reels */
+ std::string _annotation_text; ///< &lt;AnnotationText&gt;
+ /** &lt;Issuer&gt;, &lt;Creator&gt; and &lt;IssueDate&gt;. These are grouped
+ * because they occur together in a few places.
+ */
+ XMLMetadata _metadata;
+ std::string _content_title_text; ///< &lt;ContentTitleText&gt;
+ ContentKind _content_kind; ///< &lt;ContentKind&gt;
+ std::string _content_version_id; ///< &lt;Id&gt; in &lt;ContentVersion&gt;
+ std::string _content_version_label_text; ///< &lt;LabelText&gt; in &lt;ContentVersion&gt;
std::list<boost::shared_ptr<Reel> > _reels;
-
- /** our UUID */
- std::string _id;
- /** a SHA1 digest of our XML */
- mutable std::string _digest;
};
}
diff --git a/src/dcp.cc b/src/dcp.cc
index ae692256..88e36506 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,80 +18,207 @@
*/
/** @file src/dcp.cc
- * @brief A class to create a DCP.
+ * @brief DCP class.
*/
-#include <sstream>
-#include <iomanip>
-#include <cassert>
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/libxml++.h>
-#include <xmlsec/xmldsig.h>
-#include <xmlsec/app.h>
#include "dcp.h"
-#include "asset.h"
-#include "sound_asset.h"
-#include "picture_asset.h"
-#include "subtitle_asset.h"
+#include "sound_mxf.h"
+#include "picture_mxf.h"
+#include "subtitle_content.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
#include "util.h"
#include "metadata.h"
#include "exceptions.h"
-#include "parse/pkl.h"
-#include "parse/asset_map.h"
#include "reel.h"
#include "cpl.h"
#include "signer.h"
#include "kdm.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/app.h>
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+#include <iostream>
using std::string;
using std::list;
using std::stringstream;
using std::ostream;
-using std::copy;
-using std::back_inserter;
using std::make_pair;
+using std::map;
using boost::shared_ptr;
using boost::lexical_cast;
-using namespace libdcp;
+using namespace dcp;
DCP::DCP (boost::filesystem::path directory)
: _directory (directory)
{
boost::filesystem::create_directories (directory);
+ _directory = boost::filesystem::canonical (_directory);
}
void
-DCP::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+DCP::read ()
{
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_xml (interop, metadata, signer);
+ /* Read the ASSETMAP */
+
+ boost::filesystem::path asset_map_file;
+ if (boost::filesystem::exists (_directory / "ASSETMAP")) {
+ asset_map_file = _directory / "ASSETMAP";
+ } else if (boost::filesystem::exists (_directory / "ASSETMAP.xml")) {
+ asset_map_file = _directory / "ASSETMAP.xml";
+ } else {
+ boost::throw_exception (DCPReadError ("could not find AssetMap file"));
}
- string pkl_uuid = make_uuid ();
- string pkl_path = write_pkl (pkl_uuid, interop, metadata, signer);
+ cxml::Document asset_map ("AssetMap");
+ asset_map.read_file (asset_map_file);
+ list<shared_ptr<cxml::Node> > asset_nodes = asset_map.node_child("AssetList")->node_children ("Asset");
+ map<string, boost::filesystem::path> paths;
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = asset_nodes.begin(); i != asset_nodes.end(); ++i) {
+ if ((*i)->node_child("ChunkList")->node_children("Chunk").size() != 1) {
+ boost::throw_exception (XMLError ("unsupported asset chunk count"));
+ }
+ paths.insert (make_pair (
+ (*i)->string_child ("Id"),
+ (*i)->node_child("ChunkList")->node_child("Chunk")->string_child ("Path")
+ ));
+ }
+
+ /* Read all the assets from the asset map */
- write_volindex (interop);
- write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path), interop, metadata);
+ for (map<string, boost::filesystem::path>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+ boost::filesystem::path path = _directory / i->second;
+ if (boost::algorithm::ends_with (path.string(), ".xml")) {
+ xmlpp::DomParser* p = new xmlpp::DomParser;
+ try {
+ p->parse_file (path.string());
+ } catch (std::exception& e) {
+ delete p;
+ continue;
+ }
+
+ string const root = p->get_document()->get_root_node()->get_name ();
+ delete p;
+
+ if (root == "CompositionPlaylist") {
+ _assets.push_back (shared_ptr<CPL> (new CPL (path)));
+ } else if (root == "DCSubtitle") {
+ _assets.push_back (shared_ptr<SubtitleContent> (new SubtitleContent (path)));
+ }
+ } else if (boost::algorithm::ends_with (path.string(), ".mxf")) {
+ ASDCP::EssenceType_t type;
+ if (ASDCP::EssenceType (path.string().c_str(), type) != ASDCP::RESULT_OK) {
+ throw DCPReadError ("Could not find essence type");
+ }
+ switch (type) {
+ case ASDCP::ESS_UNKNOWN:
+ case ASDCP::ESS_MPEG2_VES:
+ throw DCPReadError ("MPEG2 video essences are not supported");
+ case ASDCP::ESS_JPEG_2000:
+ _assets.push_back (shared_ptr<MonoPictureMXF> (new MonoPictureMXF (path)));
+ break;
+ case ASDCP::ESS_PCM_24b_48k:
+ case ASDCP::ESS_PCM_24b_96k:
+ _assets.push_back (shared_ptr<SoundMXF> (new SoundMXF (path)));
+ break;
+ case ASDCP::ESS_JPEG_2000_S:
+ _assets.push_back (shared_ptr<StereoPictureMXF> (new StereoPictureMXF (path)));
+ break;
+ default:
+ throw DCPReadError ("Unknown MXF essence type");
+ }
+ }
+ }
+
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ (*i)->resolve_refs (list_of_type<Asset, Object> (assets ()));
+ }
}
-std::string
-DCP::write_pkl (string pkl_uuid, bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+bool
+DCP::equals (DCP const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- assert (!_cpls.empty ());
+ if (_assets.size() != other._assets.size()) {
+ note (ERROR, "Asset counts differ");
+ return false;
+ }
+
+ list<shared_ptr<Asset> >::const_iterator a = _assets.begin ();
+ list<shared_ptr<Asset> >::const_iterator b = other._assets.begin ();
+
+ while (a != _assets.end ()) {
+ if (!(*a)->equals (*b, opt, note)) {
+ return false;
+ }
+ ++a;
+ ++b;
+ }
+
+ return true;
+}
+
+void
+DCP::add (boost::shared_ptr<Asset> asset)
+{
+ _assets.push_back (asset);
+}
+
+class AssetComparator
+{
+public:
+ bool operator() (shared_ptr<const Content> a, shared_ptr<const Content> b) {
+ return a->id() < b->id();
+ }
+};
+
+bool
+DCP::encrypted () const
+{
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ if ((*i)->encrypted ()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+DCP::add (KDM const & kdm)
+{
+ list<KDMKey> keys = kdm.keys ();
+ list<shared_ptr<CPL> > cpl = cpls ();
- boost::filesystem::path p;
- p /= _directory;
+ for (list<shared_ptr<CPL> >::iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
+ if (j->cpl_id() == (*i)->id()) {
+ (*i)->add (kdm);
+ }
+ }
+ }
+}
+
+boost::filesystem::path
+DCP::write_pkl (Standard standard, string pkl_uuid, XMLMetadata metadata, shared_ptr<const Signer> signer) const
+{
+ boost::filesystem::path p = _directory;
stringstream s;
s << pkl_uuid << "_pkl.xml";
p /= s.str();
xmlpp::Document doc;
xmlpp::Element* pkl;
- if (interop) {
+ if (standard == INTEROP) {
pkl = doc.create_root_node("PackingList", "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#");
} else {
pkl = doc.create_root_node("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL");
@@ -102,83 +229,112 @@ DCP::write_pkl (string pkl_uuid, bool interop, XMLMetadata const & metadata, sha
}
pkl->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid);
+
/* XXX: this is a bit of a hack */
- pkl->add_child("AnnotationText")->add_child_text(_cpls.front()->name());
+ assert (cpls().size() > 0);
+ pkl->add_child("AnnotationText")->add_child_text (cpls().front()->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");
- list<shared_ptr<const Asset> > a = assets ();
- for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
- (*i)->write_to_pkl (asset_list, interop);
- }
-
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_to_pkl (asset_list, interop);
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_pkl (asset_list, standard);
}
if (signer) {
- signer->sign (pkl, interop);
+ 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)
+ */
void
-DCP::write_volindex (bool interop) const
+DCP::write_volindex (Standard standard) const
{
- boost::filesystem::path p;
- p /= _directory;
- if (interop) {
+ boost::filesystem::path p = _directory;
+ switch (standard) {
+ case INTEROP:
p /= "VOLINDEX";
- } else {
+ break;
+ case SMPTE:
p /= "VOLINDEX.xml";
+ break;
+ default:
+ assert (false);
}
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
root = doc.create_root_node ("VolumeIndex", "http://www.digicine.com/PROTO-ASDCP-AM-20040311#");
- } else {
+ break;
+ case SMPTE:
root = doc.create_root_node ("VolumeIndex", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
+ break;
+ default:
+ assert (false);
}
+
root->add_child("Index")->add_child_text ("1");
doc.write_to_file (p.string (), "UTF-8");
}
void
-DCP::write_assetmap (string pkl_uuid, int pkl_length, bool interop, XMLMetadata const & metadata) const
+DCP::write_assetmap (Standard standard, string pkl_uuid, int pkl_length, XMLMetadata metadata) const
{
- boost::filesystem::path p;
- p /= _directory;
- if (interop) {
+ boost::filesystem::path p = _directory;
+
+ switch (standard) {
+ case INTEROP:
p /= "ASSETMAP";
- } else {
+ break;
+ case SMPTE:
p /= "ASSETMAP.xml";
+ break;
+ default:
+ assert (false);
}
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
root = doc.create_root_node ("AssetMap", "http://www.digicine.com/PROTO-ASDCP-AM-20040311#");
- } else {
+ break;
+ case SMPTE:
root = doc.create_root_node ("AssetMap", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
+ break;
+ default:
+ assert (false);
}
root->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
root->add_child("AnnotationText")->add_child_text ("Created by " + metadata.creator);
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
root->add_child("VolumeCount")->add_child_text ("1");
root->add_child("IssueDate")->add_child_text (metadata.issue_date);
root->add_child("Issuer")->add_child_text (metadata.issuer);
root->add_child("Creator")->add_child_text (metadata.creator);
- } else {
+ break;
+ case SMPTE:
root->add_child("Creator")->add_child_text (metadata.creator);
root->add_child("VolumeCount")->add_child_text ("1");
root->add_child("IssueDate")->add_child_text (metadata.issue_date);
root->add_child("Issuer")->add_child_text (metadata.issuer);
+ break;
+ default:
+ assert (false);
}
xmlpp::Node* asset_list = root->add_child ("AssetList");
@@ -193,187 +349,41 @@ DCP::write_assetmap (string pkl_uuid, int pkl_length, bool interop, XMLMetadata
chunk->add_child("Offset")->add_child_text ("0");
chunk->add_child("Length")->add_child_text (lexical_cast<string> (pkl_length));
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_to_assetmap (asset_list);
- }
-
- list<shared_ptr<const Asset> > a = assets ();
- for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
- (*i)->write_to_assetmap (asset_list);
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_assetmap (asset_list, _directory);
}
/* This must not be the _formatted version otherwise signature digests will be wrong */
doc.write_to_file (p.string (), "UTF-8");
}
+/** Write all the XML files for this DCP.
+ * @param standand INTEROP or SMPTE.
+ * @param metadata Metadata to use for PKL and asset map files.
+ * @param signer Signer to use, or 0.
+ */
void
-DCP::read (bool require_mxfs)
-{
- read_assets ();
- read_cpls (require_mxfs);
-}
-
-void
-DCP::read_assets ()
-{
- shared_ptr<parse::AssetMap> asset_map;
- try {
- boost::filesystem::path p = _directory;
- p /= "ASSETMAP";
- if (boost::filesystem::exists (p)) {
- asset_map.reset (new libdcp::parse::AssetMap (p.string ()));
- } else {
- p = _directory;
- p /= "ASSETMAP.xml";
- if (boost::filesystem::exists (p)) {
- asset_map.reset (new libdcp::parse::AssetMap (p.string ()));
- } else {
- boost::throw_exception (DCPReadError ("could not find AssetMap file"));
- }
- }
-
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load AssetMap file", _files.asset_map, e.number ()));
- }
-
- for (list<shared_ptr<libdcp::parse::AssetMapAsset> >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) {
- if ((*i)->chunks.size() != 1) {
- boost::throw_exception (XMLError ("unsupported asset chunk count"));
- }
-
- boost::filesystem::path t = _directory;
- t /= (*i)->chunks.front()->path;
-
- if (boost::algorithm::ends_with (t.string(), ".mxf") || boost::algorithm::ends_with (t.string(), ".ttf")) {
- continue;
- }
-
- xmlpp::DomParser* p = new xmlpp::DomParser;
- try {
- p->parse_file (t.string());
- } catch (std::exception& e) {
- delete p;
- continue;
- }
-
- string const root = p->get_document()->get_root_node()->get_name ();
- delete p;
-
- if (root == "CompositionPlaylist") {
- _files.cpls.push_back (t.string());
- } else if (root == "PackingList") {
- if (_files.pkl.empty ()) {
- _files.pkl = t.string();
- } else {
- boost::throw_exception (DCPReadError ("duplicate PKLs found"));
- }
- }
- }
-
- if (_files.cpls.empty ()) {
- boost::throw_exception (DCPReadError ("no CPL files found"));
- }
-
- if (_files.pkl.empty ()) {
- boost::throw_exception (DCPReadError ("no PKL file found"));
- }
-
- shared_ptr<parse::PKL> pkl;
- try {
- pkl.reset (new parse::PKL (_files.pkl));
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load PKL file", _files.pkl, e.number ()));
- }
-
- _asset_maps.push_back (make_pair (boost::filesystem::absolute (_directory).string(), asset_map));
-}
-
-void
-DCP::read_cpls (bool require_mxfs)
-{
- for (list<string>::iterator i = _files.cpls.begin(); i != _files.cpls.end(); ++i) {
- _cpls.push_back (shared_ptr<CPL> (new CPL (_directory, *i, _asset_maps, require_mxfs)));
- }
-}
-
-bool
-DCP::equals (DCP const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (_cpls.size() != other._cpls.size()) {
- note (ERROR, "CPL counts differ");
- return false;
- }
-
- list<shared_ptr<CPL> >::const_iterator a = _cpls.begin ();
- list<shared_ptr<CPL> >::const_iterator b = other._cpls.begin ();
-
- while (a != _cpls.end ()) {
- if (!(*a)->equals (*b->get(), opt, note)) {
- return false;
- }
- ++a;
- ++b;
- }
-
- return true;
-}
-
-void
-DCP::add_cpl (shared_ptr<CPL> cpl)
-{
- _cpls.push_back (cpl);
-}
-
-class AssetComparator
-{
-public:
- bool operator() (shared_ptr<const Asset> a, shared_ptr<const Asset> b) {
- return a->uuid() < b->uuid();
- }
-};
-
-list<shared_ptr<const Asset> >
-DCP::assets () const
-{
- list<shared_ptr<const Asset> > a;
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- list<shared_ptr<const Asset> > t = (*i)->assets ();
- a.merge (t);
- }
-
- a.sort (AssetComparator ());
- a.unique ();
- return a;
-}
-
-bool
-DCP::encrypted () const
+DCP::write_xml (
+ Standard standard,
+ XMLMetadata metadata,
+ shared_ptr<const Signer> signer
+ )
{
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- if ((*i)->encrypted ()) {
- return true;
- }
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ string const filename = (*i)->id() + "_cpl.xml";
+ (*i)->write_xml (_directory / filename, standard, signer);
}
- return false;
-}
-
-void
-DCP::add_kdm (KDM const & kdm)
-{
- list<KDMKey> keys = kdm.keys ();
+ string const pkl_uuid = make_uuid ();
+ boost::filesystem::path const pkl_path = write_pkl (standard, pkl_uuid, metadata, signer);
- for (list<shared_ptr<CPL> >::iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
- if (j->cpl_id() == (*i)->id()) {
- (*i)->add_kdm (kdm);
- }
- }
- }
+ write_volindex (standard);
+ write_assetmap (standard, pkl_uuid, boost::filesystem::file_size (pkl_path), metadata);
}
-void
-DCP::add_assets_from (DCP const & ov)
+list<shared_ptr<CPL> >
+DCP::cpls () const
{
- copy (ov._asset_maps.begin(), ov._asset_maps.end(), back_inserter (_asset_maps));
+ return list_of_type<Asset, CPL> (_assets);
}
diff --git a/src/dcp.h b/src/dcp.h
index 45ccce88..d6275037 100644
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,18 +18,19 @@
*/
/** @file src/dcp.h
- * @brief A class to create or read a DCP.
+ * @brief DCP class.
*/
#ifndef LIBDCP_DCP_H
#define LIBDCP_DCP_H
-#include <string>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/signals2.hpp>
#include "types.h"
#include "certificates.h"
+#include "metadata.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/signals2.hpp>
+#include <string>
+#include <vector>
namespace xmlpp {
class Document;
@@ -37,18 +38,16 @@ namespace xmlpp {
}
/** @brief Namespace for everything in libdcp */
-namespace libdcp
+namespace dcp
{
-class Asset;
-class PictureAsset;
-class SoundAsset;
-class SubtitleAsset;
+class Content;
class Reel;
class CPL;
class XMLMetadata;
class Signer;
class KDM;
+class Asset;
namespace parse {
class AssetMap;
@@ -69,91 +68,59 @@ public:
*/
DCP (boost::filesystem::path directory);
- void read (bool require_mxfs = true);
-
- /** Read an existing DCP's assets.
- *
- * The DCP's XML metadata will be examined, and you can then look at the contents
- * of the DCP.
- */
- void read_assets ();
-
- void read_cpls (bool require_mxfs = true);
-
- /** Write the required XML files to the directory that was
- * passed into the constructor.
- */
- void write_xml (bool interop, XMLMetadata const &, boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()) const;
+ void read ();
/** Compare this DCP with another, according to various options.
* @param other DCP to compare this one to.
* @param options Options to define what "equality" means.
+ * @param note Functor to handle notes made by the equality operation.
* @return true if the DCPs are equal according to EqualityOptions, otherwise false.
*/
bool equals (DCP const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
- /** Add a CPL to this DCP.
- * @param cpl CPL to add.
- */
- void add_cpl (boost::shared_ptr<CPL> cpl);
+ void add (boost::shared_ptr<Asset> asset);
- /** @return The list of CPLs in this DCP */
- std::list<boost::shared_ptr<CPL> > cpls () const {
- return _cpls;
- }
+ std::list<boost::shared_ptr<CPL> > cpls () const;
- /** Add another DCP as a source of assets for this DCP. This should be called before
- * ::read() on the DCP that needs the extra assets. For example
- *
- * DCP original_version ("my_dcp_OV");
- * DCP supplemental ("my_dcp_VF");
- * supplemental.add_assets_from (original_version);
- * supplemental.read ();
- */
- void add_assets_from (libdcp::DCP const &);
+ /** @return All this DCP's assets (note that CPLs are assets) */
+ std::list<boost::shared_ptr<Asset> > assets () const {
+ return _assets;
+ }
bool encrypted () const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
- /** Emitted with a parameter between 0 and 1 to indicate progress
- * for long jobs.
- */
- boost::signals2::signal<void (float)> Progress;
+ void write_xml (
+ Standard standard,
+ XMLMetadata metadata = XMLMetadata (),
+ boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()
+ );
private:
/** Write the PKL file.
* @param pkl_uuid UUID to use.
*/
- std::string write_pkl (std::string pkl_uuid, bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
+ boost::filesystem::path write_pkl (
+ Standard standard,
+ std::string pkl_uuid,
+ XMLMetadata metadata,
+ boost::shared_ptr<const Signer> signer
+ ) const;
- /** Write the VOLINDEX file */
- void write_volindex (bool) const;
+ void write_volindex (Standard standard) const;
/** Write the ASSETMAP file.
* @param pkl_uuid UUID of our PKL.
* @param pkl_length Length of our PKL in bytes.
*/
- void write_assetmap (std::string pkl_uuid, int pkl_length, bool, XMLMetadata const &) const;
-
- /** @return Assets in all the CPLs in this DCP */
- std::list<boost::shared_ptr<const Asset> > assets () const;
-
- struct Files {
- std::list<std::string> cpls;
- std::string pkl;
- std::string asset_map;
- };
-
- Files _files;
+ void write_assetmap (Standard standard, std::string pkl_uuid, int pkl_length, XMLMetadata metadata) const;
/** the directory that we are writing to */
boost::filesystem::path _directory;
- /** our CPLs */
- std::list<boost::shared_ptr<CPL> > _cpls;
-
- std::list<PathAssetMap> _asset_maps;
+ /** the assets that make up this DCP */
+ std::list<boost::shared_ptr<Asset> > _assets;
};
}
diff --git a/src/dcp_time.cc b/src/dcp_time.cc
index 14155fdb..5376b972 100644
--- a/src/dcp_time.cc
+++ b/src/dcp_time.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,20 +18,20 @@
*/
/** @file src/dcp_time.cc
- * @brief A representation of time within a DCP.
+ * @brief Time class.
*/
-#include <iostream>
-#include <vector>
+#include "dcp_time.h"
+#include "exceptions.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <vector>
#include <cmath>
-#include "dcp_time.h"
-#include "exceptions.h"
using namespace std;
using namespace boost;
-using namespace libdcp;
+using namespace dcp;
Time::Time (int frame, int frames_per_second)
: h (0)
@@ -85,19 +85,19 @@ Time::Time (string time)
}
bool
-libdcp::operator== (Time const & a, Time const & b)
+dcp::operator== (Time const & a, Time const & b)
{
return (a.h == b.h && a.m == b.m && a.s == b.s && a.t == b.t);
}
bool
-libdcp::operator!= (Time const & a, Time const & b)
+dcp::operator!= (Time const & a, Time const & b)
{
return !(a == b);
}
bool
-libdcp::operator<= (Time const & a, Time const & b)
+dcp::operator<= (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h <= b.h;
@@ -119,7 +119,7 @@ libdcp::operator<= (Time const & a, Time const & b)
}
bool
-libdcp::operator< (Time const & a, Time const & b)
+dcp::operator< (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h < b.h;
@@ -141,7 +141,7 @@ libdcp::operator< (Time const & a, Time const & b)
}
bool
-libdcp::operator> (Time const & a, Time const & b)
+dcp::operator> (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h > b.h;
@@ -163,14 +163,14 @@ libdcp::operator> (Time const & a, Time const & b)
}
ostream &
-libdcp::operator<< (ostream& s, Time const & t)
+dcp::operator<< (ostream& s, Time const & t)
{
s << t.h << ":" << t.m << ":" << t.s << "." << t.t;
return s;
}
-libdcp::Time
-libdcp::operator+ (Time a, Time const & b)
+dcp::Time
+dcp::operator+ (Time a, Time const & b)
{
Time r;
@@ -197,8 +197,8 @@ libdcp::operator+ (Time a, Time const & b)
return r;
}
-libdcp::Time
-libdcp::operator- (Time a, Time const & b)
+dcp::Time
+dcp::operator- (Time a, Time const & b)
{
Time r;
@@ -226,7 +226,7 @@ libdcp::operator- (Time a, Time const & b)
}
float
-libdcp::operator/ (Time a, Time const & b)
+dcp::operator/ (Time a, Time const & b)
{
int64_t const at = a.h * 3600 * 250 + a.m * 60 * 250 + a.s * 250 + a.t;
int64_t const bt = b.h * 3600 * 250 + b.m * 60 * 250 + b.s * 250 + b.t;
diff --git a/src/dcp_time.h b/src/dcp_time.h
index 92cee9a0..697ca230 100644
--- a/src/dcp_time.h
+++ b/src/dcp_time.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,17 +18,17 @@
*/
/** @file src/dcp_time.h
- * @brief A representation of time within a DCP.
+ * @brief Time class.
*/
#ifndef LIBDCP_TIME_H
#define LIBDCP_TIME_H
+#include <stdint.h>
#include <string>
#include <iostream>
-#include <stdint.h>
-namespace libdcp {
+namespace dcp {
/** @class Time
* @brief A representation of time within a DCP.
diff --git a/src/exceptions.cc b/src/exceptions.cc
index 6a32a33f..e5a46948 100644
--- a/src/exceptions.cc
+++ b/src/exceptions.cc
@@ -17,13 +17,17 @@
*/
+/** @file src/exceptions.cc
+ * @brief Exceptions thrown by libdcp.
+ */
+
#include "exceptions.h"
#include "compose.hpp"
using std::string;
-using namespace libdcp;
+using namespace dcp;
-FileError::FileError (std::string const & message, boost::filesystem::path filename, int number)
+FileError::FileError (string message, boost::filesystem::path filename, int number)
: _message (String::compose ("%1 (error %2) (%3)", message, filename.string(), number))
, _filename (filename)
, _number (number)
@@ -31,3 +35,9 @@ FileError::FileError (std::string const & message, boost::filesystem::path filen
}
+UnresolvedRefError::UnresolvedRefError (string id)
+ : _message (String::compose ("Unresolved reference to asset id %1", id))
+{
+
+}
+
diff --git a/src/exceptions.h b/src/exceptions.h
index 2070dd0f..bc5e83d1 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,14 +26,16 @@
* @brief Exceptions thrown by libdcp.
*/
-namespace libdcp
+namespace dcp
{
-/** @brief An exception related to a file */
+/** @class FileError
+ * @brief An exception related to a file
+ */
class FileError : public std::exception
{
public:
- FileError (std::string const & message, boost::filesystem::path filename, int number);
+ FileError (std::string message, boost::filesystem::path filename, int number);
~FileError () throw () {}
/** @return error message */
@@ -59,20 +61,24 @@ private:
int _number;
};
-/** @brief An exception related to an MXF file */
+/** @class MXFFileError
+ * @brief An exception related to an MXF file
+ */
class MXFFileError : public FileError
{
public:
- MXFFileError (std::string const & message, boost::filesystem::path filename, int number)
+ MXFFileError (std::string message, boost::filesystem::path filename, int number)
: FileError (message, filename, number)
{}
};
-/** @brief A miscellaneous exception */
+/** @class MiscError
+ * @brief A miscellaneous exception
+ */
class MiscError : public std::exception
{
public:
- MiscError (std::string const & message) : _message (message) {}
+ MiscError (std::string message) : _message (message) {}
~MiscError () throw () {}
/** @return error message */
@@ -85,11 +91,13 @@ private:
std::string _message;
};
-/** @brief A DCP read exception */
+/** @class DCPReadError
+ * @brief A DCP read exception
+ */
class DCPReadError : public std::exception
{
public:
- DCPReadError (std::string const & message) : _message (message) {}
+ DCPReadError (std::string message) : _message (message) {}
~DCPReadError () throw () {}
/** @return error message */
@@ -102,11 +110,13 @@ private:
std::string _message;
};
-/** @brief An XML error */
+/** @class XMLError
+ * @brief An XML error
+ */
class XMLError : public std::exception
{
public:
- XMLError (std::string const & message) : _message (message) {}
+ XMLError (std::string message) : _message (message) {}
~XMLError () throw () {}
/** @return error message */
@@ -118,6 +128,24 @@ private:
/** error message */
std::string _message;
};
+
+/** @class UnresolvedRefError
+ * @brief An exception caused by a reference (by UUID) to something which is not known
+ */
+class UnresolvedRefError : public std::exception
+{
+public:
+ UnresolvedRefError (std::string id);
+ ~UnresolvedRefError () throw () {}
+
+ /** @return error message */
+ char const * what () const throw () {
+ return _message.c_str ();
+ }
+
+private:
+ std::string _message;
+};
}
diff --git a/src/file.cc b/src/file.cc
new file mode 100644
index 00000000..aabda166
--- /dev/null
+++ b/src/file.cc
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/file.cc
+ * @brief File class.
+ */
+
+#include "file.h"
+#include "util.h"
+
+using namespace dcp;
+
+/** Read a file into memory.
+ * @param file to read.
+ */
+File::File (boost::filesystem::path file)
+{
+ _size = boost::filesystem::file_size (file);
+ _data = new uint8_t[_size];
+ FILE* f = dcp::fopen_boost (file, "r");
+ assert (f);
+ fread (_data, 1, _size, f);
+ fclose (f);
+}
+
+/** File destructor */
+File::~File ()
+{
+ delete[] _data;
+}
diff --git a/src/rec709_linearised_gamma_lut.cc b/src/file.h
index f14e4472..b06cece0 100644
--- a/src/rec709_linearised_gamma_lut.cc
+++ b/src/file.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,39 @@
*/
-#include "rec709_linearised_gamma_lut.h"
+/** @file src/file.h
+ * @brief File class.
+ */
-using namespace libdcp;
+#ifndef LIBDCP_FILE_H
+#define LIBDCP_FILE_H
-LUTCache<Rec709LinearisedGammaLUT> Rec709LinearisedGammaLUT::cache;
+#include <boost/filesystem.hpp>
-Rec709LinearisedGammaLUT::Rec709LinearisedGammaLUT (int bits, float gamma)
- : LUT (bits, gamma)
+namespace dcp {
+
+/** @class File
+ * @brief Helper class which loads a file into memory.
+ */
+class File
{
- int const bit_length = pow (2, bits);
- for (int i = 0; i < bit_length; ++i) {
- float const p = static_cast<float> (i) / (bit_length - 1);
- if (p > 0.08125) {
- _lut[i] = pow ((p + 0.099) / 1.099, gamma);
- } else {
- _lut[i] = p / 4.5;
- }
+public:
+ File (boost::filesystem::path file);
+ ~File ();
+
+ uint8_t* data () const {
+ return _data;
+ }
+
+ int64_t size () const {
+ return _size;
}
+
+private:
+ uint8_t* _data; ///< file's data
+ int64_t _size; ///< data size in bytes
+};
+
}
+
+#endif
diff --git a/src/parse/subtitle.cc b/src/font.cc
index 914be677..52996a73 100644
--- a/src/parse/subtitle.cc
+++ b/src/font.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,20 +17,18 @@
*/
-#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-#include "subtitle.h"
-#include "../types.h"
+#include "font.h"
+#include "xml.h"
+#include "text.h"
+#include <libcxml/cxml.h>
using std::string;
using std::list;
using boost::shared_ptr;
using boost::optional;
-using boost::lexical_cast;
-using namespace libdcp;
-using namespace libdcp::parse;
+using namespace dcp;
-Font::Font (shared_ptr<const cxml::Node> node)
+Font::Font (boost::shared_ptr<const cxml::Node> node)
{
text = node->content ();
@@ -54,7 +52,7 @@ Font::Font (shared_ptr<const cxml::Node> node)
text_nodes = type_children<Text> (node, "Text");
}
-Font::Font (list<shared_ptr<Font> > const & font_nodes)
+Font::Font (std::list<boost::shared_ptr<Font> > const & font_nodes)
: size (0)
, italic (false)
, color ("FFFFFFFF")
@@ -81,69 +79,3 @@ Font::Font (list<shared_ptr<Font> > const & font_nodes)
}
}
}
-
-LoadFont::LoadFont (shared_ptr<const cxml::Node> node)
-{
- optional<string> x = node->optional_string_attribute ("Id");
- if (!x) {
- x = node->optional_string_attribute ("ID");
- }
- id = x.get_value_or ("");
-
- uri = node->optional_string_attribute ("URI");
-}
-
-Subtitle::Subtitle (shared_ptr<const cxml::Node> node)
-{
- in = Time (node->string_attribute ("TimeIn"));
- out = Time (node->string_attribute ("TimeOut"));
- font_nodes = type_children<Font> (node, "Font");
- text_nodes = type_children<Text> (node, "Text");
- fade_up_time = fade_time (node, "FadeUpTime");
- fade_down_time = fade_time (node, "FadeDownTime");
-}
-
-Time
-Subtitle::fade_time (shared_ptr<const cxml::Node> node, string name)
-{
- string const u = node->optional_string_attribute (name).get_value_or ("");
- Time t;
-
- if (u.empty ()) {
- t = Time (0, 0, 0, 20);
- } else if (u.find (":") != string::npos) {
- t = Time (u);
- } else {
- t = Time (0, 0, 0, lexical_cast<int> (u));
- }
-
- if (t > Time (0, 0, 8, 0)) {
- t = Time (0, 0, 8, 0);
- }
-
- return t;
-}
-
-Text::Text (shared_ptr<const cxml::Node> node)
- : v_align (CENTER)
-{
- /* Vertical position */
- text = node->content ();
- optional<float> x = node->optional_number_attribute<float> ("VPosition");
- if (!x) {
- x = node->number_attribute<float> ("Vposition");
- }
- v_position = x.get ();
-
- /* Vertical alignment */
- optional<string> v = node->optional_string_attribute ("VAlign");
- if (!v) {
- v = node->optional_string_attribute ("Valign");
- }
- if (v) {
- v_align = string_to_valign (v.get ());
- }
-
- font_nodes = type_children<Font> (node, "Font");
-}
-
diff --git a/src/parse/subtitle.h b/src/font.h
index 3d99d9bc..1b29e570 100644
--- a/src/parse/subtitle.h
+++ b/src/font.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,51 +17,18 @@
*/
-#include "../xml.h"
-#include "../dcp_time.h"
-#include "../types.h"
+#include "types.h"
+#include "subtitle.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <list>
-namespace libdcp
-{
-
-namespace parse
-{
-
-class Font;
+namespace cxml {
+ class Node;
+}
-class Text
-{
-public:
- Text ()
- : v_position (0)
- , v_align (TOP)
- {}
+namespace dcp {
- Text (boost::shared_ptr<const cxml::Node> node);
-
- float v_position;
- VAlign v_align;
- std::string text;
- std::list<boost::shared_ptr<Font> > font_nodes;
-};
-
-class Subtitle
-{
-public:
- Subtitle () {}
- Subtitle (boost::shared_ptr<const cxml::Node> node);
-
- Time in;
- Time out;
- Time fade_up_time;
- Time fade_down_time;
- std::list<boost::shared_ptr<Font> > font_nodes;
- std::list<boost::shared_ptr<Text> > text_nodes;
-
-private:
- Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name);
-};
-
class Font
{
public:
@@ -85,16 +52,4 @@ public:
std::list<boost::shared_ptr<Text> > text_nodes;
};
-class LoadFont
-{
-public:
- LoadFont () {}
- LoadFont (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- boost::optional<std::string> uri;
-};
-
-}
-
}
diff --git a/src/gamma_lut.cc b/src/gamma_lut.cc
index 80d9b902..abe35b7c 100644
--- a/src/gamma_lut.cc
+++ b/src/gamma_lut.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,19 +17,34 @@
*/
-#include <cmath>
#include "gamma_lut.h"
#include "lut_cache.h"
+#include <cmath>
-using namespace libdcp;
+using namespace dcp;
LUTCache<GammaLUT> GammaLUT::cache;
-GammaLUT::GammaLUT(int bits, float gamma)
- : LUT (bits, gamma)
+GammaLUT::GammaLUT (int bit_depth, float gamma, bool linearised)
+ : _bit_depth (bit_depth)
+ , _gamma (gamma)
+ , _linearised (linearised)
{
- int const bit_length = pow(2, bits);
- for (int i = 0; i < bit_length; ++i) {
- _lut[i] = pow(float(i) / (bit_length - 1), gamma);
+ _lut = new float[int(std::pow(2.0f, _bit_depth))];
+ int const bit_length = pow (2, _bit_depth);
+
+ if (_linearised) {
+ for (int i = 0; i < bit_length; ++i) {
+ float const p = static_cast<float> (i) / (bit_length - 1);
+ if (p > 0.04045) {
+ _lut[i] = pow ((p + 0.055) / 1.055, gamma);
+ } else {
+ _lut[i] = p / 12.92;
+ }
+ }
+ } else {
+ for (int i = 0; i < bit_length; ++i) {
+ _lut[i] = pow(float(i) / (bit_length - 1), gamma);
+ }
}
}
diff --git a/src/gamma_lut.h b/src/gamma_lut.h
index 32e4af02..76a63ccf 100644
--- a/src/gamma_lut.h
+++ b/src/gamma_lut.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,16 +20,42 @@
#ifndef LIBDCP_GAMMA_LUT_H
#define LIBDCP_GAMMA_LUT_H
-#include "lut.h"
#include "lut_cache.h"
-namespace libdcp {
+namespace dcp {
-class GammaLUT : public LUT
+class GammaLUT
{
public:
- GammaLUT (int bit_length, float gamma);
+ GammaLUT (int bit_depth, float gamma, bool linearised);
+
+ ~GammaLUT () {
+ delete[] _lut;
+ }
+
+ float const * lut () const {
+ return _lut;
+ }
+
+ int bit_depth () const {
+ return _bit_depth;
+ }
+
+ float gamma () const {
+ return _gamma;
+ }
+
+ bool linearised () const {
+ return _linearised;
+ }
+
static LUTCache<GammaLUT> cache;
+
+private:
+ float* _lut;
+ int _bit_depth;
+ float _gamma;
+ bool _linearised;
};
}
diff --git a/src/image.cc b/src/image.cc
index 24174fca..15ff24dc 100644
--- a/src/image.cc
+++ b/src/image.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
#include "image.h"
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
Image::Image (Size s)
: _size (s)
@@ -34,7 +34,7 @@ Image::Image (Image const & other)
}
-Image::Image (shared_ptr<const Image> other)
+Image::Image (boost::shared_ptr<const Image> other)
: _size (other->_size)
{
diff --git a/src/image.h b/src/image.h
index 8b7fee09..069534ea 100644
--- a/src/image.h
+++ b/src/image.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#include "util.h"
-namespace libdcp {
+namespace dcp {
class Image
{
diff --git a/src/kdm.cc b/src/kdm.cc
index 4132b242..fe7fe393 100644
--- a/src/kdm.cc
+++ b/src/kdm.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,23 +17,27 @@
*/
-#include <iomanip>
-#include <algorithm>
-#include <boost/algorithm/string.hpp>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include <openssl/err.h>
-#include <libcxml/cxml.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
+/** @file src/kdm.cc
+ * @brief KDM and KDMKey classes.
+ */
+
#include "util.h"
#include "kdm.h"
#include "compose.hpp"
#include "exceptions.h"
#include "signer.h"
#include "cpl.h"
-#include "mxf_asset.h"
-#include "xml/kdm_smpte.h"
+#include "mxf.h"
+#include "kdm_smpte_xml.h"
+#include "AS_DCP.h"
+#include "KM_util.h"
+#include <libcxml/cxml.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <boost/algorithm/string.hpp>
+#include <iomanip>
+#include <algorithm>
using std::list;
using std::string;
@@ -43,7 +47,7 @@ using std::setw;
using std::setfill;
using std::cout;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
: _xml_kdm (new xml::DCinemaSecurityMessage (kdm))
@@ -87,7 +91,9 @@ KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
}
KDM::KDM (
- shared_ptr<const CPL> cpl, shared_ptr<const Signer> signer, shared_ptr<const Certificate> recipient_cert,
+ boost::shared_ptr<const CPL> cpl,
+ boost::shared_ptr<const Signer> signer,
+ boost::shared_ptr<const Certificate> recipient_cert,
boost::posix_time::ptime not_valid_before, boost::posix_time::ptime not_valid_after,
string annotation_text, string issue_date
)
@@ -108,7 +114,7 @@ KDM::KDM (
apu.recipient.x509_subject_name = recipient_cert->subject ();
apu.composition_playlist_id = "urn:uuid:" + cpl->id ();
// apu.content_authenticator = signer->certificates().leaf()->thumbprint ();
- apu.content_title_text = cpl->name ();
+ apu.content_title_text = cpl->content_title_text ();
apu.content_keys_not_valid_before = ptime_to_string (not_valid_before);
apu.content_keys_not_valid_after = ptime_to_string (not_valid_after);
apu.authorized_device_info.device_list_identifier = "urn:uuid:" + make_uuid ();
@@ -124,10 +130,10 @@ KDM::KDM (
*/
apu.authorized_device_info.device_list.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
- list<shared_ptr<const Asset> > assets = cpl->assets ();
- for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ list<shared_ptr<const Content> > content = cpl->content ();
+ for (list<shared_ptr<const Content> >::iterator i = content.begin(); i != content.end(); ++i) {
/* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ shared_ptr<const MXF> mxf = boost::dynamic_pointer_cast<const MXF> (*i);
if (mxf) {
apu.key_id_list.push_back (xml::TypedKeyId (mxf->key_type(), "urn:uuid:" + mxf->key_id()));
}
@@ -138,9 +144,9 @@ KDM::KDM (
/* AuthenticatedPrivate */
- for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ for (list<shared_ptr<const Content> >::iterator i = content.begin(); i != content.end(); ++i) {
/* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ shared_ptr<const MXF> mxf = boost::dynamic_pointer_cast<const MXF> (*i);
if (mxf) {
KDMKey kkey (
signer, cpl->id (), mxf->key_type (), mxf->key_id (),
@@ -202,7 +208,13 @@ KDM::as_xml () const
}
KDMKey::KDMKey (
- shared_ptr<const Signer> signer, string cpl_id, string key_type, string key_id, boost::posix_time::ptime from, boost::posix_time::ptime until, Key key
+ boost::shared_ptr<const Signer> signer,
+ string cpl_id,
+ string key_type,
+ string key_id,
+ boost::posix_time::ptime from,
+ boost::posix_time::ptime until,
+ Key key
)
: _cpl_id (cpl_id)
, _key_type (key_type)
@@ -275,7 +287,7 @@ KDMKey::operator= (KDMKey const & other)
}
string
-KDMKey::encrypted_base64 (shared_ptr<const Certificate> recipient_cert) const
+KDMKey::encrypted_base64 (boost::shared_ptr<const Certificate> recipient_cert) const
{
assert (_key_type.length() == 4);
assert (_not_valid_before.length() == 25);
@@ -383,7 +395,7 @@ KDMKey::put_uuid (uint8_t ** d, string id) const
}
bool
-libdcp::operator== (libdcp::KDMKey const & a, libdcp::KDMKey const & b)
+dcp::operator== (dcp::KDMKey const & a, dcp::KDMKey const & b)
{
if (memcmp (a._signer_thumbprint, b._signer_thumbprint, 20) != 0) {
return false;
diff --git a/src/kdm.h b/src/kdm.h
index 4e897ca8..02395a72 100644
--- a/src/kdm.h
+++ b/src/kdm.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,21 +18,21 @@
*/
/** @file src/kdm.h
- * @brief Handling of Key Delivery Messages (KDMs).
+ * @brief KDM and KDMKey classes.
*/
#ifndef LIBDCP_KDM_H
#define LIBDCP_KDM_H
+#include "key.h"
+#include "metadata.h"
#include <boost/filesystem.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "key.h"
-#include "metadata.h"
class kdm_key_test;
-namespace libdcp {
+namespace dcp {
namespace xml {
class DCinemaSecurityMessage;
@@ -161,8 +161,8 @@ public:
* @param recipient_cert Certificate of the projector that this KDM is targeted at.
* @param not_valid_before Start of validity period.
* @param not_valid_after End of validity period.
- * @param annotation_text Text for the <AnnotationText> node.
- * @param issue_date Text for the <IssueDate> node.
+ * @param annotation_text Text for the &lt;AnnotationText&gt; node.
+ * @param issue_date Text for the &lt;IssueDate&gt; node.
*/
KDM (
boost::shared_ptr<const CPL> cpl, boost::shared_ptr<const Signer> signer, boost::shared_ptr<const Certificate> recipient_cert,
diff --git a/src/xml/kdm_smpte.h b/src/kdm_smpte_xml.h
index 32a297f8..70b7847e 100644
--- a/src/xml/kdm_smpte.h
+++ b/src/kdm_smpte_xml.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
*/
-/** @file src/xml/kdm_smpte.h
+/** @file src/kdm_smpte_xml.h
* @brief 1:1ish C++ representations of the XML schema for a SMPTE KDM.
*
* This file contains classes which map pretty-much 1:1 to the elements in a SMPTE KDM
@@ -29,19 +29,19 @@
* change very often.
*/
-#ifndef LIBDCP_XML_KDM_SMPTE_H
-#define LIBDCP_XML_KDM_SMPTE_H
+#ifndef LIBDCP_KDM_SMPTE_XML_H
+#define LIBDCP_KDM_SMPTE_XML_H
-#include <string>
-#include <list>
-#include <boost/optional.hpp>
-#include <boost/filesystem.hpp>
+#include "exceptions.h"
+#include <libcxml/cxml.h>
#include <libxml/parser.h>
#include <libxml++/libxml++.h>
-#include <libcxml/cxml.h>
-#include "../exceptions.h"
+#include <boost/optional.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <list>
-namespace libdcp {
+namespace dcp {
namespace xml {
class Writer
diff --git a/src/key.cc b/src/key.cc
index 8cac04a3..43e59dfc 100644
--- a/src/key.cc
+++ b/src/key.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,19 +17,23 @@
*/
-#include <sstream>
-#include <string>
-#include <iomanip>
+/** @file src/key.cc
+ * @brief Key class.
+ */
+
+#include "key.h"
#include "AS_DCP.h"
#include "KM_prng.h"
#include "KM_util.h"
-#include "key.h"
+#include <sstream>
+#include <string>
+#include <iomanip>
using std::string;
using std::stringstream;
using std::setw;
using std::setfill;
-using namespace libdcp;
+using namespace dcp;
Key::Key ()
: _value (new uint8_t[ASDCP::KeyLen])
@@ -86,13 +90,13 @@ Key::hex () const
}
bool
-libdcp::operator== (Key const & a, Key const & b)
+dcp::operator== (Key const & a, Key const & b)
{
return memcmp (a.value(), b.value(), ASDCP::KeyLen) == 0;
}
bool
-libdcp::operator!= (Key const & a, Key const & b)
+dcp::operator!= (Key const & a, Key const & b)
{
return !(a == b);
}
diff --git a/src/key.h b/src/key.h
index d0286627..248a2a95 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,18 +18,19 @@
*/
/** @file src/key.h
- * @brief Class to hold a key for encrypting MXFs.
+ * @brief Key class.
*/
#ifndef LIBDCP_KEY_H
#define LIBDCP_KEY_H
#include <stdint.h>
+#include <string>
-namespace libdcp {
+namespace dcp {
/** @class Key
- * @brief A key for encrypting MXFs.
+ * @brief A key for decrypting/encrypting MXFs.
*/
class Key
{
diff --git a/src/rec709_linearised_gamma_lut.h b/src/load_font.cc
index af0158a5..707f4a0b 100644
--- a/src/rec709_linearised_gamma_lut.h
+++ b/src/load_font.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,16 +17,14 @@
*/
-#include "lut.h"
-#include "lut_cache.h"
+#include "load_font.h"
+#include <libcxml/cxml.h>
-namespace libdcp {
+using boost::shared_ptr;
+using namespace dcp;
-class Rec709LinearisedGammaLUT : public LUT
+LoadFont::LoadFont (boost::shared_ptr<const cxml::Node> node)
{
-public:
- Rec709LinearisedGammaLUT (int bit_length, float gamma);
- static LUTCache<Rec709LinearisedGammaLUT> cache;
-};
-
+ id = node->string_attribute ("Id");
+ uri = node->string_attribute ("URI");
}
diff --git a/src/srgb_linearised_gamma_lut.h b/src/load_font.h
index 34800c66..6319b1de 100644
--- a/src/srgb_linearised_gamma_lut.h
+++ b/src/load_font.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,16 +17,22 @@
*/
-#include "lut.h"
-#include "lut_cache.h"
+#include <boost/shared_ptr.hpp>
-namespace libdcp {
+namespace cxml {
+ class Node;
+}
-class SRGBLinearisedGammaLUT : public LUT
+namespace dcp {
+
+class LoadFont
{
public:
- SRGBLinearisedGammaLUT (int bit_length, float gamma);
- static LUTCache<SRGBLinearisedGammaLUT> cache;
+ LoadFont () {}
+ LoadFont (boost::shared_ptr<const cxml::Node> node);
+
+ std::string id;
+ std::string uri;
};
}
diff --git a/src/lut_cache.h b/src/lut_cache.h
index b60ee109..5c75fe6a 100644
--- a/src/lut_cache.h
+++ b/src/lut_cache.h
@@ -1,14 +1,34 @@
+/*
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
#ifndef LIBDCP_LUT_CACHE_H
#define LIBDCP_LUT_CACHE_H
#include <list>
#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
template<class T>
-class LUTCache
+class LUTCache : public boost::noncopyable
{
public:
- boost::shared_ptr<T> get (int bit_depth, float gamma)
+ boost::shared_ptr<T> get (int bit_depth, float gamma, bool linearised)
{
for (typename std::list<boost::shared_ptr<T> >::iterator i = _cache.begin(); i != _cache.end(); ++i) {
if ((*i)->bit_depth() == bit_depth && (*i)->gamma() == gamma) {
@@ -16,7 +36,7 @@ public:
}
}
- boost::shared_ptr<T> lut (new T (bit_depth, gamma));
+ boost::shared_ptr<T> lut (new T (bit_depth, gamma, linearised));
_cache.push_back (lut);
return lut;
}
diff --git a/src/metadata.cc b/src/metadata.cc
index acbc3b2e..e3382613 100644
--- a/src/metadata.cc
+++ b/src/metadata.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,20 +18,20 @@
*/
/** @file src/metadata.cc
- * @brief Metadata for writing to the DCP.
+ * @brief XMLMetadata and MXFMetadata classes.
*/
-#include <sstream>
-#include <iomanip>
-#include <time.h>
+#include "metadata.h"
+#include "util.h"
#ifdef LIBDCP_WINDOWS
#include <windows.h>
#endif
-#include "metadata.h"
-#include "util.h"
+#include <sstream>
+#include <iomanip>
+#include <time.h>
using namespace std;
-using namespace libdcp;
+using namespace dcp;
MXFMetadata::MXFMetadata ()
: company_name ("libdcp")
diff --git a/src/metadata.h b/src/metadata.h
index b4c0896d..b1fcdd8e 100644
--- a/src/metadata.h
+++ b/src/metadata.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,16 +21,19 @@
#define LIBDCP_METADATA_H
/** @file src/metadata.h
- * @brief Metadata for writing to the DCP.
+ * @brief XMLMetadata and MXFMetadata classes.
*/
#include <string>
class utc_offset_to_string_test;
-namespace libdcp
+namespace dcp
{
+/** @class MXFMetadata
+ * @brief Metadata that is written to a MXF file's header
+ */
class MXFMetadata
{
public:
@@ -41,6 +44,9 @@ public:
std::string product_version;
};
+/** @class XMLMetadata
+ * @brief Common metadata that is written to a few different XML files
+ */
class XMLMetadata
{
public:
diff --git a/src/mono_picture_asset.cc b/src/mono_picture_asset.cc
deleted file mode 100644
index 0ac48d37..00000000
--- a/src/mono_picture_asset.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "mono_picture_asset.h"
-#include "mono_picture_asset_writer.h"
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "exceptions.h"
-#include "mono_picture_frame.h"
-
-using std::string;
-using std::vector;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::lexical_cast;
-using namespace libdcp;
-
-MonoPictureAsset::MonoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-MonoPictureAsset::create (vector<boost::filesystem::path> const & files)
-{
- create (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
-}
-
-void
-MonoPictureAsset::create (boost::function<boost::filesystem::path (int)> get_path)
-{
- ASDCP::JP2K::CodestreamParser j2k_parser;
- ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
- Kumu::Result_t r = j2k_parser.OpenReadFrame (get_path(0).string().c_str(), frame_buffer);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path(0), r));
- }
-
- ASDCP::JP2K::PictureDescriptor picture_desc;
- j2k_parser.FillPictureDescriptor (picture_desc);
- picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
-
- ASDCP::WriterInfo writer_info;
- fill_writer_info (&writer_info);
-
- ASDCP::JP2K::MXFWriter mxf_writer;
- r = mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for writing", path().string(), r));
- }
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
-
- boost::filesystem::path const path = get_path (i);
-
- Kumu::Result_t r = j2k_parser.OpenReadFrame (path.string().c_str(), frame_buffer);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", path, r));
- }
-
- r = mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", this->path().string(), r));
- }
-
- if (_progress) {
- (*_progress) (0.5 * float (i) / _intrinsic_duration);
- }
- }
-
- r = mxf_writer.Finalize();
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string(), r));
- }
-}
-
-void
-MonoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
- _intrinsic_duration = desc.ContainerDuration;
-}
-
-boost::filesystem::path
-MonoPictureAsset::path_from_list (int f, vector<boost::filesystem::path> const & files) const
-{
- return files[f];
-}
-
-shared_ptr<const MonoPictureFrame>
-MonoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (path(), n, _decryption_context));
-}
-
-bool
-MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!MXFAsset::equals (other, opt, note)) {
- return false;
- }
-
- ASDCP::JP2K::MXFReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::MXFReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc_A;
- if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
- ASDCP::JP2K::PictureDescriptor desc_B;
- if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- if (!descriptor_equals (desc_A, desc_B, note)) {
- return false;
- }
-
- shared_ptr<const MonoPictureAsset> other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
- assert (other_picture);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- if (i >= other_picture->intrinsic_duration()) {
- return false;
- }
-
- note (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_intrinsic_duration));
- shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
- shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->j2k_data(), frame_A->j2k_size(),
- frame_B->j2k_data(), frame_B->j2k_size()
- )) {
- return false;
- }
- }
-
- return true;
-}
-
-shared_ptr<PictureAssetWriter>
-MonoPictureAsset::start_write (bool overwrite)
-{
- /* XXX: can't we use shared_ptr here? */
- return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite));
-}
-
-string
-MonoPictureAsset::cpl_node_name () const
-{
- return "MainPicture";
-}
-
-int
-MonoPictureAsset::edit_rate_factor () const
-{
- return 1;
-}
diff --git a/src/mono_picture_asset.h b/src/mono_picture_asset.h
deleted file mode 100644
index ae2df4d2..00000000
--- a/src/mono_picture_asset.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LIBDCP_MONO_PICTURE_ASSET_H
-#define LIBDCP_MONO_PICTURE_ASSET_H
-
-#include "picture_asset.h"
-
-namespace libdcp {
-
-/** A 2D (monoscopic) picture asset */
-class MonoPictureAsset : public PictureAsset
-{
-public:
- MonoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- void read ();
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- */
- void create (std::vector<boost::filesystem::path> const & files);
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- */
- void create (boost::function<boost::filesystem::path (int)> get_path);
-
- /** Start a progressive write to a MonoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
-
- boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
-private:
- boost::filesystem::path path_from_list (int f, std::vector<boost::filesystem::path> const & files) const;
- void construct (boost::function<boost::filesystem::path (int)>, bool, MXFMetadata const &);
- std::string cpl_node_name () const;
- int edit_rate_factor () const;
-};
-
-}
-
-#endif
diff --git a/src/mono_picture_frame.cc b/src/mono_picture_frame.cc
index 890967d1..c2f8abb7 100644
--- a/src/mono_picture_frame.cc
+++ b/src/mono_picture_frame.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,26 +17,30 @@
*/
-#include <openjpeg.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
+/** @file src/mono_picture_frame.cc
+ * @brief MonoPictureFrame class.
+ */
+
#include "mono_picture_frame.h"
#include "exceptions.h"
#include "argb_frame.h"
-#include "lut.h"
-#include "util.h"
#include "gamma_lut.h"
+#include "util.h"
#include "rgb_xyz.h"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <openjpeg.h>
#define DCI_GAMMA 2.6
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** Make a picture frame from a 2D (monoscopic) asset.
* @param mxf_path Path to the asset's MXF file.
* @param n Frame within the asset, not taking EntryPoint into account.
+ * @param c Context for decryption, or 0.
*/
MonoPictureFrame::MonoPictureFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext* c)
{
@@ -54,17 +58,20 @@ MonoPictureFrame::MonoPictureFrame (boost::filesystem::path mxf_path, int n, ASD
}
}
+/** MonoPictureFrame destructor */
MonoPictureFrame::~MonoPictureFrame ()
{
delete _buffer;
}
+/** @return Pointer to JPEG2000 data */
uint8_t const *
MonoPictureFrame::j2k_data () const
{
return _buffer->RoData ();
}
+/** @return Size of JPEG2000 data in bytes */
int
MonoPictureFrame::j2k_size () const
{
@@ -74,17 +81,18 @@ MonoPictureFrame::j2k_size () const
/** @param reduce a factor by which to reduce the resolution
* of the image, expressed as a power of two (pass 0 for no
* reduction).
+ * @param srgb_gamma Reciprocal of output gamma to use after
+ * the conversion from XYZ to RGB.
*
* @return An ARGB representation of this frame. This is ARGB in the
* Cairo sense, so that each pixel takes up 4 bytes; the first byte
* is blue, second green, third red and fourth alpha (always 255).
- *
*/
shared_ptr<ARGBFrame>
MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const
{
return xyz_to_rgb (
decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce),
- GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)
+ GammaLUT::cache.get (12, DCI_GAMMA, false), GammaLUT::cache.get (12, 1 / srgb_gamma, false)
);
}
diff --git a/src/mono_picture_frame.h b/src/mono_picture_frame.h
index 0eedfb95..cc6096cd 100644
--- a/src/mono_picture_frame.h
+++ b/src/mono_picture_frame.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,10 +17,16 @@
*/
+/** @file src/mono_picture_frame.h
+ * @brief MonoPictureFrame class.
+ */
+
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
#include <string>
#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include "types.h"
namespace ASDCP {
namespace JP2K {
@@ -29,12 +35,14 @@ namespace ASDCP {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
-/** A single frame of a 2D (monoscopic) picture asset */
-class MonoPictureFrame
+/** @class MonoPictureFrame
+ * @brief A single frame of a 2D (monoscopic) picture asset.
+ */
+class MonoPictureFrame : public boost::noncopyable
{
public:
MonoPictureFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext *);
diff --git a/src/mono_picture_mxf.cc b/src/mono_picture_mxf.cc
new file mode 100644
index 00000000..4af24008
--- /dev/null
+++ b/src/mono_picture_mxf.cc
@@ -0,0 +1,137 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "mono_picture_mxf.h"
+#include "mono_picture_mxf_writer.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "exceptions.h"
+#include "mono_picture_frame.h"
+#include "compose.hpp"
+
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using namespace dcp;
+
+MonoPictureMXF::MonoPictureMXF (boost::filesystem::path file)
+ : PictureMXF (file)
+{
+ ASDCP::JP2K::MXFReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
+}
+
+MonoPictureMXF::MonoPictureMXF (Fraction edit_rate)
+ : PictureMXF (edit_rate)
+{
+
+}
+
+shared_ptr<const MonoPictureFrame>
+MonoPictureMXF::get_frame (int n) const
+{
+ return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (_file, n, _decryption_context));
+}
+
+bool
+MonoPictureMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!MXF::equals (other, opt, note)) {
+ return false;
+ }
+
+ ASDCP::JP2K::MXFReader reader_A;
+ Kumu::Result_t r = reader_A.OpenRead (_file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", _file.string(), r));
+ }
+
+ ASDCP::JP2K::MXFReader reader_B;
+ r = reader_B.OpenRead (other->file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->file().string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc_A;
+ if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+ ASDCP::JP2K::PictureDescriptor desc_B;
+ if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ if (!descriptor_equals (desc_A, desc_B, note)) {
+ return false;
+ }
+
+ shared_ptr<const MonoPictureMXF> other_picture = dynamic_pointer_cast<const MonoPictureMXF> (other);
+ assert (other_picture);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ if (i >= other_picture->intrinsic_duration()) {
+ return false;
+ }
+
+ note (PROGRESS, String::compose ("Comparing video frame %1 of %2", i, _intrinsic_duration));
+ shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
+ shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->j2k_data(), frame_A->j2k_size(),
+ frame_B->j2k_data(), frame_B->j2k_size()
+ )) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+shared_ptr<PictureMXFWriter>
+MonoPictureMXF::start_write (boost::filesystem::path file, Standard standard, bool overwrite)
+{
+ /* XXX: can't we use shared_ptr here? */
+ return shared_ptr<MonoPictureMXFWriter> (new MonoPictureMXFWriter (this, file, standard, overwrite));
+}
+
+string
+MonoPictureMXF::cpl_node_name () const
+{
+ return "MainPicture";
+}
diff --git a/src/mono_picture_mxf.h b/src/mono_picture_mxf.h
new file mode 100644
index 00000000..c02a63c1
--- /dev/null
+++ b/src/mono_picture_mxf.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_MONO_PICTURE_MXF_H
+#define LIBDCP_MONO_PICTURE_MXF_H
+
+#include "picture_mxf.h"
+
+namespace dcp {
+
+class MonoPictureMXFWriter;
+
+/** @class MonoPictureMXF
+ * @brief A 2D (monoscopic) picture MXF.
+ */
+class MonoPictureMXF : public PictureMXF
+{
+public:
+ /** Create a MonoPictureMXF by reading a file.
+ * @param file MXF file to read.
+ */
+ MonoPictureMXF (boost::filesystem::path file);
+
+ /** Create a MonoPictureMXF with a given edit rate.
+ * @param edit_rate Edit rate (i.e. frame rate) in frames per second.
+ */
+ MonoPictureMXF (Fraction edit_rate);
+
+ /** Start a progressive write to a MonoPictureMXF */
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path, Standard standard, bool);
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
diff --git a/src/mono_picture_asset_writer.cc b/src/mono_picture_mxf_writer.cc
index 6f0ba973..5cc424e1 100644
--- a/src/mono_picture_asset_writer.cc
+++ b/src/mono_picture_mxf_writer.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,25 @@
*/
+/** @file src/mono_picture_mxf_writer.cc
+ * @brief MonoPictureMXFWriter class
+ */
+
#include "AS_DCP.h"
#include "KM_fileio.h"
-#include "mono_picture_asset_writer.h"
+#include "mono_picture_mxf_writer.h"
#include "exceptions.h"
-#include "picture_asset.h"
+#include "picture_mxf.h"
-#include "picture_asset_writer_common.cc"
+#include "picture_mxf_writer_common.cc"
using std::istream;
using std::ostream;
using std::string;
using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
+using namespace dcp;
-struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+struct MonoPictureMXFWriter::ASDCPState : public ASDCPStateBase
{
ASDCP::JP2K::MXFWriter mxf_writer;
};
@@ -40,21 +43,22 @@ struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
/** @param a Asset to write to. `a' must not be deleted while
* this writer class still exists, or bad things will happen.
*/
-MonoPictureAssetWriter::MonoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new MonoPictureAssetWriter::ASDCPState)
+MonoPictureMXFWriter::MonoPictureMXFWriter (PictureMXF* asset, boost::filesystem::path file, Standard standard, bool overwrite)
+ : PictureMXFWriter (asset, file, standard, overwrite)
+ , _state (new MonoPictureMXFWriter::ASDCPState)
{
_state->encryption_context = asset->encryption_context ();
}
void
-MonoPictureAssetWriter::start (uint8_t* data, int size)
+MonoPictureMXFWriter::start (uint8_t* data, int size)
{
- libdcp::start (this, _state, _asset, data, size);
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
+ _picture_mxf->set_frame_rate (_picture_mxf->edit_rate());
}
FrameInfo
-MonoPictureAssetWriter::write (uint8_t* data, int size)
+MonoPictureMXFWriter::write (uint8_t* data, int size)
{
assert (!_finalized);
@@ -71,7 +75,7 @@ MonoPictureAssetWriter::write (uint8_t* data, int size)
string hash;
ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0, &hash);
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _file.string(), r));
}
++_frames_written;
@@ -79,31 +83,27 @@ MonoPictureAssetWriter::write (uint8_t* data, int size)
}
void
-MonoPictureAssetWriter::fake_write (int size)
+MonoPictureMXFWriter::fake_write (int size)
{
assert (_started);
assert (!_finalized);
Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size);
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
}
++_frames_written;
}
void
-MonoPictureAssetWriter::finalize ()
+MonoPictureMXFWriter::finalize ()
{
- assert (!_finalized);
-
Kumu::Result_t r = _state->mxf_writer.Finalize();
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in finalizing video MXF", _mxf->file().string(), r));
}
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written);
- _asset->set_duration (_frames_written);
+ PictureMXFWriter::finalize ();
}
diff --git a/src/mono_picture_asset_writer.h b/src/mono_picture_mxf_writer.h
index e3922623..065171c2 100644
--- a/src/mono_picture_asset_writer.h
+++ b/src/mono_picture_mxf_writer.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,26 +17,33 @@
*/
+/** @file src/mono_picture_mxf_writer.h
+ * @brief MonoPictureMXFWriter class
+ */
+
+#ifndef LIBDCP_MONO_PICTURE_MXF_WRITER_H
+#define LIBDCP_MONO_PICTURE_MXF_WRITER_H
+
+#include "picture_mxf_writer.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
#include <stdint.h>
#include <string>
#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "picture_asset_writer.h"
-namespace libdcp {
+namespace dcp {
-/** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame,
- * rather than giving libdcp all the frames in one go).
+/** @class MonoPictureMXFWriter
+ * @brief A helper class for writing to MonoPictureMXFs
*
- * Objects of this class can only be created with MonoPictureAsset::start_write().
+ * Objects of this class can only be created with MonoPictureMXF::start_write().
*
* Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
* (a verbatim .j2c file). finalize() must be called after the last frame has been written.
* The action of finalize() can't be done in MonoPictureAssetWriter's destructor as it may
* throw an exception.
*/
-class MonoPictureAssetWriter : public PictureAssetWriter
+class MonoPictureMXFWriter : public PictureMXFWriter
{
public:
FrameInfo write (uint8_t *, int);
@@ -44,9 +51,9 @@ public:
void finalize ();
private:
- friend class MonoPictureAsset;
+ friend class MonoPictureMXF;
- MonoPictureAssetWriter (PictureAsset *, bool);
+ MonoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, Standard standard, bool);
void start (uint8_t *, int);
/* do this with an opaque pointer so we don't have to include
@@ -58,3 +65,5 @@ private:
};
}
+
+#endif
diff --git a/src/mxf_asset.cc b/src/mxf.cc
index c2428a3c..e1ed9650 100644
--- a/src/mxf_asset.cc
+++ b/src/mxf.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,18 +21,18 @@
* @brief Parent class for assets of DCPs made up of MXF files.
*/
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/nodes/element.h>
#include "AS_DCP.h"
#include "KM_prng.h"
#include "KM_util.h"
-#include "mxf_asset.h"
+#include "mxf.h"
#include "util.h"
#include "metadata.h"
#include "exceptions.h"
#include "kdm.h"
+#include "compose.hpp"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <iostream>
using std::string;
using std::list;
@@ -40,38 +40,44 @@ using std::pair;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::dynamic_pointer_cast;
-using namespace libdcp;
+using namespace dcp;
+
+MXF::MXF (Fraction edit_rate)
+ : Content (edit_rate)
+ , _encryption_context (0)
+ , _decryption_context (0)
+{
-MXFAsset::MXFAsset (boost::filesystem::path directory, boost::filesystem::path file_name)
- : Asset (directory, file_name)
- , _progress (0)
+}
+
+MXF::MXF (boost::filesystem::path file)
+ : Content (file)
, _encryption_context (0)
, _decryption_context (0)
- , _interop (false)
{
}
-MXFAsset::~MXFAsset ()
+MXF::~MXF ()
{
delete _encryption_context;
delete _decryption_context;
}
void
-MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info)
+MXF::fill_writer_info (ASDCP::WriterInfo* writer_info, Standard standard)
{
writer_info->ProductVersion = _metadata.product_version;
writer_info->CompanyName = _metadata.company_name;
writer_info->ProductName = _metadata.product_name.c_str();
- if (_interop) {
+ if (standard == INTEROP) {
writer_info->LabelSetType = ASDCP::LS_MXF_INTEROP;
} else {
writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
}
unsigned int c;
- Kumu::hex2bin (_uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
+ Kumu::hex2bin (_id.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
assert (c == Kumu::UUID_Length);
if (_key) {
@@ -85,19 +91,19 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info)
}
bool
-MXFAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+MXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- if (!Asset::equals (other, opt, note)) {
+ if (!Content::equals (other, opt, note)) {
return false;
}
- shared_ptr<const MXFAsset> other_mxf = dynamic_pointer_cast<const MXFAsset> (other);
+ shared_ptr<const MXF> other_mxf = dynamic_pointer_cast<const MXF> (other);
if (!other_mxf) {
note (ERROR, "comparing an MXF asset with a non-MXF asset");
return false;
}
- if (_file_name != other_mxf->_file_name) {
+ if (_file != other_mxf->file ()) {
note (ERROR, "MXF names differ");
if (!opt.mxf_names_can_differ) {
return false;
@@ -107,27 +113,13 @@ MXFAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::fun
return true;
}
+/** Set the (private) key that will be used to encrypt or decrypt this MXF's content.
+ * This is the top-secret key that is distributed (itself encrypted) to cinemas
+ * via Key Delivery Messages (KDMs).
+ * @param key Key to use.
+ */
void
-MXFAsset::write_to_cpl (xmlpp::Element* node) const
-{
- pair<string, string> const attr = cpl_node_attribute ();
- xmlpp::Element* a = node->add_child (cpl_node_name ());
- if (!attr.first.empty ()) {
- a->set_attribute (attr.first, attr.second);
- }
- a->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid);
- a->add_child ("AnnotationText")->add_child_text (_file_name.string ());
- a->add_child ("EditRate")->add_child_text (lexical_cast<string> (_edit_rate) + " 1");
- a->add_child ("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration));
- a->add_child ("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point));
- a->add_child ("Duration")->add_child_text (lexical_cast<string> (_duration));
- if (!_key_id.empty ()) {
- a->add_child("KeyId")->add_child_text ("urn:uuid:" + _key_id);
- }
-}
-
-void
-MXFAsset::set_key (Key key)
+MXF::set_key (Key key)
{
_key = key;
@@ -153,3 +145,24 @@ MXFAsset::set_key (Key key)
throw MiscError ("could not set up CBC initialization vector");
}
}
+
+void
+MXF::read_writer_info (ASDCP::WriterInfo const & info)
+{
+ char buffer[64];
+ Kumu::bin2UUIDhex (info.AssetUUID, 16, buffer, 64);
+ _id = buffer;
+}
+
+string
+MXF::pkl_type (Standard standard) const
+{
+ switch (standard) {
+ case INTEROP:
+ return String::compose ("application/x-smpte-mxf;asdcpKind=%1", asdcp_kind ());
+ case SMPTE:
+ return "application/x-smpte-mxf";
+ default:
+ assert (false);
+ }
+}
diff --git a/src/mxf_asset.h b/src/mxf.h
index 7a645b7c..48a1f64e 100644
--- a/src/mxf_asset.h
+++ b/src/mxf.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,106 +17,101 @@
*/
-#ifndef LIBDCP_MXF_ASSET_H
-#define LIBDCP_MXF_ASSET_H
+#ifndef LIBDCP_MXF_H
+#define LIBDCP_MXF_H
-#include <boost/signals2.hpp>
-#include "asset.h"
+#include "content.h"
#include "key.h"
#include "metadata.h"
+#include <boost/signals2.hpp>
namespace ASDCP {
class AESEncContext;
class AESDecContext;
}
-namespace libdcp
+namespace dcp
{
class MXFMetadata;
-/** @brief Parent class for assets which have MXF files */
-class MXFAsset : public Asset
+/** @class MXF
+ * @brief Parent class for classes which represent MXF files.
+ */
+class MXF : public Content
{
public:
- /** Construct an MXFAsset.
- * This class will not write anything to disk in this constructor, but subclasses may.
- *
- * @param directory Directory where MXF file is.
- * @param file_name Name of MXF file.
- */
- MXFAsset (boost::filesystem::path directory, boost::filesystem::path file_name);
-
- ~MXFAsset ();
+ MXF (Fraction edit_rate);
+ MXF (boost::filesystem::path file);
+ ~MXF ();
- virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
- virtual void write_to_cpl (xmlpp::Element *) const;
+ /** @return the 4-character key type for this MXF (MDIK, MDAK, etc.) */
virtual std::string key_type () const = 0;
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
/** Fill in a ADSCP::WriteInfo struct.
* @param w struct to fill in.
+ * @param standard INTEROP or SMPTE.
*/
- void fill_writer_info (ASDCP::WriterInfo* w);
-
- void set_progress (boost::signals2::signal<void (float)>* progress) {
- _progress = progress;
- }
+ void fill_writer_info (ASDCP::WriterInfo* w, Standard standard);
+ /** @return true if the data is encrypted */
bool encrypted () const {
return !_key_id.empty ();
}
+ /** Set the ID of the key that is used for encryption/decryption.
+ * @param i key ID.
+ */
void set_key_id (std::string i) {
_key_id = i;
}
+ /** @return the ID of the key used for encryption/decryption, or an empty string */
std::string key_id () const {
return _key_id;
}
-
+
void set_key (Key);
+ /** @return encryption/decryption key, if one has been set */
boost::optional<Key> key () const {
return _key;
}
+ /** @return encryption context, set up with any key that has been passed to set_key() */
ASDCP::AESEncContext* encryption_context () const {
return _encryption_context;
}
+ /** Set the metadata that is written to the MXF file.
+ * @param m Metadata.
+ */
void set_metadata (MXFMetadata m) {
_metadata = m;
}
+ /** @return metadata from the MXF file */
MXFMetadata metadata () const {
return _metadata;
}
- /** Set whether or not the asset should be written in Interop mode.
- * @param i true to use interop.
- */
- void set_interop (bool i) {
- _interop = i;
- }
-
- bool interop () const {
- return _interop;
- }
-
protected:
- virtual std::string cpl_node_name () const = 0;
- virtual std::pair<std::string, std::string> cpl_node_attribute () const {
- return std::make_pair ("", "");
- }
+ std::string pkl_type (Standard standard) const;
+ void read_writer_info (ASDCP::WriterInfo const &);
- /** Signal to emit to report progress, or 0 */
- boost::signals2::signal<void (float)>* _progress;
ASDCP::AESEncContext* _encryption_context;
ASDCP::AESDecContext* _decryption_context;
+ /** ID of the key used for encryption/decryption, or an empty string */
std::string _key_id;
+ /** Key used for encryption/decryption, if there is one */
boost::optional<Key> _key;
MXFMetadata _metadata;
- bool _interop;
};
}
diff --git a/src/mxf_writer.cc b/src/mxf_writer.cc
new file mode 100644
index 00000000..374e6590
--- /dev/null
+++ b/src/mxf_writer.cc
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/mxf_writer.h
+ * @brief MXFWriter class.
+ */
+
+#include "mxf_writer.h"
+#include "mxf.h"
+
+using namespace dcp;
+
+/** Create an MXFWriter.
+ * @param mxf MXF that we are writing.
+ * @param file File to write to.
+ */
+MXFWriter::MXFWriter (MXF* mxf, boost::filesystem::path file)
+ : _mxf (mxf)
+ , _file (file)
+ , _frames_written (0)
+ , _finalized (false)
+{
+ mxf->set_file (file);
+}
+
+MXFWriter::~MXFWriter ()
+{
+ assert (_finalized);
+}
+
+void
+MXFWriter::finalize ()
+{
+ assert (!_finalized);
+ _finalized = true;
+ _mxf->_intrinsic_duration = _frames_written;
+}
diff --git a/src/mxf_writer.h b/src/mxf_writer.h
new file mode 100644
index 00000000..b4e20f33
--- /dev/null
+++ b/src/mxf_writer.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/mxf_writer.h
+ * @brief MXFWriter class.
+ */
+
+#ifndef LIBDCP_MXF_WRITER_H
+#define LIBDCP_MXF_WRITER_H
+
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class MXF;
+
+/** @class MXFWriter
+ * @brief Parent class for classes which can write MXF files.
+ *
+ * The MXFWriter lasts for the duration of the write and is then discarded.
+ * They can only be created by calling start_write() on an MXF object.
+ */
+class MXFWriter : public boost::noncopyable
+{
+public:
+ virtual ~MXFWriter ();
+ virtual void finalize ();
+
+protected:
+ MXFWriter (MXF* mxf, boost::filesystem::path file);
+
+ /** MXF that we are writing */
+ MXF* _mxf;
+ /** File that we are writing to */
+ boost::filesystem::path _file;
+ /** Number of `frames' written so far; the definition of a frame
+ * varies depending on the subclass.
+ */
+ int64_t _frames_written;
+ /** true if finalize() has been called on this object */
+ bool _finalized;
+};
+
+}
+
+#endif
diff --git a/src/object.cc b/src/object.cc
new file mode 100644
index 00000000..315e501a
--- /dev/null
+++ b/src/object.cc
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/object.cc
+ * @brief Object class.
+ */
+
+#include "object.h"
+#include "util.h"
+
+using std::string;
+using namespace dcp;
+
+/** Create an Object with a random ID. */
+Object::Object ()
+ : _id (make_uuid ())
+{
+
+}
+
+/** Create an Object with a given ID.
+ * @param id ID to use.
+ */
+Object::Object (string id)
+ : _id (id)
+{
+
+}
diff --git a/src/srgb_linearised_gamma_lut.cc b/src/object.h
index 0d3650f4..82598c58 100644
--- a/src/srgb_linearised_gamma_lut.cc
+++ b/src/object.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,38 @@
*/
-#include "srgb_linearised_gamma_lut.h"
+/** @file src/object.h
+ * @brief Object class.
+ */
-using namespace libdcp;
+#ifndef LIBDCP_OBJECT_H
+#define LIBDCP_OBJECT_H
-LUTCache<SRGBLinearisedGammaLUT> SRGBLinearisedGammaLUT::cache;
+#include <boost/noncopyable.hpp>
+#include <string>
-SRGBLinearisedGammaLUT::SRGBLinearisedGammaLUT (int bits, float gamma)
- : LUT (bits, gamma)
+namespace dcp {
+
+/** @class Object
+ * @brief Some part of a DCP that has a UUID.
+ */
+class Object : public boost::noncopyable
{
- int const bit_length = pow (2, bits);
- for (int i = 0; i < bit_length; ++i) {
- float const p = static_cast<float> (i) / (bit_length - 1);
- if (p > 0.04045) {
- _lut[i] = pow ((p + 0.055) / 1.055, gamma);
- } else {
- _lut[i] = p / 12.92;
- }
+public:
+ Object ();
+ Object (std::string id);
+ virtual ~Object () {}
+
+ /** @return ID */
+ std::string id () const {
+ return _id;
}
+
+protected:
+ /** ID */
+ std::string _id;
+};
+
}
+
+#endif
diff --git a/src/parse/asset_map.cc b/src/parse/asset_map.cc
deleted file mode 100644
index 484c2710..00000000
--- a/src/parse/asset_map.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/asset_map.cc
- * @brief Classes used to parse a AssetMap.
- */
-
-#include <boost/algorithm/string.hpp>
-#include "asset_map.h"
-#include "../util.h"
-#include "../xml.h"
-
-using std::string;
-using std::list;
-using boost::shared_ptr;
-using namespace libdcp::parse;
-
-AssetMap::AssetMap (string file)
-{
- cxml::Document f ("AssetMap");
- f.read_file (file);
-
- id = f.string_child ("Id");
- creator = f.string_child ("Creator");
- volume_count = f.number_child<int64_t> ("VolumeCount");
- issue_date = f.string_child ("IssueDate");
- issuer = f.string_child ("Issuer");
- assets = type_grand_children<AssetMapAsset> (f, "AssetList", "Asset");
-}
-
-AssetMapAsset::AssetMapAsset (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- packing_list = node->optional_string_child ("PackingList").get_value_or ("");
- chunks = type_grand_children<Chunk> (node, "ChunkList", "Chunk");
-}
-
-Chunk::Chunk (shared_ptr<const cxml::Node> node)
-{
- path = node->string_child ("Path");
-
- string const prefix = "file://";
-
- if (boost::algorithm::starts_with (path, prefix)) {
- path = path.substr (prefix.length());
- }
-
- volume_index = node->optional_number_child<int64_t> ("VolumeIndex").get_value_or (0);
- offset = node->optional_number_child<int64_t> ("Offset").get_value_or (0);
- length = node->optional_number_child<int64_t> ("Length").get_value_or (0);
-}
-
-shared_ptr<AssetMapAsset>
-AssetMap::asset_from_id (string id) const
-{
- for (list<shared_ptr<AssetMapAsset> >::const_iterator i = assets.begin (); i != assets.end(); ++i) {
- if ((*i)->id == id) {
- return *i;
- }
- }
-
- return shared_ptr<AssetMapAsset> ();
-}
diff --git a/src/parse/asset_map.h b/src/parse/asset_map.h
deleted file mode 100644
index af3e8918..00000000
--- a/src/parse/asset_map.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/asset_map.h
- * @brief Classes used to parse a AssetMap.
- */
-
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <libcxml/cxml.h>
-
-namespace libdcp {
-
-namespace parse {
-
-/** @class Chunk
- * @brief A simple parser for and representation of a \<Chunk\> node within an asset map.
- */
-class Chunk
-{
-public:
- Chunk ();
- Chunk (boost::shared_ptr<const cxml::Node> node);
-
- std::string path;
- int64_t volume_index;
- int64_t offset;
- int64_t length;
-};
-
-/** @class AssetMapAsset
- * @brief A simple parser for and representation of an \<AssetMap\> node within an asset map.
- */
-class AssetMapAsset
-{
-public:
- AssetMapAsset ();
- AssetMapAsset (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string packing_list;
- std::list<boost::shared_ptr<Chunk> > chunks;
-};
-
-/** @class AssetMap
- * @brief A simple parser for and representation of an asset map file.
- */
-class AssetMap
-{
-public:
- AssetMap (std::string file);
-
- boost::shared_ptr<AssetMapAsset> asset_from_id (std::string id) const;
-
- std::string id;
- std::string creator;
- int64_t volume_count;
- std::string issue_date;
- std::string issuer;
- std::list<boost::shared_ptr<AssetMapAsset> > assets;
-};
-
-}
-
-}
diff --git a/src/parse/cpl.cc b/src/parse/cpl.cc
deleted file mode 100644
index f6ce434c..00000000
--- a/src/parse/cpl.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/cpl_file.cc
- * @brief Classes used to parse a CPL.
- */
-
-#include <iostream>
-#include "cpl.h"
-#include "../xml.h"
-#include "../util.h"
-
-using std::string;
-using std::bad_cast;
-using boost::shared_ptr;
-using namespace libdcp::parse;
-
-CPL::CPL (string file)
-{
- cxml::Document f ("CompositionPlaylist");
- f.read_file (file);
-
- id = f.string_child ("Id");
- annotation_text = f.optional_string_child ("AnnotationText").get_value_or ("");
- issue_date = f.string_child ("IssueDate");
- creator = f.optional_string_child ("Creator").get_value_or ("");
- content_title_text = f.string_child ("ContentTitleText");
- content_kind = content_kind_from_string (f.string_child ("ContentKind"));
- content_version = optional_type_child<ContentVersion> (f, "ContentVersion");
- f.ignore_child ("RatingList");
- reels = type_grand_children<Reel> (f, "ReelList", "Reel");
-
- f.ignore_child ("Issuer");
- f.ignore_child ("Signer");
- f.ignore_child ("Signature");
-
- f.done ();
-}
-
-ContentVersion::ContentVersion (shared_ptr<const cxml::Node> node)
-{
- id = node->optional_string_child ("Id").get_value_or ("");
- label_text = node->string_child ("LabelText");
- node->done ();
-}
-
-Reel::Reel (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- asset_list = type_child<CPLAssetList> (node, "AssetList");
-
- node->ignore_child ("AnnotationText");
- node->done ();
-}
-
-CPLAssetList::CPLAssetList (shared_ptr<const cxml::Node> node)
-{
- main_picture = optional_type_child<MainPicture> (node, "MainPicture");
- main_stereoscopic_picture = optional_type_child<MainStereoscopicPicture> (node, "MainStereoscopicPicture");
- main_sound = optional_type_child<MainSound> (node, "MainSound");
- main_subtitle = optional_type_child<MainSubtitle> (node, "MainSubtitle");
-
- node->done ();
-}
-
-MainPicture::MainPicture (shared_ptr<const cxml::Node> node)
- : Picture (node)
-{
-
-}
-
-MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr<const cxml::Node> node)
- : Picture (node)
-{
-
-}
-
-Picture::Picture (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- annotation_text = node->optional_string_child ("AnnotationText").get_value_or ("");
- edit_rate = Fraction (node->string_child ("EditRate"));
- intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("Duration");
- frame_rate = Fraction (node->string_child ("FrameRate"));
- try {
- screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio"));
- } catch (XMLError& e) {
- /* Maybe it's not a fraction */
- }
- try {
- float f = node->number_child<float> ("ScreenAspectRatio");
- screen_aspect_ratio = Fraction (f * 1000, 1000);
- } catch (bad_cast& e) {
-
- }
-
- key_id = node->optional_string_child ("KeyId").get_value_or ("");
-
- node->ignore_child ("Hash");
-
- node->done ();
-}
-
-MainSound::MainSound (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- annotation_text = node->optional_string_child ("AnnotationText").get_value_or ("");
- edit_rate = Fraction (node->string_child ("EditRate"));
- intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("Duration");
- key_id = node->optional_string_child ("KeyId").get_value_or ("");
-
- node->ignore_child ("Hash");
- node->ignore_child ("Language");
-
- node->done ();
-}
-
-MainSubtitle::MainSubtitle (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- annotation_text = node->optional_string_child ("AnnotationText").get_value_or ("");
- edit_rate = Fraction (node->string_child ("EditRate"));
- intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("Duration");
-
- node->ignore_child ("Hash");
- node->ignore_child ("Language");
-
- node->done ();
-}
diff --git a/src/parse/cpl.h b/src/parse/cpl.h
deleted file mode 100644
index 04bf9351..00000000
--- a/src/parse/cpl.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/parse/cpl.h
- * @brief Classes used to parse a CPL.
- */
-
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <libcxml/cxml.h>
-#include "../types.h"
-
-namespace libdcp {
-
-namespace parse {
-
-/** @brief A simple representation of a CPL \<Picture\> node */
-class Picture
-{
-public:
- Picture () {}
- Picture (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string annotation_text;
- Fraction edit_rate;
- /** Duration of the whole thing */
- int64_t intrinsic_duration;
- /** Start point in frames */
- int64_t entry_point;
- /** Duration that will actually play */
- int64_t duration;
- Fraction frame_rate;
- Fraction screen_aspect_ratio;
- std::string key_id;
-};
-
-
-/** @brief A simple parser for and representation of a CPL \<MainPicture\> node */
-class MainPicture : public Picture
-{
-public:
- MainPicture () {}
- MainPicture (boost::shared_ptr<const cxml::Node> node);
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainStereoscopicPicture\> node */
-class MainStereoscopicPicture : public Picture
-{
-public:
- MainStereoscopicPicture () {}
- MainStereoscopicPicture (boost::shared_ptr<const cxml::Node> node);
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainSound\> node */
-class MainSound
-{
-public:
- MainSound () {}
- MainSound (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string annotation_text;
- Fraction edit_rate;
- int64_t intrinsic_duration;
- int64_t entry_point;
- int64_t duration;
- std::string key_id;
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainSubtitle\> node */
-class MainSubtitle
-{
-public:
- MainSubtitle () {}
- MainSubtitle (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string annotation_text;
- Fraction edit_rate;
- int64_t intrinsic_duration;
- int64_t entry_point;
- int64_t duration;
-};
-
-/** @brief A simple parser for and representation of a CPL \<AssetList\> node */
-class CPLAssetList
-{
-public:
- CPLAssetList () {}
- CPLAssetList (boost::shared_ptr<const cxml::Node> node);
-
- boost::shared_ptr<MainPicture> main_picture;
- boost::shared_ptr<MainStereoscopicPicture> main_stereoscopic_picture;
- boost::shared_ptr<MainSound> main_sound;
- boost::shared_ptr<MainSubtitle> main_subtitle;
-};
-
-/** @brief A simple parser for and representation of a CPL \<Reel\> node */
-class Reel
-{
-public:
- Reel () {}
- Reel (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- boost::shared_ptr<CPLAssetList> asset_list;
-};
-
-
-/** @brief A simple parser for and representation of a CPL \<ContentVersion\> node */
-class ContentVersion
-{
-public:
- ContentVersion () {}
- ContentVersion (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string label_text;
-};
-
-/** @class CPL
- * @brief Class to parse a CPL
- *
- * This class is used to parse XML CPL files. It is rarely necessary
- * for the caller to use it outside libdcp.
- */
-class CPL
-{
-public:
- /** Parse a CPL XML file into our member variables */
- CPL (std::string file);
-
- std::string id;
- std::string annotation_text;
- std::string issue_date;
- std::string creator;
- std::string content_title_text;
- ContentKind content_kind;
- boost::shared_ptr<ContentVersion> content_version;
- std::list<boost::shared_ptr<Reel> > reels;
-};
-
-}
-
-}
-
diff --git a/src/parse/pkl.cc b/src/parse/pkl.cc
deleted file mode 100644
index bbf070ae..00000000
--- a/src/parse/pkl.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/pkl_file.cc
- * @brief Classes used to parse a PKL.
- */
-
-#include <iostream>
-#include "pkl.h"
-
-using namespace std;
-using namespace boost;
-using namespace libdcp::parse;
-
-PKL::PKL (string file)
-{
- cxml::Document f ("PackingList");
- f.read_file (file);
-
- id = f.string_child ("Id");
- annotation_text = f.optional_string_child ("AnnotationText").get_value_or ("");
- issue_date = f.string_child ("IssueDate");
- issuer = f.string_child ("Issuer");
- creator = f.string_child ("Creator");
- assets = type_grand_children<PKLAsset> (f, "AssetList", "Asset");
-}
-
-PKLAsset::PKLAsset (boost::shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- annotation_text = node->optional_string_child ("AnnotationText").get_value_or ("");
- hash = node->string_child ("Hash");
- size = node->number_child<int64_t> ("Size");
- type = node->string_child ("Type");
- original_file_name = node->optional_string_child ("OriginalFileName").get_value_or ("");
-}
diff --git a/src/picture_asset.h b/src/picture_asset.h
deleted file mode 100644
index c09808e2..00000000
--- a/src/picture_asset.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LIBDCP_PICTURE_ASSET_H
-#define LIBDCP_PICTURE_ASSET_H
-
-/** @file src/picture_asset.h
- * @brief An asset made up of JPEG2000 data
- */
-
-#include <openjpeg.h>
-#include "mxf_asset.h"
-#include "util.h"
-#include "metadata.h"
-
-namespace ASDCP {
- namespace JP2K {
- class PictureDescriptor;
- }
-}
-
-namespace libdcp
-{
-
-class MonoPictureFrame;
-class StereoPictureFrame;
-class PictureAssetWriter;
-
-/** @brief An asset made up of JPEG2000 data */
-class PictureAsset : public MXFAsset
-{
-public:
- /** Construct a PictureAsset.
- *
- * @param directory Directory where MXF file is.
- * @param mxf_name Name of MXF file.
- */
- PictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- /** Start a progressive write to this asset.
- * The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- *
- * @param overwrite true to overwrite an existing MXF file; in this mode, writing can be resumed to a partially-written MXF; false if the
- * MXF file does not exist.
- */
- virtual boost::shared_ptr<PictureAssetWriter> start_write (bool overwrite) = 0;
-
- virtual void read () = 0;
- virtual void create (std::vector<boost::filesystem::path> const &) {}
- virtual void create (boost::function<boost::filesystem::path (int)>) {}
-
- Size size () const {
- return _size;
- }
-
- void set_size (Size s) {
- _size = s;
- }
-
- void write_to_cpl (xmlpp::Element *) const;
-
-protected:
-
- std::string asdcp_kind () const {
- return "Picture";
- }
-
- bool frame_buffer_equals (
- int frame, EqualityOptions opt, boost::function<void (NoteType, std::string)> note,
- uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
- ) const;
-
- bool descriptor_equals (
- ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, boost::function<void (NoteType, std::string)>
- ) const;
-
- /** picture size in pixels */
- Size _size;
-
-private:
- std::string key_type () const;
- virtual int edit_rate_factor () const = 0;
-};
-
-
-}
-
-#endif
diff --git a/src/picture_asset.cc b/src/picture_mxf.cc
index b2eecee5..4a8e477b 100644
--- a/src/picture_asset.cc
+++ b/src/picture_mxf.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,25 +17,21 @@
*/
-/** @file src/picture_asset.cc
- * @brief An asset made up of JPEG2000 files
- */
-
+#include "picture_mxf.h"
+#include "util.h"
+#include "exceptions.h"
+#include "xyz_frame.h"
+#include "picture_mxf_writer.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include <libxml++/nodes/element.h>
+#include <openjpeg.h>
+#include <boost/filesystem.hpp>
#include <list>
#include <stdexcept>
#include <iostream>
#include <sstream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <openjpeg.h>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "picture_asset.h"
-#include "util.h"
-#include "exceptions.h"
-#include "xyz_frame.h"
-#include "picture_asset_writer.h"
using std::string;
using std::ostream;
@@ -48,41 +44,33 @@ using std::make_pair;
using std::istream;
using std::cout;
using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::lexical_cast;
-using namespace libdcp;
+using namespace dcp;
-PictureAsset::PictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : MXFAsset (directory, mxf_name)
+PictureMXF::PictureMXF (boost::filesystem::path file)
+ : MXF (file)
{
}
-void
-PictureAsset::write_to_cpl (xmlpp::Element* node) const
+PictureMXF::PictureMXF (Fraction edit_rate)
+ : MXF (edit_rate)
{
- MXFAsset::write_to_cpl (node);
-
- xmlpp::Node::NodeList c = node->get_children ();
- xmlpp::Node::NodeList::iterator i = c.begin();
- while (i != c.end() && (*i)->get_name() != cpl_node_name ()) {
- ++i;
- }
- assert (i != c.end ());
+}
- (*i)->add_child ("FrameRate")->add_child_text (lexical_cast<string> (_edit_rate * edit_rate_factor ()) + " 1");
- if (_interop) {
- stringstream s;
- s << std::fixed << std::setprecision (2) << (float (_size.width) / _size.height);
- (*i)->add_child ("ScreenAspectRatio")->add_child_text (s.str ());
- } else {
- (*i)->add_child ("ScreenAspectRatio")->add_child_text (lexical_cast<string> (_size.width) + " " + lexical_cast<string> (_size.height));
- }
+void
+PictureMXF::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
+{
+ _size.width = desc.StoredWidth;
+ _size.height = desc.StoredHeight;
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+ _intrinsic_duration = desc.ContainerDuration;
+ _frame_rate = Fraction (desc.SampleRate.Numerator, desc.SampleRate.Denominator);
+ _screen_aspect_ratio = Fraction (desc.AspectRatio.Numerator, desc.AspectRatio.Denominator);
}
bool
-PictureAsset::descriptor_equals (
+PictureMXF::descriptor_equals (
ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, boost::function<void (NoteType, string)> note
) const
{
@@ -124,7 +112,7 @@ PictureAsset::descriptor_equals (
}
bool
-PictureAsset::frame_buffer_equals (
+PictureMXF::frame_buffer_equals (
int frame, EqualityOptions opt, boost::function<void (NoteType, string)> note,
uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
) const
@@ -148,7 +136,7 @@ PictureAsset::frame_buffer_equals (
for (int c = 0; c < 3; ++c) {
if (image_A->size() != image_B->size()) {
- note (ERROR, "image sizes for frame " + lexical_cast<string>(frame) + " differ");
+ note (ERROR, String::compose ("image sizes for frame %1 differ", frame));
return false;
}
@@ -174,14 +162,12 @@ PictureAsset::frame_buffer_equals (
double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
- note (NOTE, "mean difference " + lexical_cast<string> (mean) + ", deviation " + lexical_cast<string> (std_dev));
+ note (NOTE, String::compose ("mean difference %1, deviation %2", mean, std_dev));
if (mean > opt.max_mean_pixel_error) {
note (
ERROR,
- "mean " + lexical_cast<string>(mean) +
- " out of range " + lexical_cast<string>(opt.max_mean_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
+ String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
);
return false;
@@ -190,9 +176,7 @@ PictureAsset::frame_buffer_equals (
if (std_dev > opt.max_std_dev_pixel_error) {
note (
ERROR,
- "standard deviation " + lexical_cast<string>(std_dev) +
- " out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
+ String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
);
return false;
@@ -202,10 +186,7 @@ PictureAsset::frame_buffer_equals (
}
string
-PictureAsset::key_type () const
+PictureMXF::key_type () const
{
return "MDIK";
}
-
-
-
diff --git a/src/picture_mxf.h b/src/picture_mxf.h
new file mode 100644
index 00000000..1ce2e7de
--- /dev/null
+++ b/src/picture_mxf.h
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_PICTURE_MXF_H
+#define LIBDCP_PICTURE_MXF_H
+
+/** @file src/picture_mxf.h
+ * @brief PictureMXF class.
+ */
+
+#include "mxf.h"
+#include "util.h"
+#include "metadata.h"
+#include <openjpeg.h>
+
+namespace ASDCP {
+ namespace JP2K {
+ class PictureDescriptor;
+ }
+}
+
+namespace dcp
+{
+
+class MonoPictureFrame;
+class StereoPictureFrame;
+class PictureMXFWriter;
+
+/** @class PictureMXF
+ * @brief An asset made up of JPEG2000 data.
+ */
+class PictureMXF : public MXF
+{
+public:
+ PictureMXF (boost::filesystem::path file);
+ PictureMXF (Fraction edit_rate);
+
+ virtual boost::shared_ptr<PictureMXFWriter> start_write (
+ boost::filesystem::path file,
+ Standard standard,
+ bool overwrite
+ ) = 0;
+
+ Size size () const {
+ return _size;
+ }
+
+ void set_size (Size s) {
+ _size = s;
+ }
+
+ Fraction frame_rate () const {
+ return _frame_rate;
+ }
+
+ void set_frame_rate (Fraction r) {
+ _frame_rate = r;
+ }
+
+ Fraction screen_aspect_ratio () const {
+ return _screen_aspect_ratio;
+ }
+
+ void set_screen_aspect_ratio (Fraction r) {
+ _screen_aspect_ratio = r;
+ }
+
+protected:
+
+ bool frame_buffer_equals (
+ int frame, EqualityOptions opt, boost::function<void (NoteType, std::string)> note,
+ uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
+ ) const;
+
+ bool descriptor_equals (
+ ASDCP::JP2K::PictureDescriptor const & a,
+ ASDCP::JP2K::PictureDescriptor const & b,
+ boost::function<void (NoteType, std::string)>
+ ) const;
+
+ void read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const &);
+
+ /** picture size in pixels */
+ Size _size;
+ Fraction _frame_rate;
+ Fraction _screen_aspect_ratio;
+
+private:
+ std::string key_type () const;
+ std::string asdcp_kind () const {
+ return "Picture";
+ }
+};
+
+
+}
+
+#endif
diff --git a/src/picture_asset_writer.cc b/src/picture_mxf_writer.cc
index 92b384db..46426401 100644
--- a/src/picture_asset_writer.cc
+++ b/src/picture_mxf_writer.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,19 +17,19 @@
*/
-#include <inttypes.h>
-#include <stdint.h>
-#include "AS_DCP.h"
#include "KM_fileio.h"
-#include "picture_asset_writer.h"
+#include "picture_mxf_writer.h"
#include "exceptions.h"
-#include "picture_asset.h"
+#include "picture_mxf.h"
+#include "AS_DCP.h"
+#include <inttypes.h>
+#include <stdint.h>
using std::istream;
using std::ostream;
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
FrameInfo::FrameInfo (istream& s)
: offset (0)
@@ -82,13 +82,12 @@ FrameInfo::write (FILE* f) const
#endif
}
-
-PictureAssetWriter::PictureAssetWriter (PictureAsset* asset, bool overwrite)
- : _asset (asset)
- , _frames_written (0)
+PictureMXFWriter::PictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, Standard standard, bool overwrite)
+ : MXFWriter (mxf, file)
+ , _picture_mxf (mxf)
, _started (false)
- , _finalized (false)
+ , _standard (standard)
, _overwrite (overwrite)
{
-
+
}
diff --git a/src/picture_asset_writer.h b/src/picture_mxf_writer.h
index a62b20b2..d1baa7ad 100644
--- a/src/picture_asset_writer.h
+++ b/src/picture_mxf_writer.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,19 +17,29 @@
*/
+/** @file src/picture_mxf_writer.h
+ * @brief PictureMXFWriter and FrameInfo classes.
+ */
+
+#ifndef LIBDCP_PICTURE_MXF_WRITER_H
+#define LIBDCP_PICTURE_MXF_WRITER_H
+
+#include "metadata.h"
+#include "types.h"
+#include "mxf_writer.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
#include <stdint.h>
#include <string>
#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "metadata.h"
-#include "types.h"
-namespace libdcp {
+namespace dcp {
-class PictureAsset;
+class PictureMXF;
-/** Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame) */
+/** @class FrameInfo
+ * @brief Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame)
+ */
struct FrameInfo
{
FrameInfo (uint64_t o, uint64_t s, std::string h)
@@ -49,31 +59,27 @@ struct FrameInfo
std::string hash;
};
-class PictureAssetWriter : public boost::noncopyable
+/** @class PictureMXFWriter
+ * @brief Parent class for classes which write picture MXF files.
+ */
+class PictureMXFWriter : public MXFWriter
{
public:
- virtual ~PictureAssetWriter () {}
virtual FrameInfo write (uint8_t *, int) = 0;
- virtual void finalize () = 0;
virtual void fake_write (int) = 0;
-
+
protected:
template <class P, class Q>
- friend void start (PictureAssetWriter *, boost::shared_ptr<P>, Q *, uint8_t *, int);
+ friend void start (PictureMXFWriter *, boost::shared_ptr<P>, Standard, Q *, uint8_t *, int);
- PictureAssetWriter (PictureAsset *, bool);
+ PictureMXFWriter (PictureMXF *, boost::filesystem::path, Standard standard, bool);
- PictureAsset* _asset;
-
- /** Number of picture frames written to the asset so far. For stereo assets
- * this will be incremented for each eye (i.e. there will be twice the number
- * of frames as in a mono asset).
- */
- int _frames_written;
+ PictureMXF* _picture_mxf;
bool _started;
- /** true if finalize() has been called */
- bool _finalized;
+ Standard _standard;
bool _overwrite;
};
}
+
+#endif
diff --git a/src/picture_asset_writer_common.cc b/src/picture_mxf_writer_common.cc
index 52848745..d8d1589b 100644
--- a/src/picture_asset_writer_common.cc
+++ b/src/picture_mxf_writer_common.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,19 +33,24 @@ struct ASDCPStateBase
};
template <class P, class Q>
-void libdcp::start (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t* data, int size)
+void dcp::start (PictureMXFWriter* writer, shared_ptr<P> state, Standard standard, Q* mxf, uint8_t* data, int size)
{
+ mxf->set_file (writer->_file);
+
if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
boost::throw_exception (MiscError ("could not parse J2K frame"));
}
state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
- state->picture_descriptor.EditRate = ASDCP::Rational (asset->edit_rate(), 1);
+ state->picture_descriptor.EditRate = ASDCP::Rational (mxf->edit_rate().numerator, mxf->edit_rate().denominator);
+
+ mxf->set_size (Size (state->picture_descriptor.StoredWidth, state->picture_descriptor.StoredHeight));
+ mxf->set_screen_aspect_ratio (Fraction (state->picture_descriptor.AspectRatio.Numerator, state->picture_descriptor.AspectRatio.Denominator));
- asset->fill_writer_info (&state->writer_info);
+ mxf->fill_writer_info (&state->writer_info, standard);
Kumu::Result_t r = state->mxf_writer.OpenWrite (
- asset->path().string().c_str(),
+ mxf->file().string().c_str(),
state->writer_info,
state->picture_descriptor,
16384,
@@ -53,7 +58,7 @@ void libdcp::start (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, u
);
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for writing", asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("could not open MXF file for writing", mxf->file().string(), r));
}
writer->_started = true;
diff --git a/src/reel.cc b/src/reel.cc
index ff51c025..4bdbcb5f 100644
--- a/src/reel.cc
+++ b/src/reel.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,46 +17,79 @@
*/
-#include <libxml++/nodes/element.h>
#include "reel.h"
#include "util.h"
-#include "picture_asset.h"
-#include "mono_picture_asset.h"
-#include "stereo_picture_asset.h"
-#include "sound_asset.h"
-#include "subtitle_asset.h"
+#include "picture_mxf.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_stereo_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
#include "kdm.h"
+#include <libxml++/nodes/element.h>
using std::string;
using std::list;
using std::cout;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-using namespace libdcp;
+using namespace dcp;
+
+Reel::Reel (boost::shared_ptr<const cxml::Node> node)
+ : Object (node->string_child ("Id"))
+{
+ shared_ptr<cxml::Node> asset_list = node->node_child ("AssetList");
+
+ shared_ptr<cxml::Node> main_picture = asset_list->optional_node_child ("MainPicture");
+ if (main_picture) {
+ _main_picture.reset (new ReelMonoPictureAsset (main_picture));
+ }
+
+ shared_ptr<cxml::Node> main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
+ if (main_stereoscopic_picture) {
+ _main_picture.reset (new ReelStereoPictureAsset (main_stereoscopic_picture));
+ }
+
+ shared_ptr<cxml::Node> main_sound = asset_list->optional_node_child ("MainSound");
+ if (main_sound) {
+ _main_sound.reset (new ReelSoundAsset (main_sound));
+ }
+
+ shared_ptr<cxml::Node> main_subtitle = asset_list->optional_node_child ("MainSubtitle");
+ if (main_subtitle) {
+ _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle));
+ }
+
+ node->ignore_child ("AnnotationText");
+ node->done ();
+}
void
-Reel::write_to_cpl (xmlpp::Element* node) const
+Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
{
xmlpp::Element* reel = node->add_child ("Reel");
reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
xmlpp::Element* asset_list = reel->add_child ("AssetList");
- if (_main_picture && dynamic_pointer_cast<MonoPictureAsset> (_main_picture)) {
+ if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) {
/* Mono pictures come before other stuff... */
- _main_picture->write_to_cpl (asset_list);
+ _main_picture->write_to_cpl (asset_list, standard);
}
if (_main_sound) {
- _main_sound->write_to_cpl (asset_list);
+ _main_sound->write_to_cpl (asset_list, standard);
}
if (_main_subtitle) {
- _main_subtitle->write_to_cpl (asset_list);
+ _main_subtitle->write_to_cpl (asset_list, standard);
}
- if (_main_picture && dynamic_pointer_cast<StereoPictureAsset> (_main_picture)) {
+ if (_main_picture && dynamic_pointer_cast<ReelStereoPictureAsset> (_main_picture)) {
/* ... but stereo pictures must come after */
- _main_picture->write_to_cpl (asset_list);
+ _main_picture->write_to_cpl (asset_list, standard);
}
}
@@ -100,16 +133,16 @@ Reel::encrypted () const
}
void
-Reel::add_kdm (KDM const & kdm)
+Reel::add (KDM const & kdm)
{
list<KDMKey> keys = kdm.keys ();
for (list<KDMKey>::iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->key_id() == _main_picture->key_id()) {
- _main_picture->set_key (i->key ());
+ _main_picture->mxf()->set_key (i->key ());
}
if (i->key_id() == _main_sound->key_id()) {
- _main_sound->set_key (i->key ());
+ _main_sound->mxf()->set_key (i->key ());
}
}
}
@@ -117,10 +150,41 @@ Reel::add_kdm (KDM const & kdm)
void
Reel::set_mxf_keys (Key key)
{
- _main_picture->set_key (key);
+ _main_picture->mxf()->set_key (key);
if (_main_sound) {
- _main_sound->set_key (key);
+ _main_sound->mxf()->set_key (key);
}
/* XXX: subtitle asset? */
}
+
+void
+Reel::add (shared_ptr<ReelAsset> asset)
+{
+ shared_ptr<ReelPictureAsset> p = dynamic_pointer_cast<ReelPictureAsset> (asset);
+ shared_ptr<ReelSoundAsset> so = dynamic_pointer_cast<ReelSoundAsset> (asset);
+ shared_ptr<ReelSubtitleAsset> su = dynamic_pointer_cast<ReelSubtitleAsset> (asset);
+ if (p) {
+ _main_picture = p;
+ } else if (so) {
+ _main_sound = so;
+ } else if (su) {
+ _main_subtitle = su;
+ }
+}
+
+void
+Reel::resolve_refs (list<shared_ptr<Object> > objects)
+{
+ if (_main_picture) {
+ _main_picture->content().resolve (objects);
+ }
+
+ if (_main_sound) {
+ _main_sound->content().resolve (objects);
+ }
+
+ if (_main_subtitle) {
+ _main_subtitle->content().resolve (objects);
+ }
+}
diff --git a/src/reel.h b/src/reel.h
index 35302f17..14def9c8 100644
--- a/src/reel.h
+++ b/src/reel.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,64 +20,75 @@
#ifndef LIBDCP_REEL_H
#define LIBDCP_REEL_H
-#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
-#include <libxml++/libxml++.h>
#include "key.h"
#include "types.h"
+#include "ref.h"
+#include <libxml++/libxml++.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <list>
-namespace xmlpp {
+namespace cxml {
class Node;
}
-namespace libdcp {
+namespace dcp {
-class PictureAsset;
-class SoundAsset;
-class SubtitleAsset;
-class KDM;
+class KDM;
+class ReelAsset;
+class ReelPictureAsset;
+class ReelSoundAsset;
+class ReelSubtitleAsset;
+class Content;
-/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */
-class Reel
+/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */
+class Reel : public Object
{
public:
+ Reel () {}
+
Reel (
- boost::shared_ptr<PictureAsset> picture,
- boost::shared_ptr<SoundAsset> sound,
- boost::shared_ptr<SubtitleAsset> subtitle
+ boost::shared_ptr<ReelPictureAsset> picture,
+ boost::shared_ptr<ReelSoundAsset> sound,
+ boost::shared_ptr<ReelSubtitleAsset> subtitle
)
: _main_picture (picture)
, _main_sound (sound)
, _main_subtitle (subtitle)
{}
+
+ Reel (boost::shared_ptr<const cxml::Node>);
- boost::shared_ptr<const PictureAsset> main_picture () const {
+ boost::shared_ptr<ReelPictureAsset> main_picture () const {
return _main_picture;
}
- boost::shared_ptr<const SoundAsset> main_sound () const {
+ boost::shared_ptr<ReelSoundAsset> main_sound () const {
return _main_sound;
}
- boost::shared_ptr<const SubtitleAsset> main_subtitle () const {
+ boost::shared_ptr<ReelSubtitleAsset> main_subtitle () const {
return _main_subtitle;
}
- void write_to_cpl (xmlpp::Element *) const;
+ void add (boost::shared_ptr<ReelAsset> asset);
+
+ void write_to_cpl (xmlpp::Element* node, Standard standard) const;
bool encrypted () const;
- void set_mxf_keys (libdcp::Key);
+ void set_mxf_keys (dcp::Key);
bool equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> notes) const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
private:
- boost::shared_ptr<PictureAsset> _main_picture;
- boost::shared_ptr<SoundAsset> _main_sound;
- boost::shared_ptr<SubtitleAsset> _main_subtitle;
+ boost::shared_ptr<ReelPictureAsset> _main_picture;
+ boost::shared_ptr<ReelSoundAsset> _main_sound;
+ boost::shared_ptr<ReelSubtitleAsset> _main_subtitle;
};
}
diff --git a/src/reel_asset.cc b/src/reel_asset.cc
new file mode 100644
index 00000000..fa0068c5
--- /dev/null
+++ b/src/reel_asset.cc
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "reel_asset.h"
+#include "content.h"
+#include "compose.hpp"
+#include <libcxml/cxml.h>
+
+using std::pair;
+using std::string;
+using std::make_pair;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using namespace dcp;
+
+ReelAsset::ReelAsset ()
+ : Object (make_uuid ())
+ , _content (_id)
+ , _edit_rate (Fraction (24, 1))
+ , _intrinsic_duration (0)
+ , _entry_point (0)
+ , _duration (0)
+{
+
+}
+
+/** Construct a ReelAsset.
+ * @param content Content that this asset refers to.
+ * @param entry_point Entry point to use in that content.
+ */
+ReelAsset::ReelAsset (boost::shared_ptr<Content> content, int64_t entry_point)
+ : Object (content->id ())
+ , _content (content)
+ , _edit_rate (content->edit_rate ())
+ , _intrinsic_duration (content->intrinsic_duration ())
+ , _entry_point (entry_point)
+ , _duration (_intrinsic_duration - _entry_point)
+ , _hash (make_digest (content->file (), 0))
+{
+ /* default _annotation_text to the leaf name of our file */
+ _annotation_text = content->file().leaf().string ();
+}
+
+ReelAsset::ReelAsset (boost::shared_ptr<const cxml::Node> node)
+ : Object (node->string_child ("Id"))
+ , _content (_id)
+ , _annotation_text (node->optional_string_child ("AnnotationText").get_value_or (""))
+ , _edit_rate (Fraction (node->string_child ("EditRate")))
+ , _intrinsic_duration (node->number_child<int64_t> ("IntrinsicDuration"))
+ , _entry_point (node->number_child<int64_t> ("EntryPoint"))
+ , _duration (node->number_child<int64_t> ("Duration"))
+ , _hash (node->optional_string_child ("Hash").get_value_or (""))
+ , _key_id (node->optional_string_child ("KeyId").get_value_or (""))
+{
+ if (_id.length() > 9) {
+ _id = _id.substr (9);
+ _content.set_id (_id);
+ }
+
+ if (_key_id.length() > 9) {
+ _key_id = _key_id.substr (9);
+ }
+}
+
+void
+ReelAsset::write_to_cpl (xmlpp::Node* node, Standard) const
+{
+ pair<string, string> const attr = cpl_node_attribute ();
+ xmlpp::Element* a = node->add_child (cpl_node_name ());
+ if (!attr.first.empty ()) {
+ a->set_attribute (attr.first, attr.second);
+ }
+ a->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ a->add_child("AnnotationText")->add_child_text (_annotation_text);
+ a->add_child("EditRate")->add_child_text (String::compose ("%1 %2", _edit_rate.numerator, _edit_rate.denominator));
+ a->add_child("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration));
+ a->add_child("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point));
+ a->add_child("Duration")->add_child_text (lexical_cast<string> (_duration));
+ if (!_key_id.empty ()) {
+ a->add_child("KeyId")->add_child_text ("urn:uuid:" + _key_id);
+ }
+}
+
+pair<string, string>
+ReelAsset::cpl_node_attribute () const
+{
+ return make_pair ("", "");
+}
diff --git a/src/reel_asset.h b/src/reel_asset.h
new file mode 100644
index 00000000..a71290ae
--- /dev/null
+++ b/src/reel_asset.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_REEL_ASSET_H
+#define LIBDCP_REEL_ASSET_H
+
+#include "object.h"
+#include "util.h"
+#include "ref.h"
+#include <boost/shared_ptr.hpp>
+
+namespace cxml {
+ class Node;
+}
+
+namespace xmlpp {
+ class Node;
+}
+
+namespace dcp {
+
+class Content;
+
+/** @class ReelAsset
+ * @brief An entry in a &lt;Reel&gt; which refers to a use of a piece of content.
+ *
+ * This class encapsulates the XML that exists in a &lt;Reel&gt; to say
+ * that a piece of content is used in this reel. It does not
+ * describe the content itself (but links to a Content object which does).
+ */
+class ReelAsset : public Object
+{
+public:
+ ReelAsset ();
+ ReelAsset (boost::shared_ptr<Content> content, int64_t entry_point);
+ ReelAsset (boost::shared_ptr<const cxml::Node>);
+
+ virtual void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
+ virtual bool equals (
+ boost::shared_ptr<const ReelAsset>,
+ EqualityOptions,
+ boost::function<void (NoteType, std::string)>)
+ const {
+
+ return false;
+ }
+
+ /** @return a Ref to our actual content */
+ Ref<Content>& content () {
+ return _content;
+ }
+
+ /** @return true if a KeyId is specified for this asset, implying
+ * that its content is encrypted.
+ */
+ bool encrypted () const {
+ return !_key_id.empty ();
+ }
+
+ /** @return Key ID to describe the key that encrypts this asset's;
+ * content.
+ */
+ std::string key_id () const {
+ return _key_id;
+ }
+
+protected:
+ /** @return the node name that this asset uses in the CPL's &lt;Reel&gt; node
+ * e.g. MainPicture, MainSound etc.
+ */
+ virtual std::string cpl_node_name () const = 0;
+
+ /** @return Any attribute that should be used on the asset's node in the
+ * CPL.
+ */
+ virtual std::pair<std::string, std::string> cpl_node_attribute () const;
+
+ /** Reference to the content (MXF or XML file) that this reel entry
+ * applies to.
+ */
+ Ref<Content> _content;
+
+private:
+
+ std::string _annotation_text; ///< The <AnnotationText> from the reel's entry for this asset
+ Fraction _edit_rate; ///< The <EditRate> from the reel's entry for this asset
+ int64_t _intrinsic_duration; ///< The <IntrinsicDuration> from the reel's entry for this asset
+ int64_t _entry_point; ///< The <EntryPoint> from the reel's entry for this asset
+ int64_t _duration; ///< The <Duration> from the reel's entry for this asset
+ std::string _hash; ///< The <Hash> from the reel's entry for this asset
+ std::string _key_id; ///< The <KeyId> from the reel's entry for this asset, or empty if there isn't one
+};
+
+}
+
+#endif
diff --git a/src/reel_mono_picture_asset.cc b/src/reel_mono_picture_asset.cc
new file mode 100644
index 00000000..b4ed6301
--- /dev/null
+++ b/src/reel_mono_picture_asset.cc
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_mono_picture_asset.cc
+ * @brief ReelMonoPictureAsset class.
+ */
+
+#include "reel_mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelMonoPictureAsset::ReelMonoPictureAsset ()
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<MonoPictureMXF> mxf, int64_t entry_point)
+ : ReelPictureAsset (mxf, entry_point)
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+ node->done ();
+}
+
+string
+ReelMonoPictureAsset::cpl_node_name () const
+{
+ return "MainPicture";
+}
+
diff --git a/src/reel_mono_picture_asset.h b/src/reel_mono_picture_asset.h
new file mode 100644
index 00000000..a25550a4
--- /dev/null
+++ b/src/reel_mono_picture_asset.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_mono_picture_asset.h
+ * @brief ReelMonoPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_MONO_PICTURE_ASSET_H
+#define LIBDCP_REEL_MONO_PICTURE_ASSET_H
+
+#include "reel_picture_asset.h"
+
+namespace dcp {
+
+class MonoPictureMXF;
+
+/** @class ReelMonoPictureAsset
+ * @brief Part of a Reel's description which refers to a monoscopic picture MXF.
+ */
+class ReelMonoPictureAsset : public ReelPictureAsset
+{
+public:
+ ReelMonoPictureAsset ();
+ ReelMonoPictureAsset (boost::shared_ptr<MonoPictureMXF> content, int64_t entry_point);
+ ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
diff --git a/src/reel_picture_asset.cc b/src/reel_picture_asset.cc
new file mode 100644
index 00000000..d1910bb3
--- /dev/null
+++ b/src/reel_picture_asset.cc
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_picture_asset.h
+ * @brief ReelPictureAsset class.
+ */
+
+#include "content.h"
+#include "reel_picture_asset.h"
+#include "picture_mxf.h"
+#include "compose.hpp"
+#include <libcxml/cxml.h>
+
+using std::bad_cast;
+using std::string;
+using std::stringstream;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelPictureAsset::ReelPictureAsset ()
+ : _frame_rate (Fraction (24, 1))
+ , _screen_aspect_ratio (Fraction (1998, 1080))
+{
+
+}
+
+ReelPictureAsset::ReelPictureAsset (boost::shared_ptr<PictureMXF> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+ , _frame_rate (content->frame_rate ())
+ , _screen_aspect_ratio (content->screen_aspect_ratio ())
+{
+
+}
+
+ReelPictureAsset::ReelPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ _frame_rate = Fraction (node->string_child ("FrameRate"));
+ try {
+ _screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio"));
+ } catch (XMLError& e) {
+ /* Maybe it's not a fraction */
+ }
+ try {
+ float f = node->number_child<float> ("ScreenAspectRatio");
+ _screen_aspect_ratio = Fraction (f * 1000, 1000);
+ } catch (bad_cast& e) {
+
+ }
+}
+
+void
+ReelPictureAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+{
+ ReelAsset::write_to_cpl (node, standard);
+
+ xmlpp::Node::NodeList c = node->get_children ();
+ xmlpp::Node::NodeList::iterator i = c.begin();
+ while (i != c.end() && (*i)->get_name() != cpl_node_name ()) {
+ ++i;
+ }
+
+ assert (i != c.end ());
+
+ (*i)->add_child ("FrameRate")->add_child_text (String::compose ("%1 %2", _frame_rate.numerator, _frame_rate.denominator));
+ if (standard == INTEROP) {
+ stringstream s;
+ s << std::fixed << std::setprecision (2) << (float (_screen_aspect_ratio.numerator) / _screen_aspect_ratio.denominator);
+ (*i)->add_child ("ScreenAspectRatio")->add_child_text (s.str ());
+ } else {
+ (*i)->add_child ("ScreenAspectRatio")->add_child_text (
+ String::compose ("%1 %2", _screen_aspect_ratio.numerator, _screen_aspect_ratio.denominator)
+ );
+ }
+}
diff --git a/src/reel_picture_asset.h b/src/reel_picture_asset.h
new file mode 100644
index 00000000..547f3ada
--- /dev/null
+++ b/src/reel_picture_asset.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_picture_asset.h
+ * @brief ReelPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_PICTURE_ASSET_H
+#define LIBDCP_REEL_PICTURE_ASSET_H
+
+#include "reel_asset.h"
+#include "picture_mxf.h"
+
+namespace dcp {
+
+/** @class ReelPictureAsset
+ * @brief Part of a Reel's description which refers to a picture MXF.
+ */
+class ReelPictureAsset : public ReelAsset
+{
+public:
+ ReelPictureAsset ();
+ ReelPictureAsset (boost::shared_ptr<PictureMXF> content, int64_t entry_point);
+ ReelPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+ virtual void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
+ boost::shared_ptr<PictureMXF> mxf () {
+ return boost::dynamic_pointer_cast<PictureMXF> (_content.object ());
+ }
+
+ void set_screen_aspect_ratio (Fraction a) {
+ _screen_aspect_ratio = a;
+ }
+
+private:
+ Fraction _frame_rate;
+ Fraction _screen_aspect_ratio;
+};
+
+}
+
+#endif
diff --git a/src/reel_sound_asset.cc b/src/reel_sound_asset.cc
new file mode 100644
index 00000000..984434dd
--- /dev/null
+++ b/src/reel_sound_asset.cc
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_sound_asset.cc
+ * @brief ReelSoundAsset class.
+ */
+
+#include "reel_sound_asset.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSoundAsset::ReelSoundAsset (boost::shared_ptr<Content> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSoundAsset::ReelSoundAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSoundAsset::cpl_node_name () const
+{
+ return "MainSound";
+}
diff --git a/src/reel_sound_asset.h b/src/reel_sound_asset.h
new file mode 100644
index 00000000..42835c84
--- /dev/null
+++ b/src/reel_sound_asset.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_sound_asset.h
+ * @brief ReelSoundAsset class.
+ */
+
+#include "reel_asset.h"
+#include "sound_mxf.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+/** @class ReelSoundAsset
+ * @brief Part of a Reel's description which refers to a sound MXF.
+ */
+class ReelSoundAsset : public ReelAsset
+{
+public:
+ ReelSoundAsset (boost::shared_ptr<Content> content, int64_t entry_point);
+ ReelSoundAsset (boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<SoundMXF> mxf () {
+ return boost::dynamic_pointer_cast<SoundMXF> (_content.object ());
+ }
+
+ boost::shared_ptr<const SoundMXF> mxf () const {
+ return boost::dynamic_pointer_cast<const SoundMXF> (_content.object ());
+ }
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
diff --git a/src/reel_stereo_picture_asset.cc b/src/reel_stereo_picture_asset.cc
new file mode 100644
index 00000000..09178dc2
--- /dev/null
+++ b/src/reel_stereo_picture_asset.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_stereo_picture_asset.cc
+ * @brief ReelStereoPictureAsset class.
+ */
+
+#include "reel_stereo_picture_asset.h"
+#include "stereo_picture_mxf.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelStereoPictureAsset::ReelStereoPictureAsset ()
+{
+
+}
+
+ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<StereoPictureMXF> mxf, int64_t entry_point)
+ : ReelPictureAsset (mxf, entry_point)
+{
+
+}
+
+ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+ node->done ();
+}
+
+string
+ReelStereoPictureAsset::cpl_node_name () const
+{
+ return "msp-cpl:MainStereoscopicPicture";
+}
+
+pair<string, string>
+ReelStereoPictureAsset::cpl_node_attribute (Standard standard) const
+{
+ if (standard == INTEROP) {
+ return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
+ } else {
+ return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
+ }
+
+ return make_pair ("", "");
+}
diff --git a/src/reel_stereo_picture_asset.h b/src/reel_stereo_picture_asset.h
new file mode 100644
index 00000000..57cc4da1
--- /dev/null
+++ b/src/reel_stereo_picture_asset.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_stereo_picture_asset.h
+ * @brief ReelStereoPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_STEREO_PICTURE_ASSET_H
+#define LIBDCP_REEL_STEREO_PICTURE_ASSET_H
+
+#include "reel_picture_asset.h"
+
+namespace dcp {
+
+class StereoPictureMXF;
+
+/** @class ReelStereoPictureAsset
+ * @brief Part of a Reel's description which refers to a stereoscopic picture MXF.
+ */
+class ReelStereoPictureAsset : public ReelPictureAsset
+{
+public:
+ ReelStereoPictureAsset ();
+ ReelStereoPictureAsset (boost::shared_ptr<StereoPictureMXF> content, int64_t entry_point);
+ ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+private:
+ std::string cpl_node_name () const;
+ std::pair<std::string, std::string> cpl_node_attribute (Standard standard) const;
+};
+
+}
+
+#endif
+
diff --git a/src/reel_subtitle_asset.cc b/src/reel_subtitle_asset.cc
new file mode 100644
index 00000000..1c948200
--- /dev/null
+++ b/src/reel_subtitle_asset.cc
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_subtitle_asset.cc
+ * @brief ReelSubtitleAsset class.
+ */
+
+#include "subtitle_content.h"
+#include "reel_subtitle_asset.h"
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<SubtitleContent> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSubtitleAsset::cpl_node_name () const
+{
+ return "MainSubtitle";
+}
diff --git a/src/reel_subtitle_asset.h b/src/reel_subtitle_asset.h
new file mode 100644
index 00000000..5cdfac13
--- /dev/null
+++ b/src/reel_subtitle_asset.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/reel_subtitle_asset.h
+ * @brief ReelSubtitleAsset class.
+ */
+
+#ifndef LIBDCP_REEL_SUBTITLE_ASSET_H
+#define LIBDCP_REEL_SUBTITLE_ASSET_H
+
+#include "reel_asset.h"
+
+namespace dcp {
+
+class SubtitleContent;
+
+/** @class ReelSubtitleAsset
+ * @brief Part of a Reel's description which refers to a subtitle XML file.
+ */
+class ReelSubtitleAsset : public ReelAsset
+{
+public:
+ ReelSubtitleAsset (boost::shared_ptr<SubtitleContent> content, int64_t entry_point);
+ ReelSubtitleAsset (boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<SubtitleContent> subtitle_content () const {
+ return boost::dynamic_pointer_cast<SubtitleContent> (_content.object ());
+ }
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
diff --git a/src/ref.h b/src/ref.h
new file mode 100644
index 00000000..c22222cc
--- /dev/null
+++ b/src/ref.h
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/ref.h
+ * @brief Ref class.
+ */
+
+#ifndef LIBDCP_REF_H
+#define LIBDCP_REF_H
+
+#include "exceptions.h"
+#include "object.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+/** @class Ref
+ * @brief A reference to an object which is identified by a universally-unique identifier (UUID).
+ *
+ * This class is a `pointer' to a thing. It will always know the
+ * UUID of the thing, and it may have a shared_ptr to the C++ object
+ * which represents the thing.
+ *
+ * If the Ref does not have a shared_ptr it may be given one by
+ * calling resolve() with a list of objects. The shared_ptr will be
+ * set up using any object on the list which has a matching ID.
+ */
+template<class T>
+class Ref
+{
+public:
+ /** Initialise a Ref with an ID but no shared_ptr */
+ Ref (std::string id)
+ : _id (id)
+ {}
+
+ /** Initialise a Ref with a shared_ptr to an object */
+ Ref (boost::shared_ptr<T> object)
+ : _id (object->id ())
+ , _object (object)
+ {}
+
+ /** Set the ID of this Ref */
+ void set_id (std::string id)
+ {
+ _id = id;
+ }
+
+ /** Look through a list of objects and copy a shared_ptr to any object
+ * which matches the ID of this one.
+ */
+ void resolve (std::list<boost::shared_ptr<Object> > objects)
+ {
+ typename std::list<boost::shared_ptr<Object> >::iterator i = objects.begin();
+ while (i != objects.end() && (*i)->id() != _id) {
+ ++i;
+ }
+
+ if (i != objects.end ()) {
+ _object = boost::dynamic_pointer_cast<T> (*i);
+ }
+ }
+
+ /** @return the ID of the thing that we are pointing to */
+ std::string id () const {
+ return _id;
+ }
+
+ /** @return a shared_ptr to the thing; an UnresolvedRefError is thrown
+ * if the shared_ptr is not known.
+ */
+ boost::shared_ptr<T> object () const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object;
+ }
+
+ /** operator-> to access the shared_ptr; an UnresolvedRefError is thrown
+ * if the shared_ptr is not known.
+ */
+ T * operator->() const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object.get ();
+ }
+
+ /** @return true if a shared_ptr is known for this Ref */
+ bool resolved () const {
+ return _object;
+ }
+
+private:
+ std::string _id; ///< ID; will always be known
+ boost::shared_ptr<T> _object; ///< shared_ptr to the thing, may be null.
+};
+
+}
+
+#endif
diff --git a/src/rgb_xyz.cc b/src/rgb_xyz.cc
index dea2106c..92997441 100644
--- a/src/rgb_xyz.cc
+++ b/src/rgb_xyz.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,16 +27,22 @@
using std::min;
using std::max;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
#define DCI_COEFFICIENT (48.0 / 52.37)
/** Convert an openjpeg XYZ image to RGB.
* @param xyz_frame Frame in XYZ.
+ * @param lut_in Input Gamma LUT to use.
+ * @param lut_out Output Gamma LUT to use.
* @return RGB image.
*/
shared_ptr<ARGBFrame>
-libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out)
+dcp::xyz_to_rgb (
+ boost::shared_ptr<const XYZFrame> xyz_frame,
+ boost::shared_ptr<const GammaLUT> lut_in,
+ boost::shared_ptr<const GammaLUT> lut_out
+ )
{
int const max_colour = pow (2, lut_out->bit_depth()) - 1;
@@ -99,8 +105,13 @@ libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const LUT>
return argb_frame;
}
-shared_ptr<libdcp::XYZFrame>
-libdcp::rgb_to_xyz (shared_ptr<const Image> rgb, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out, double const colour_matrix[3][3])
+shared_ptr<dcp::XYZFrame>
+dcp::rgb_to_xyz (
+ boost::shared_ptr<const Image> rgb,
+ boost::shared_ptr<const GammaLUT> lut_in,
+ boost::shared_ptr<const GammaLUT> lut_out,
+ double const colour_matrix[3][3]
+ )
{
assert (lut_in->bit_depth() == 12);
assert (lut_out->bit_depth() == 16);
diff --git a/src/rgb_xyz.h b/src/rgb_xyz.h
index 87959cb3..28e09230 100644
--- a/src/rgb_xyz.h
+++ b/src/rgb_xyz.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,19 +19,19 @@
#include <boost/shared_ptr.hpp>
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
class XYZFrame;
-class LUT;
+class GammaLUT;
class Image;
extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (
- boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>
+ boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const GammaLUT>
);
extern boost::shared_ptr<XYZFrame> rgb_to_xyz (
- boost::shared_ptr<const Image>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>, double const colour_matrix[3][3]
+ boost::shared_ptr<const Image>, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const GammaLUT>, double const colour_matrix[3][3]
);
}
diff --git a/src/signer.cc b/src/signer.cc
index 63da8d8e..a280cb07 100644
--- a/src/signer.cc
+++ b/src/signer.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,33 +17,49 @@
*/
+/** @file src/signer.cc
+ * @brief Signer class.
+ */
+
+#include "signer.h"
+#include "exceptions.h"
+#include <libcxml/cxml.h>
#include <libxml++/libxml++.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/dl.h>
#include <xmlsec/app.h>
#include <xmlsec/crypto.h>
-#include <libcxml/cxml.h>
-#include "signer.h"
-#include "exceptions.h"
using std::string;
using std::list;
using std::cout;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
-/** @param signer_key Filename of private key to sign with */
+/** Add a &lt;Signer&gt; and &lt;ds:Signature&gt; nodes to an XML node.
+ * @param parent XML node to add to.
+ * @param standard INTEROP or SMPTE.
+ */
void
-Signer::sign (xmlpp::Element* parent, bool interop) const
+Signer::sign (xmlpp::Element* parent, Standard standard) const
{
- add_signer (parent, "dsig");
+ /* <Signer> */
+
+ xmlpp::Element* signer = parent->add_child("Signer");
+ xmlpp::Element* data = signer->add_child("X509Data", "dsig");
+ xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", "dsig");
+ serial_element->add_child("X509IssuerName", "dsig")->add_child_text (_certificates.leaf()->issuer());
+ serial_element->add_child("X509SerialNumber", "dsig")->add_child_text (_certificates.leaf()->serial());
+ data->add_child("X509SubjectName", "dsig")->add_child_text (_certificates.leaf()->subject());
+ /* <Signature> */
+
xmlpp::Element* signature = parent->add_child("Signature", "dsig");
xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
- if (interop) {
+ if (standard == INTEROP) {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
} else {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
@@ -113,21 +129,3 @@ Signer::add_signature_value (xmlpp::Node* parent, string ns) const
xmlSecDSigCtxDestroy (signature_context);
}
-
-void
-Signer::add_signer (xmlpp::Element* parent, string ns) const
-{
- xmlpp::Element* signer = parent->add_child("Signer");
-
- {
- xmlpp::Element* data = signer->add_child("X509Data", ns);
-
- {
- xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", ns);
- serial_element->add_child("X509IssuerName", ns)->add_child_text (_certificates.leaf()->issuer());
- serial_element->add_child("X509SerialNumber", ns)->add_child_text (_certificates.leaf()->serial());
- }
-
- data->add_child("X509SubjectName", ns)->add_child_text (_certificates.leaf()->subject());
- }
-}
diff --git a/src/signer.h b/src/signer.h
index efb8099b..6e258f8d 100644
--- a/src/signer.h
+++ b/src/signer.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,25 +17,39 @@
*/
-#include <boost/filesystem.hpp>
+#ifndef LIBDCP_SIGNER_H
+#define LIBDCP_SIGNER_H
+
+/** @file src/signer.h
+ * @brief Signer class.
+ */
+
#include "certificates.h"
+#include "types.h"
+#include <boost/filesystem.hpp>
namespace xmlpp {
class Element;
class Node;
}
-namespace libdcp {
+namespace dcp {
-class Signer
+/** @class Signer
+ * @brief A class which can sign XML files.
+ */
+class Signer : public boost::noncopyable
{
public:
+ /** @param c Certificate chain to sign with.
+ * @param k Key to sign with.
+ */
Signer (CertificateChain c, boost::filesystem::path k)
: _certificates (c)
, _key (k)
{}
- void sign (xmlpp::Element* parent, bool interop) const;
+ void sign (xmlpp::Element* parent, Standard standard) const;
void add_signature_value (xmlpp::Node* parent, std::string ns) const;
CertificateChain const & certificates () const {
@@ -44,11 +58,12 @@ public:
private:
- void add_signer (xmlpp::Element* parent, std::string ns) const;
-
+ /** Certificate chain to sign with */
CertificateChain _certificates;
/** Filename of signer key */
boost::filesystem::path _key;
};
}
+
+#endif
diff --git a/src/signer_chain.cc b/src/signer_chain.cc
index f35e4ff6..3b75b06c 100644
--- a/src/signer_chain.cc
+++ b/src/signer_chain.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,17 +17,21 @@
*/
-#include <fstream>
-#include <sstream>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
-#include <openssl/sha.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include "KM_util.h"
+/** @file src/signer_chain.cc
+ * @brief Functions to make signer chains.
+ */
+
#include "signer_chain.h"
#include "exceptions.h"
#include "util.h"
+#include "KM_util.h"
+#include <openssl/sha.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <fstream>
+#include <sstream>
using std::string;
using std::ofstream;
@@ -35,7 +39,11 @@ using std::ifstream;
using std::stringstream;
using std::cout;
-static void command (string cmd)
+/** Run a shell command.
+ * @param cmd Command to run (UTF8-encoded).
+ */
+static void
+command (string cmd)
{
#ifdef LIBDCP_WINDOWS
/* We need to use CreateProcessW on Windows so that the UTF-8/16 mess
@@ -77,16 +85,15 @@ static void command (string cmd)
if (code) {
stringstream s;
s << "error " << code << " in " << cmd << " within " << boost::filesystem::current_path();
- throw libdcp::MiscError (s.str());
+ throw dcp::MiscError (s.str());
}
}
/** Extract a public key from a private key and create a SHA1 digest of it.
- * @param key Private key
+ * @param private_key Private key
* @param openssl openssl binary name (or full path if openssl is not on the system path).
* @return SHA1 digest of corresponding public key, with escaped / characters.
*/
-
static string
public_key_digest (boost::filesystem::path private_key, boost::filesystem::path openssl)
{
@@ -102,7 +109,7 @@ public_key_digest (boost::filesystem::path private_key, boost::filesystem::path
string pub;
ifstream f (public_name.string().c_str ());
if (!f.good ()) {
- throw libdcp::MiscError ("public key not found");
+ throw dcp::MiscError ("public key not found");
}
bool read = false;
@@ -121,22 +128,22 @@ public_key_digest (boost::filesystem::path private_key, boost::filesystem::path
/* Decode the base64 of the public key */
unsigned char buffer[512];
- int const N = libdcp::base64_decode (pub, buffer, 1024);
+ int const N = dcp::base64_decode (pub, buffer, 1024);
/* Hash it with SHA1 (without the first 24 bytes, for reasons that are not entirely clear) */
SHA_CTX context;
if (!SHA1_Init (&context)) {
- throw libdcp::MiscError ("could not init SHA1 context");
+ throw dcp::MiscError ("could not init SHA1 context");
}
if (!SHA1_Update (&context, buffer + 24, N - 24)) {
- throw libdcp::MiscError ("could not update SHA1 digest");
+ throw dcp::MiscError ("could not update SHA1 digest");
}
unsigned char digest[SHA_DIGEST_LENGTH];
if (!SHA1_Final (digest, &context)) {
- throw libdcp::MiscError ("could not finish SHA1 digest");
+ throw dcp::MiscError ("could not finish SHA1 digest");
}
char digest_base64[64];
@@ -149,8 +156,12 @@ public_key_digest (boost::filesystem::path private_key, boost::filesystem::path
return dig;
}
+/** Generate a chain of root, intermediate and leaf keys by running an OpenSSL binary.
+ * @param directory Directory to write the files to.
+ * @param openssl openssl binary path.
+ */
void
-libdcp::make_signer_chain (boost::filesystem::path directory, boost::filesystem::path openssl)
+dcp::make_signer_chain (boost::filesystem::path directory, boost::filesystem::path openssl)
{
boost::filesystem::path const cwd = boost::filesystem::current_path ();
diff --git a/src/signer_chain.h b/src/signer_chain.h
index 50f56ed9..f039caf3 100644
--- a/src/signer_chain.h
+++ b/src/signer_chain.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,9 +17,13 @@
*/
+/** @file src/signer_chain.h
+ * @brief Functions to make signer chains.
+ */
+
#include <boost/filesystem.hpp>
-namespace libdcp {
+namespace dcp {
/** Create a chain of certificates for signing things.
* @param directory Directory to write files to.
diff --git a/src/sound_asset.cc b/src/sound_asset.cc
deleted file mode 100644
index 95244b90..00000000
--- a/src/sound_asset.cc
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/sound_asset.cc
- * @brief An asset made up of WAV files
- */
-
-#include <iostream>
-#include <stdexcept>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/nodes/element.h>
-#include "KM_fileio.h"
-#include "AS_DCP.h"
-#include "sound_asset.h"
-#include "util.h"
-#include "exceptions.h"
-#include "sound_frame.h"
-
-using std::string;
-using std::stringstream;
-using std::ostream;
-using std::vector;
-using std::list;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
-
-SoundAsset::SoundAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : MXFAsset (directory, mxf_name)
- , _channels (0)
- , _sampling_rate (0)
-{
-
-}
-
-void
-SoundAsset::create (vector<boost::filesystem::path> const & files)
-{
- create (boost::bind (&SoundAsset::path_from_channel, this, _1, files));
-}
-
-void
-SoundAsset::read ()
-{
- ASDCP::PCM::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::AudioDescriptor desc;
- if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
-
- _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
- _channels = desc.ChannelCount;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
- _intrinsic_duration = desc.ContainerDuration;
-}
-
-boost::filesystem::path
-SoundAsset::path_from_channel (Channel channel, vector<boost::filesystem::path> const & files)
-{
- unsigned int const c = int (channel);
- assert (c < files.size ());
- return files[c];
-}
-
-void
-SoundAsset::create (boost::function<boost::filesystem::path (Channel)> get_path)
-{
- ASDCP::Rational asdcp_edit_rate (_edit_rate, 1);
-
- assert (_channels > 0);
- ASDCP::PCM::WAVParser* pcm_parser_channel[_channels];
- for (int i = 0; i < _channels; ++i) {
- pcm_parser_channel[i] = new ASDCP::PCM::WAVParser ();
- }
-
- Kumu::Result_t r = pcm_parser_channel[0]->OpenRead (get_path(LEFT).string().c_str(), asdcp_edit_rate);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open WAV file for reading", get_path(LEFT), r));
- }
-
- ASDCP::PCM::AudioDescriptor audio_desc;
- pcm_parser_channel[0]->FillAudioDescriptor (audio_desc);
- audio_desc.ChannelCount = 0;
- audio_desc.BlockAlign = 0;
- audio_desc.EditRate = asdcp_edit_rate;
- audio_desc.AvgBps = audio_desc.AvgBps * _channels;
-
- Channel channels[] = {
- LEFT,
- RIGHT,
- CENTRE,
- LFE,
- LS,
- RS,
- /* XXX: not quite sure what these should be yet */
- CHANNEL_7,
- CHANNEL_8
- };
-
- assert (int(_channels) <= int(sizeof(channels) / sizeof(Channel)));
-
- ASDCP::PCM::FrameBuffer* frame_buffer_channel[_channels];
- ASDCP::PCM::AudioDescriptor* audio_desc_channel[_channels];
- for (int i = 0; i < _channels; ++i) {
- frame_buffer_channel[i] = new ASDCP::PCM::FrameBuffer ();
- audio_desc_channel[i] = new ASDCP::PCM::AudioDescriptor ();
- }
-
- for (int i = 0; i < _channels; ++i) {
-
- boost::filesystem::path const path = get_path (channels[i]);
-
- Kumu::Result_t r = pcm_parser_channel[i]->OpenRead (path.string().c_str(), asdcp_edit_rate);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open WAV file for reading", path, r));
- }
-
- pcm_parser_channel[i]->FillAudioDescriptor (*audio_desc_channel[i]);
- frame_buffer_channel[i]->Capacity (ASDCP::PCM::CalcFrameBufferSize (*audio_desc_channel[i]));
-
- audio_desc.ChannelCount += audio_desc_channel[i]->ChannelCount;
- audio_desc.BlockAlign += audio_desc_channel[i]->BlockAlign;
- }
-
- ASDCP::PCM::FrameBuffer frame_buffer;
- frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
- frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
-
- ASDCP::WriterInfo writer_info;
- MXFAsset::fill_writer_info (&writer_info);
-
- ASDCP::PCM::MXFWriter mxf_writer;
- r = mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open audio MXF for writing", path().string(), r));
- }
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
-
- for (int j = 0; j < _channels; ++j) {
- memset (frame_buffer_channel[j]->Data(), 0, frame_buffer_channel[j]->Capacity());
- if (ASDCP_FAILURE (pcm_parser_channel[j]->ReadFrame (*frame_buffer_channel[j]))) {
- boost::throw_exception (MiscError ("could not read audio frame"));
- }
- }
-
- byte_t *data_s = frame_buffer.Data();
- byte_t *data_e = data_s + frame_buffer.Capacity();
- byte_t sample_size = ASDCP::PCM::CalcSampleSize (*audio_desc_channel[0]);
- int offset = 0;
-
- while (data_s < data_e) {
- for (int j = 0; j < _channels; ++j) {
- byte_t* frame = frame_buffer_channel[j]->Data() + offset;
- memcpy (data_s, frame, sample_size);
- data_s += sample_size;
- }
- offset += sample_size;
- }
-
- if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0))) {
- boost::throw_exception (MiscError ("could not write audio MXF frame"));
- }
-
- if (_progress) {
- (*_progress) (0.5 * float (i) / _intrinsic_duration);
- }
- }
-
- bool const failed = ASDCP_FAILURE (mxf_writer.Finalize());
-
- for (int i = 0; i < _channels; ++i) {
- delete pcm_parser_channel[i];
- delete frame_buffer_channel[i];
- delete audio_desc_channel[i];
- }
-
- if (failed) {
- boost::throw_exception (MiscError ("could not finalise audio MXF"));
- }
-}
-
-string
-SoundAsset::cpl_node_name () const
-{
- return "MainSound";
-}
-
-bool
-SoundAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!MXFAsset::equals (other, opt, note)) {
- return false;
- }
-
- ASDCP::PCM::MXFReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::MXFReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::AudioDescriptor desc_A;
- if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
- ASDCP::PCM::AudioDescriptor desc_B;
- if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
-
- if (
- desc_A.EditRate != desc_B.EditRate ||
- desc_A.AudioSamplingRate != desc_B.AudioSamplingRate ||
- desc_A.Locked != desc_B.Locked ||
- desc_A.ChannelCount != desc_B.ChannelCount ||
- desc_A.QuantizationBits != desc_B.QuantizationBits ||
- desc_A.BlockAlign != desc_B.BlockAlign ||
- desc_A.AvgBps != desc_B.AvgBps ||
- desc_A.LinkedTrackID != desc_B.LinkedTrackID ||
- desc_A.ContainerDuration != desc_B.ContainerDuration
-// desc_A.ChannelFormat != desc_B.ChannelFormat ||
- ) {
-
- note (ERROR, "audio MXF picture descriptors differ");
- return false;
- }
-
- ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte);
- ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- if (ASDCP_FAILURE (reader_A.ReadFrame (i, buffer_A))) {
- boost::throw_exception (DCPReadError ("could not read audio frame"));
- }
-
- if (ASDCP_FAILURE (reader_B.ReadFrame (i, buffer_B))) {
- boost::throw_exception (DCPReadError ("could not read audio frame"));
- }
-
- if (buffer_A.Size() != buffer_B.Size()) {
- note (ERROR, "sizes of audio data for frame " + lexical_cast<string>(i) + " differ");
- return false;
- }
-
- if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) {
- for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
- int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
- if (d > opt.max_audio_sample_error) {
- note (ERROR, "PCM data difference of " + lexical_cast<string> (d));
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-shared_ptr<const SoundFrame>
-SoundAsset::get_frame (int n) const
-{
- /* XXX: should add on entry point here? */
- return shared_ptr<const SoundFrame> (new SoundFrame (path().string(), n, _decryption_context));
-}
-
-shared_ptr<SoundAssetWriter>
-SoundAsset::start_write ()
-{
- /* XXX: can't we use a shared_ptr here? */
- return shared_ptr<SoundAssetWriter> (new SoundAssetWriter (this));
-}
-
-struct SoundAssetWriter::ASDCPState
-{
- ASDCP::PCM::MXFWriter mxf_writer;
- ASDCP::PCM::FrameBuffer frame_buffer;
- ASDCP::WriterInfo writer_info;
- ASDCP::PCM::AudioDescriptor audio_desc;
- ASDCP::AESEncContext* encryption_context;
-};
-
-SoundAssetWriter::SoundAssetWriter (SoundAsset* a)
- : _state (new SoundAssetWriter::ASDCPState)
- , _asset (a)
- , _finalized (false)
- , _frames_written (0)
- , _frame_buffer_offset (0)
-{
- _state->encryption_context = a->encryption_context ();
-
- /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
- _state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
- _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
- _state->audio_desc.Locked = 0;
- _state->audio_desc.ChannelCount = _asset->channels ();
- _state->audio_desc.QuantizationBits = 24;
- _state->audio_desc.BlockAlign = 3 * _asset->channels();
- _state->audio_desc.AvgBps = _asset->sampling_rate() * _state->audio_desc.BlockAlign;
- _state->audio_desc.LinkedTrackID = 0;
- _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE;
-
- _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
- _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
- memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
-
- _asset->fill_writer_info (&_state->writer_info);
-
- Kumu::Result_t r = _state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string(), r));
- }
-}
-
-void
-SoundAssetWriter::write (float const * const * data, int frames)
-{
- for (int i = 0; i < frames; ++i) {
-
- byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
-
- /* Write one sample per channel */
- for (int j = 0; j < _asset->channels(); ++j) {
- int32_t const s = data[j][i] * (1 << 23);
- *out++ = (s & 0xff);
- *out++ = (s & 0xff00) >> 8;
- *out++ = (s & 0xff0000) >> 16;
- }
- _frame_buffer_offset += 3 * _asset->channels();
-
- assert (_frame_buffer_offset <= int (_state->frame_buffer.Capacity()));
-
- /* Finish the MXF frame if required */
- if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
- write_current_frame ();
- _frame_buffer_offset = 0;
- memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
- }
- }
-}
-
-void
-SoundAssetWriter::write_current_frame ()
-{
- ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MiscError ("could not write audio MXF frame (" + lexical_cast<string> (int (r)) + ")"));
- }
-
- ++_frames_written;
-}
-
-void
-SoundAssetWriter::finalize ()
-{
- if (_frame_buffer_offset > 0) {
- write_current_frame ();
- }
-
- if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
- boost::throw_exception (MiscError ("could not finalise audio MXF"));
- }
-
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written);
- _asset->set_duration (_frames_written);
-}
-
-string
-SoundAsset::key_type () const
-{
- return "MDAK";
-}
diff --git a/src/sound_asset.h b/src/sound_asset.h
deleted file mode 100644
index c52a5436..00000000
--- a/src/sound_asset.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LIBDCP_SOUND_ASSET_H
-#define LIBDCP_SOUND_ASSET_H
-
-/** @file src/sound_asset.h
- * @brief An asset made up of PCM audio data files
- */
-
-#include "mxf_asset.h"
-#include "types.h"
-#include "metadata.h"
-
-namespace libdcp
-{
-
-class SoundFrame;
-class SoundAsset;
-
-class SoundAssetWriter
-{
-public:
- void write (float const * const *, int);
- void finalize ();
-
-private:
- friend class SoundAsset;
-
- SoundAssetWriter (SoundAsset *);
-
- /* no copy construction */
- SoundAssetWriter (SoundAssetWriter const &);
- SoundAssetWriter& operator= (SoundAssetWriter const &);
-
- void write_current_frame ();
-
- /* do this with an opaque pointer so we don't have to include
- ASDCP headers
- */
-
- struct ASDCPState;
- boost::shared_ptr<ASDCPState> _state;
-
- SoundAsset* _asset;
- bool _finalized;
- int _frames_written;
- int _frame_buffer_offset;
-};
-
-/** @brief An asset made up of WAV files */
-class SoundAsset : public MXFAsset
-{
-public:
- SoundAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- void read ();
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- * Channels (set_channels)
- * Intrinsic duration (set_intrinsic_duration)
- */
- void create (std::vector<boost::filesystem::path> const & files);
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- * Channels (set_channels)
- * Intrinsic duration (set_intrinsic_duration)
- */
- void create (boost::function<boost::filesystem::path (Channel)> get_path);
-
- boost::shared_ptr<SoundAssetWriter> start_write ();
-
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
- boost::shared_ptr<const SoundFrame> get_frame (int n) const;
-
- void set_channels (int c) {
- _channels = c;
- }
-
- int channels () const {
- return _channels;
- }
-
- void set_sampling_rate (int s) {
- _sampling_rate = s;
- }
-
- int sampling_rate () const {
- return _sampling_rate;
- }
-
-protected:
-
- std::string asdcp_kind () const {
- return "Sound";
- }
-
-private:
- std::string key_type () const;
- void construct (boost::function<boost::filesystem::path (Channel)> get_path);
- boost::filesystem::path path_from_channel (Channel channel, std::vector<boost::filesystem::path> const & files);
- std::string cpl_node_name () const;
-
- /** Number of channels in the asset */
- int _channels;
- int _sampling_rate;
-};
-
-}
-
-#endif
diff --git a/src/sound_frame.cc b/src/sound_frame.cc
index 6bc52c1a..c79b29b3 100644
--- a/src/sound_frame.cc
+++ b/src/sound_frame.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,18 +17,22 @@
*/
-#include "AS_DCP.h"
-#include "KM_fileio.h"
+/** @file src/sound_frame.cc
+ * @brief SoundFrame class.
+ */
+
#include "sound_frame.h"
#include "exceptions.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
using namespace std;
-using namespace libdcp;
+using namespace dcp;
-SoundFrame::SoundFrame (string mxf_path, int n, ASDCP::AESDecContext* c)
+SoundFrame::SoundFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext* c)
{
ASDCP::PCM::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (mxf_path.c_str());
+ Kumu::Result_t r = reader.OpenRead (mxf_path.string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path, r));
}
diff --git a/src/sound_frame.h b/src/sound_frame.h
index 154ff84b..26f738d3 100644
--- a/src/sound_frame.h
+++ b/src/sound_frame.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,11 +17,17 @@
*/
+/** @file src/sound_frame.h
+ * @brief SoundFrame class.
+ */
+
#ifndef LIBDCP_SOUND_FRAME_H
#define LIBDCP_SOUND_FRAME_H
-#include <string>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
#include <stdint.h>
+#include <string>
namespace ASDCP {
namespace PCM {
@@ -30,18 +36,22 @@ namespace ASDCP {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
-class SoundFrame
+/** @class SoundFrame
+ * @brief One &lsquo;frame&rsquo; of sound data from a MXF.
+ */
+class SoundFrame : public boost::noncopyable
{
public:
- SoundFrame (std::string mxf_path, int n, ASDCP::AESDecContext *);
+ SoundFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext *);
~SoundFrame ();
uint8_t const * data () const;
int size () const;
private:
+ /** a buffer to hold the frame */
ASDCP::PCM::FrameBuffer* _buffer;
};
diff --git a/src/sound_mxf.cc b/src/sound_mxf.cc
new file mode 100644
index 00000000..fa48a6c1
--- /dev/null
+++ b/src/sound_mxf.cc
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/sound_mxf.cc
+ * @brief SoundMXF class.
+ */
+
+#include "sound_mxf.h"
+#include "util.h"
+#include "exceptions.h"
+#include "sound_frame.h"
+#include "sound_mxf_writer.h"
+#include "compose.hpp"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include <stdexcept>
+
+using std::string;
+using std::stringstream;
+using std::ostream;
+using std::vector;
+using std::list;
+using boost::shared_ptr;
+using namespace dcp;
+
+SoundMXF::SoundMXF (boost::filesystem::path file)
+ : MXF (file)
+ , _channels (0)
+ , _sampling_rate (0)
+{
+ ASDCP::PCM::MXFReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::PCM::AudioDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
+ _channels = desc.ChannelCount;
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+
+ _intrinsic_duration = desc.ContainerDuration;
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ read_writer_info (info);
+
+}
+
+SoundMXF::SoundMXF (Fraction edit_rate, int sampling_rate, int channels)
+ : MXF (edit_rate)
+ , _channels (channels)
+ , _sampling_rate (sampling_rate)
+{
+
+}
+
+bool
+SoundMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!MXF::equals (other, opt, note)) {
+ return false;
+ }
+
+ ASDCP::PCM::MXFReader reader_A;
+ Kumu::Result_t r = reader_A.OpenRead (file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::PCM::MXFReader reader_B;
+ r = reader_B.OpenRead (other->file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::PCM::AudioDescriptor desc_A;
+ if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+ ASDCP::PCM::AudioDescriptor desc_B;
+ if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ if (
+ desc_A.EditRate != desc_B.EditRate ||
+ desc_A.AudioSamplingRate != desc_B.AudioSamplingRate ||
+ desc_A.Locked != desc_B.Locked ||
+ desc_A.ChannelCount != desc_B.ChannelCount ||
+ desc_A.QuantizationBits != desc_B.QuantizationBits ||
+ desc_A.BlockAlign != desc_B.BlockAlign ||
+ desc_A.AvgBps != desc_B.AvgBps ||
+ desc_A.LinkedTrackID != desc_B.LinkedTrackID ||
+ desc_A.ContainerDuration != desc_B.ContainerDuration
+// desc_A.ChannelFormat != desc_B.ChannelFormat ||
+ ) {
+
+ note (ERROR, "audio MXF picture descriptors differ");
+ return false;
+ }
+
+ ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte);
+ ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ if (ASDCP_FAILURE (reader_A.ReadFrame (i, buffer_A))) {
+ boost::throw_exception (DCPReadError ("could not read audio frame"));
+ }
+
+ if (ASDCP_FAILURE (reader_B.ReadFrame (i, buffer_B))) {
+ boost::throw_exception (DCPReadError ("could not read audio frame"));
+ }
+
+ if (buffer_A.Size() != buffer_B.Size()) {
+ note (ERROR, String::compose ("sizes of audio data for frame %1 differ", i));
+ return false;
+ }
+
+ if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) {
+ for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
+ int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
+ if (d > opt.max_audio_sample_error) {
+ note (ERROR, String::compose ("PCM data difference of %1", d));
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+shared_ptr<const SoundFrame>
+SoundMXF::get_frame (int n) const
+{
+ /* XXX: should add on entry point here? */
+ return shared_ptr<const SoundFrame> (new SoundFrame (file(), n, _decryption_context));
+}
+
+shared_ptr<SoundMXFWriter>
+SoundMXF::start_write (boost::filesystem::path file, Standard standard)
+{
+ /* XXX: can't we use a shared_ptr here? */
+ return shared_ptr<SoundMXFWriter> (new SoundMXFWriter (this, file, standard));
+}
+
+string
+SoundMXF::key_type () const
+{
+ return "MDAK";
+}
diff --git a/src/sound_mxf.h b/src/sound_mxf.h
new file mode 100644
index 00000000..50d10957
--- /dev/null
+++ b/src/sound_mxf.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/sound_mxf.h
+ * @brief SoundMXF class
+ */
+
+#ifndef LIBDCP_SOUND_MXF_H
+#define LIBDCP_SOUND_MXF_H
+
+#include "mxf.h"
+#include "types.h"
+#include "metadata.h"
+
+namespace dcp
+{
+
+class SoundFrame;
+class SoundMXFWriter;
+
+/** @class SoundMXF
+ * @brief Representation of a MXF file containing sound
+ */
+class SoundMXF : public MXF
+{
+public:
+ SoundMXF (boost::filesystem::path file);
+ SoundMXF (Fraction edit_rate, int sampling_rate, int channels);
+
+ boost::shared_ptr<SoundMXFWriter> start_write (boost::filesystem::path file, Standard standard);
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ boost::shared_ptr<const SoundFrame> get_frame (int n) const;
+
+ /** @return number of channels */
+ int channels () const {
+ return _channels;
+ }
+
+ /** @return sampling rate in Hz */
+ int sampling_rate () const {
+ return _sampling_rate;
+ }
+
+private:
+ std::string key_type () const;
+ std::string asdcp_kind () const {
+ return "Sound";
+ }
+
+ int _channels; ///< number of channels
+ int _sampling_rate; ///< sampling rate in Hz
+};
+
+}
+
+#endif
diff --git a/src/sound_mxf_writer.cc b/src/sound_mxf_writer.cc
new file mode 100644
index 00000000..51ba7e40
--- /dev/null
+++ b/src/sound_mxf_writer.cc
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "sound_mxf_writer.h"
+#include "sound_mxf.h"
+#include "exceptions.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+
+using namespace dcp;
+
+struct SoundMXFWriter::ASDCPState
+{
+ ASDCP::PCM::MXFWriter mxf_writer;
+ ASDCP::PCM::FrameBuffer frame_buffer;
+ ASDCP::WriterInfo writer_info;
+ ASDCP::PCM::AudioDescriptor audio_desc;
+ ASDCP::AESEncContext* encryption_context;
+};
+
+SoundMXFWriter::SoundMXFWriter (SoundMXF* m, boost::filesystem::path file, Standard standard)
+ : MXFWriter (m, file)
+ , _state (new SoundMXFWriter::ASDCPState)
+ , _sound_mxf (m)
+ , _frame_buffer_offset (0)
+{
+ _state->encryption_context = m->encryption_context ();
+
+ /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
+ _state->audio_desc.EditRate = ASDCP::Rational (_sound_mxf->edit_rate().numerator, _sound_mxf->edit_rate().denominator);
+ _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_sound_mxf->sampling_rate(), 1);
+ _state->audio_desc.Locked = 0;
+ _state->audio_desc.ChannelCount = _sound_mxf->channels ();
+ _state->audio_desc.QuantizationBits = 24;
+ _state->audio_desc.BlockAlign = 3 * _sound_mxf->channels();
+ _state->audio_desc.AvgBps = _sound_mxf->sampling_rate() * _state->audio_desc.BlockAlign;
+ _state->audio_desc.LinkedTrackID = 0;
+ _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE;
+
+ _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
+ _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
+ memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
+
+ _sound_mxf->fill_writer_info (&_state->writer_info, standard);
+
+ Kumu::Result_t r = _state->mxf_writer.OpenWrite (file.string().c_str(), _state->writer_info, _state->audio_desc);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (FileError ("could not open audio MXF for writing", file.string(), r));
+ }
+}
+
+void
+SoundMXFWriter::write (float const * const * data, int frames)
+{
+ assert (!_finalized);
+
+ for (int i = 0; i < frames; ++i) {
+
+ byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
+
+ /* Write one sample per channel */
+ for (int j = 0; j < _sound_mxf->channels(); ++j) {
+ int32_t const s = data[j][i] * (1 << 23);
+ *out++ = (s & 0xff);
+ *out++ = (s & 0xff00) >> 8;
+ *out++ = (s & 0xff0000) >> 16;
+ }
+ _frame_buffer_offset += 3 * _sound_mxf->channels();
+
+ assert (_frame_buffer_offset <= int (_state->frame_buffer.Capacity()));
+
+ /* Finish the MXF frame if required */
+ if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
+ write_current_frame ();
+ _frame_buffer_offset = 0;
+ memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
+ }
+ }
+}
+
+void
+SoundMXFWriter::write_current_frame ()
+{
+ ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MiscError (String::compose ("could not write audio MXF frame (%1)", int (r))));
+ }
+
+ ++_frames_written;
+}
+
+void
+SoundMXFWriter::finalize ()
+{
+ if (_frame_buffer_offset > 0) {
+ write_current_frame ();
+ }
+
+ if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
+ boost::throw_exception (MiscError ("could not finalise audio MXF"));
+ }
+
+ MXFWriter::finalize ();
+}
diff --git a/src/sound_mxf_writer.h b/src/sound_mxf_writer.h
new file mode 100644
index 00000000..4f60074c
--- /dev/null
+++ b/src/sound_mxf_writer.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "mxf_writer.h"
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class SoundFrame;
+class SoundMXF;
+
+class SoundMXFWriter : public MXFWriter
+{
+public:
+ void write (float const * const *, int);
+ void finalize ();
+
+private:
+ friend class SoundMXF;
+
+ SoundMXFWriter (SoundMXF *, boost::filesystem::path, Standard standard);
+
+ void write_current_frame ();
+
+ /* do this with an opaque pointer so we don't have to include
+ ASDCP headers
+ */
+
+ struct ASDCPState;
+ boost::shared_ptr<ASDCPState> _state;
+
+ SoundMXF* _sound_mxf;
+ int _frame_buffer_offset;
+};
+
+}
+
diff --git a/src/stereo_picture_frame.cc b/src/stereo_picture_frame.cc
index dce1f106..0b56b216 100644
--- a/src/stereo_picture_frame.cc
+++ b/src/stereo_picture_frame.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,21 @@
*/
-#include <openjpeg.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
#include "stereo_picture_frame.h"
#include "exceptions.h"
#include "argb_frame.h"
-#include "lut.h"
#include "util.h"
#include "gamma_lut.h"
#include "rgb_xyz.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include <openjpeg.h>
#define DCI_GAMMA 2.6
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** Make a picture frame from a 3D (stereoscopic) asset.
* @param mxf_path Path to the asset's MXF file.
@@ -59,11 +58,12 @@ StereoPictureFrame::~StereoPictureFrame ()
delete _buffer;
}
-/** @param reduce a factor by which to reduce the resolution
+/** @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
+ * @param reduce a factor by which to reduce the resolution
* of the image, expressed as a power of two (pass 0 for no
* reduction).
- *
- * @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
+ * @param srgb_gamma Reciprocal of gamma to use when doing the
+ * output gamma correction (after conversion from XYZ to RGB).
*
* @return An ARGB representation of one of the eyes (left or right)
* of this frame. This is ARGB in the Cairo sense, so that each
@@ -84,7 +84,7 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const
break;
}
- return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma));
+ return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA, false), GammaLUT::cache.get (12, 1 / srgb_gamma, false));
}
uint8_t const *
diff --git a/src/stereo_picture_frame.h b/src/stereo_picture_frame.h
index ab99ceac..1fd05453 100644
--- a/src/stereo_picture_frame.h
+++ b/src/stereo_picture_frame.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,10 +17,12 @@
*/
-#include <string>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
+#include <stdint.h>
+#include <string>
namespace ASDCP {
namespace JP2K {
@@ -29,12 +31,12 @@ namespace ASDCP {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
/** A single frame of a 3D (stereoscopic) picture asset */
-class StereoPictureFrame
+class StereoPictureFrame : public boost::noncopyable
{
public:
StereoPictureFrame (boost::filesystem::path mxf_path, int n);
diff --git a/src/stereo_picture_asset.cc b/src/stereo_picture_mxf.cc
index 47a41cc2..0188e4e7 100644
--- a/src/stereo_picture_asset.cc
+++ b/src/stereo_picture_mxf.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,35 +18,78 @@
*/
#include "AS_DCP.h"
-#include "stereo_picture_asset.h"
+#include "stereo_picture_mxf.h"
#include "stereo_picture_frame.h"
#include "exceptions.h"
-#include "stereo_picture_asset_writer.h"
+#include "stereo_picture_mxf_writer.h"
using std::string;
using std::pair;
using std::make_pair;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-using namespace libdcp;
+using namespace dcp;
+
+StereoPictureMXF::StereoPictureMXF (boost::filesystem::path file)
+ : PictureMXF (file)
+{
+ ASDCP::JP2K::MXFSReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
+}
+
+StereoPictureMXF::StereoPictureMXF (Fraction edit_rate)
+ : PictureMXF
+ (edit_rate)
+{
+
+}
+
+shared_ptr<const StereoPictureFrame>
+StereoPictureMXF::get_frame (int n) const
+{
+ return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (file().string(), n));
+}
+
+shared_ptr<PictureMXFWriter>
+StereoPictureMXF::start_write (boost::filesystem::path file, Standard standard, bool overwrite)
+{
+ return shared_ptr<StereoPictureMXFWriter> (new StereoPictureMXFWriter (this, file, standard, overwrite));
+}
bool
-StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+StereoPictureMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- if (!MXFAsset::equals (other, opt, note)) {
+ if (!MXF::equals (other, opt, note)) {
return false;
}
ASDCP::JP2K::MXFSReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
+ Kumu::Result_t r = reader_A.OpenRead (file().string().c_str());
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
}
ASDCP::JP2K::MXFSReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
+ r = reader_B.OpenRead (other->file().string().c_str());
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
}
ASDCP::JP2K::PictureDescriptor desc_A;
@@ -62,7 +105,7 @@ StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt,
return false;
}
- shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
+ shared_ptr<const StereoPictureMXF> other_picture = dynamic_pointer_cast<const StereoPictureMXF> (other);
assert (other_picture);
for (int i = 0; i < _intrinsic_duration; ++i) {
@@ -88,63 +131,3 @@ StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt,
return true;
}
-
-StereoPictureAsset::StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-StereoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFSReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
-}
-
-shared_ptr<const StereoPictureFrame>
-StereoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n));
-}
-
-shared_ptr<PictureAssetWriter>
-StereoPictureAsset::start_write (bool overwrite)
-{
- return shared_ptr<StereoPictureAssetWriter> (new StereoPictureAssetWriter (this, overwrite));
-}
-
-string
-StereoPictureAsset::cpl_node_name () const
-{
- return "msp-cpl:MainStereoscopicPicture";
-}
-
-pair<string, string>
-StereoPictureAsset::cpl_node_attribute () const
-{
- if (_interop) {
- return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
- } else {
- return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
- }
-
- return make_pair ("", "");
-}
-
-int
-StereoPictureAsset::edit_rate_factor () const
-{
- return 2;
-}
diff --git a/src/stereo_picture_asset.h b/src/stereo_picture_mxf.h
index 64cdb6b3..dc4605c7 100644
--- a/src/stereo_picture_asset.h
+++ b/src/stereo_picture_mxf.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,31 +17,30 @@
*/
-#ifndef LIBDCP_STEREO_PICTURE_ASSET_H
-#define LIBDCP_STEREO_PICTURE_ASSET_H
+#ifndef LIBDCP_STEREO_PICTURE_MXF_H
+#define LIBDCP_STEREO_PICTURE_MXF_H
-#include "picture_asset.h"
+#include "picture_mxf.h"
-namespace libdcp {
+namespace dcp {
/** A 3D (stereoscopic) picture asset */
-class StereoPictureAsset : public PictureAsset
+class StereoPictureMXF : public PictureMXF
{
public:
- StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
+ StereoPictureMXF (boost::filesystem::path file);
+ StereoPictureMXF (Fraction edit_rate);
- void read ();
-
- /** Start a progressive write to a StereoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
+ /** Start a progressive write to a StereoPictureMXF */
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, Standard, bool);
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
-private:
- std::string cpl_node_name () const;
- std::pair<std::string, std::string> cpl_node_attribute () const;
- int edit_rate_factor () const;
};
}
diff --git a/src/stereo_picture_asset_writer.cc b/src/stereo_picture_mxf_writer.cc
index b4b0ad52..4f98c60e 100644
--- a/src/stereo_picture_asset_writer.cc
+++ b/src/stereo_picture_mxf_writer.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,37 +17,38 @@
*/
+#include "stereo_picture_mxf_writer.h"
+#include "exceptions.h"
+#include "picture_mxf.h"
#include "AS_DCP.h"
#include "KM_fileio.h"
-#include "stereo_picture_asset_writer.h"
-#include "exceptions.h"
-#include "picture_asset.h"
-#include "picture_asset_writer_common.cc"
+#include "picture_mxf_writer_common.cc"
using std::istream;
using std::ostream;
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
-struct StereoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+struct StereoPictureMXFWriter::ASDCPState : public ASDCPStateBase
{
ASDCP::JP2K::MXFSWriter mxf_writer;
};
-StereoPictureAssetWriter::StereoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new StereoPictureAssetWriter::ASDCPState)
+StereoPictureMXFWriter::StereoPictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, Standard standard, bool overwrite)
+ : PictureMXFWriter (mxf, file, standard, overwrite)
+ , _state (new StereoPictureMXFWriter::ASDCPState)
, _next_eye (EYE_LEFT)
{
- _state->encryption_context = asset->encryption_context ();
+ _state->encryption_context = mxf->encryption_context ();
}
void
-StereoPictureAssetWriter::start (uint8_t* data, int size)
+StereoPictureMXFWriter::start (uint8_t* data, int size)
{
- libdcp::start (this, _state, _asset, data, size);
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
+ _picture_mxf->set_frame_rate (Fraction (_picture_mxf->edit_rate().numerator * 2, _picture_mxf->edit_rate().denominator));
}
/** Write a frame for one eye. Frames must be written left, then right, then left etc.
@@ -55,7 +56,7 @@ StereoPictureAssetWriter::start (uint8_t* data, int size)
* @param size Size of data.
*/
FrameInfo
-StereoPictureAssetWriter::write (uint8_t* data, int size)
+StereoPictureMXFWriter::write (uint8_t* data, int size)
{
assert (!_finalized);
@@ -79,41 +80,42 @@ StereoPictureAssetWriter::write (uint8_t* data, int size)
);
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
}
_next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
- ++_frames_written;
+ if (_next_eye == EYE_LEFT) {
+ ++_frames_written;
+ }
+
return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
}
void
-StereoPictureAssetWriter::fake_write (int size)
+StereoPictureMXFWriter::fake_write (int size)
{
assert (_started);
assert (!_finalized);
Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size, _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT);
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
}
_next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
- ++_frames_written;
+ if (_next_eye == EYE_LEFT) {
+ ++_frames_written;
+ }
}
void
-StereoPictureAssetWriter::finalize ()
+StereoPictureMXFWriter::finalize ()
{
- assert (!_finalized);
-
Kumu::Result_t r = _state->mxf_writer.Finalize();
if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
+ boost::throw_exception (MXFFileError ("error in finalizing video MXF", _mxf->file().string(), r));
}
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written / 2);
- _asset->set_duration (_frames_written / 2);
+ PictureMXFWriter::finalize ();
}
diff --git a/src/stereo_picture_asset_writer.h b/src/stereo_picture_mxf_writer.h
index 771524c4..ebd9dbec 100644
--- a/src/stereo_picture_asset_writer.h
+++ b/src/stereo_picture_mxf_writer.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,14 +17,15 @@
*/
+#include "picture_mxf_writer.h"
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
#include <stdint.h>
#include <string>
#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "picture_asset_writer.h"
-namespace libdcp {
+namespace dcp {
/** A helper class for writing to StereoPictureAssets progressively (i.e. writing frame-by-frame,
* rather than giving libdcp all the frames in one go).
@@ -36,7 +37,7 @@ namespace libdcp {
* The action of finalize() can't be done in MonoPictureAssetWriter's destructor as it may
* throw an exception.
*/
-class StereoPictureAssetWriter : public PictureAssetWriter
+class StereoPictureMXFWriter : public PictureMXFWriter
{
public:
FrameInfo write (uint8_t *, int);
@@ -44,9 +45,9 @@ public:
void finalize ();
private:
- friend class StereoPictureAsset;
+ friend class StereoPictureMXF;
- StereoPictureAssetWriter (PictureAsset *, bool);
+ StereoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, Standard, bool);
void start (uint8_t *, int);
/* do this with an opaque pointer so we don't have to include
@@ -56,7 +57,7 @@ private:
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
- libdcp::Eye _next_eye;
+ dcp::Eye _next_eye;
};
}
diff --git a/src/subtitle.cc b/src/subtitle.cc
new file mode 100644
index 00000000..8c40254a
--- /dev/null
+++ b/src/subtitle.cc
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "subtitle.h"
+#include "xml.h"
+#include "font.h"
+#include "text.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using namespace dcp;
+
+Subtitle::Subtitle (boost::shared_ptr<const cxml::Node> node)
+{
+ in = Time (node->string_attribute ("TimeIn"));
+ out = Time (node->string_attribute ("TimeOut"));
+ font_nodes = type_children<Font> (node, "Font");
+ text_nodes = type_children<Text> (node, "Text");
+ fade_up_time = fade_time (node, "FadeUpTime");
+ fade_down_time = fade_time (node, "FadeDownTime");
+}
+
+Time
+Subtitle::fade_time (shared_ptr<const cxml::Node> node, string name)
+{
+ string const u = node->optional_string_attribute (name).get_value_or ("");
+ Time t;
+
+ if (u.empty ()) {
+ t = Time (0, 0, 0, 20);
+ } else if (u.find (":") != string::npos) {
+ t = Time (u);
+ } else {
+ t = Time (0, 0, 0, lexical_cast<int> (u));
+ }
+
+ if (t > Time (0, 0, 8, 0)) {
+ t = Time (0, 0, 8, 0);
+ }
+
+ return t;
+}
diff --git a/src/lut.h b/src/subtitle.h
index ad291467..073bfb0c 100644
--- a/src/lut.h
+++ b/src/subtitle.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,45 +17,37 @@
*/
-#ifndef LIBDCP_LUT_H
-#define LIBDCP_LUT_H
+#ifndef LIBDCP_SUBTITLE_H
+#define LIBDCP_SUBTITLE_H
-#include <cmath>
-#include <boost/utility.hpp>
+#include "dcp_time.h"
+#include <boost/shared_ptr.hpp>
+#include <list>
-namespace libdcp {
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font;
+class Text;
-class LUT : boost::noncopyable
+class Subtitle
{
public:
- LUT(int bit_depth, float gamma)
- : _lut(0)
- , _bit_depth (bit_depth)
- , _gamma (gamma)
- {
- _lut = new float[int(std::pow(2.0f, _bit_depth))];
- }
-
- virtual ~LUT() {
- delete[] _lut;
- }
-
- float const * lut() const {
- return _lut;
- }
-
- int bit_depth () const {
- return _bit_depth;
- }
-
- float gamma () const {
- return _gamma;
- }
-
-protected:
- float* _lut;
- int _bit_depth;
- float _gamma;
+ Subtitle () {}
+ Subtitle (boost::shared_ptr<const cxml::Node> node);
+
+ Time in;
+ Time out;
+ Time fade_up_time;
+ Time fade_down_time;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+
+private:
+ Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name);
};
}
diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h
deleted file mode 100644
index a7ec641c..00000000
--- a/src/subtitle_asset.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LIBDCP_SUBTITLE_ASSET_H
-#define LIBDCP_SUBTITLE_ASSET_H
-
-#include <libcxml/cxml.h>
-#include "asset.h"
-#include "dcp_time.h"
-
-namespace libdcp
-{
-
-namespace parse
-{
- class Font;
- class Text;
- class Subtitle;
- class LoadFont;
-}
-
-class Subtitle
-{
-public:
- Subtitle (
- std::string font,
- bool italic,
- Color color,
- int size,
- Time in,
- Time out,
- float v_position,
- VAlign v_align,
- std::string text,
- Effect effect,
- Color effect_color,
- Time fade_up_time,
- Time fade_down_time
- );
-
- std::string font () const {
- return _font;
- }
-
- bool italic () const {
- return _italic;
- }
-
- Color color () const {
- return _color;
- }
-
- Time in () const {
- return _in;
- }
-
- Time out () const {
- return _out;
- }
-
- std::string text () const {
- return _text;
- }
-
- float v_position () const {
- return _v_position;
- }
-
- VAlign v_align () const {
- return _v_align;
- }
-
- Effect effect () const {
- return _effect;
- }
-
- Color effect_color () const {
- return _effect_color;
- }
-
- Time fade_up_time () const {
- return _fade_up_time;
- }
-
- Time fade_down_time () const {
- return _fade_down_time;
- }
-
- int size () const {
- return _size;
- }
-
- int size_in_pixels (int screen_height) const;
-
-private:
- std::string _font;
- bool _italic;
- Color _color;
- /** Size in points as if the screen height is 11 inches, so a 72pt font
- * would be 1/11th of the screen height.
- */
- int _size;
- Time _in;
- Time _out;
- /** Vertical position as a proportion of the screen height from the top
- * (between 0 and 1)
- */
- float _v_position;
- VAlign _v_align;
- std::string _text;
- Effect _effect;
- Color _effect_color;
- Time _fade_up_time;
- Time _fade_down_time;
-};
-
-bool operator== (Subtitle const & a, Subtitle const & b);
-std::ostream& operator<< (std::ostream& s, Subtitle const & sub);
-
-class SubtitleAsset : public Asset
-{
-public:
- SubtitleAsset (std::string directory, std::string xml_file);
- SubtitleAsset (std::string directory, std::string movie_title, std::string language);
-
- void write_to_cpl (xmlpp::Element *) const;
- virtual bool equals (boost::shared_ptr<const Asset>, EqualityOptions, boost::function<void (NoteType, std::string)> note) const {
- /* XXX */
- note (ERROR, "subtitle assets not compared yet");
- return true;
- }
-
- std::string language () const {
- return _language;
- }
-
- std::list<boost::shared_ptr<Subtitle> > subtitles_at (Time t) const;
- std::list<boost::shared_ptr<Subtitle> > const & subtitles () const {
- return _subtitles;
- }
-
- void add (boost::shared_ptr<Subtitle>);
-
- void read_xml (std::string);
- void write_xml () const;
- Glib::ustring xml_as_string () const;
-
-protected:
-
- std::string asdcp_kind () const {
- return "Subtitle";
- }
-
-private:
- std::string font_id_to_name (std::string id) const;
- void read_mxf (std::string);
- void read_xml (boost::shared_ptr<cxml::Document>);
-
- struct ParseState {
- std::list<boost::shared_ptr<parse::Font> > font_nodes;
- std::list<boost::shared_ptr<parse::Text> > text_nodes;
- std::list<boost::shared_ptr<parse::Subtitle> > subtitle_nodes;
- };
-
- void maybe_add_subtitle (std::string text, ParseState const & parse_state);
-
- void examine_font_nodes (
- boost::shared_ptr<const cxml::Node> xml,
- std::list<boost::shared_ptr<parse::Font> > const & font_nodes,
- ParseState& parse_state
- );
-
- void examine_text_nodes (
- boost::shared_ptr<const cxml::Node> xml,
- std::list<boost::shared_ptr<parse::Text> > const & text_nodes,
- ParseState& parse_state
- );
-
- boost::optional<std::string> _movie_title;
- /* strangely, this is sometimes a string */
- std::string _reel_number;
- std::string _language;
- std::list<boost::shared_ptr<parse::LoadFont> > _load_font_nodes;
-
- std::list<boost::shared_ptr<Subtitle> > _subtitles;
- bool _need_sort;
-};
-
-}
-
-#endif
diff --git a/src/subtitle_asset.cc b/src/subtitle_content.cc
index 4eb1a9cd..f338517e 100644
--- a/src/subtitle_asset.cc
+++ b/src/subtitle_content.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,17 +17,17 @@
*/
-#include <fstream>
-#include <cerrno>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
-#include "subtitle_asset.h"
-#include "parse/subtitle.h"
+#include "subtitle_content.h"
#include "util.h"
#include "xml.h"
+#include "font.h"
+#include "text.h"
+#include "load_font.h"
+#include "subtitle_string.h"
+#include <libxml++/nodes/element.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <fstream>
using std::string;
using std::list;
@@ -38,117 +38,56 @@ using std::cout;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::optional;
-using namespace libdcp;
+using namespace dcp;
-SubtitleAsset::SubtitleAsset (string directory, string file)
- : Asset (directory, file)
- , _need_sort (false)
-{
- /* Grotesque hack: we should look in the PKL to see what type this file is;
- instead we'll look at the first character to decide what to do.
- I think this is easily fixable (properly) in 1.0.
- */
-
- FILE* f = fopen_boost (path(), "r");
- if (!f) {
- throw FileError ("Could not open file for reading", file, errno);
- }
- unsigned char test[1];
- fread (test, 1, 1, f);
- fclose (f);
-
- if (test[0] == '<' || test[0] == 0xef) {
- read_xml (path().string());
- } else {
- read_mxf (path().string());
- }
-}
-
-SubtitleAsset::SubtitleAsset (string directory, string movie_title, string language)
- : Asset (directory)
- , _movie_title (movie_title)
- , _reel_number ("1")
- , _language (language)
+SubtitleContent::SubtitleContent (boost::filesystem::path file)
+ : Content (file)
, _need_sort (false)
{
-
-}
-
-void
-SubtitleAsset::read_mxf (string mxf_file)
-{
- ASDCP::TimedText::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (mxf_file.c_str ());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", mxf_file, r));
- }
-
- string s;
- reader.ReadTimedTextResource (s, 0, 0);
- shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
- stringstream t;
- t << s;
- xml->read_stream (t);
- read_xml (xml);
-}
-
-void
-SubtitleAsset::read_xml (string xml_file)
-{
shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
- xml->read_file (xml_file);
- read_xml (xml);
-}
-
-void
-SubtitleAsset::read_xml (shared_ptr<cxml::Document> xml)
-{
- /* XXX: hacks aplenty in here; need separate parsers for DCSubtitle and SubtitleReel */
+ xml->read_file (file);
- /* DCSubtitle */
- optional<string> x = xml->optional_string_child ("SubtitleID");
- if (!x) {
- /* SubtitleReel */
- x = xml->optional_string_child ("Id");
- }
- _uuid = x.get_value_or ("");
-
- _movie_title = xml->optional_string_child ("MovieTitle");
+ _id = xml->string_child ("SubtitleID");
+ _movie_title = xml->string_child ("MovieTitle");
_reel_number = xml->string_child ("ReelNumber");
_language = xml->string_child ("Language");
xml->ignore_child ("LoadFont");
- list<shared_ptr<libdcp::parse::Font> > font_nodes = type_children<libdcp::parse::Font> (xml, "Font");
- _load_font_nodes = type_children<libdcp::parse::LoadFont> (xml, "LoadFont");
+ list<shared_ptr<dcp::Font> > font_nodes = type_children<dcp::Font> (xml, "Font");
+ _load_font_nodes = type_children<dcp::LoadFont> (xml, "LoadFont");
/* Now make Subtitle objects to represent the raw XML nodes
in a sane way.
*/
-
- shared_ptr<cxml::Node> subtitle_list = xml->optional_node_child ("SubtitleList");
- if (subtitle_list) {
- list<shared_ptr<libdcp::parse::Font> > font = type_children<libdcp::parse::Font> (subtitle_list, "Font");
- copy (font.begin(), font.end(), back_inserter (font_nodes));
- }
ParseState parse_state;
examine_font_nodes (xml, font_nodes, parse_state);
}
+SubtitleContent::SubtitleContent (Fraction edit_rate, string movie_title, string language)
+ : Content (edit_rate)
+ , _movie_title (movie_title)
+ , _reel_number ("1")
+ , _language (language)
+ , _need_sort (false)
+{
+
+}
+
void
-SubtitleAsset::examine_font_nodes (
+SubtitleContent::examine_font_nodes (
shared_ptr<const cxml::Node> xml,
- list<shared_ptr<libdcp::parse::Font> > const & font_nodes,
+ list<shared_ptr<dcp::Font> > const & font_nodes,
ParseState& parse_state
)
{
- for (list<shared_ptr<libdcp::parse::Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
+ for (list<shared_ptr<dcp::Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
parse_state.font_nodes.push_back (*i);
maybe_add_subtitle ((*i)->text, parse_state);
- for (list<shared_ptr<libdcp::parse::Subtitle> >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) {
+ for (list<shared_ptr<dcp::Subtitle> >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) {
parse_state.subtitle_nodes.push_back (*j);
examine_text_nodes (xml, (*j)->text_nodes, parse_state);
examine_font_nodes (xml, (*j)->font_nodes, parse_state);
@@ -163,13 +102,13 @@ SubtitleAsset::examine_font_nodes (
}
void
-SubtitleAsset::examine_text_nodes (
+SubtitleContent::examine_text_nodes (
shared_ptr<const cxml::Node> xml,
- list<shared_ptr<libdcp::parse::Text> > const & text_nodes,
+ list<shared_ptr<dcp::Text> > const & text_nodes,
ParseState& parse_state
)
{
- for (list<shared_ptr<libdcp::parse::Text> >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) {
+ for (list<shared_ptr<dcp::Text> >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) {
parse_state.text_nodes.push_back (*i);
maybe_add_subtitle ((*i)->text, parse_state);
examine_font_nodes (xml, (*i)->font_nodes, parse_state);
@@ -178,7 +117,7 @@ SubtitleAsset::examine_text_nodes (
}
void
-SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state)
+SubtitleContent::maybe_add_subtitle (string text, ParseState const & parse_state)
{
if (empty_or_white_space (text)) {
return;
@@ -191,13 +130,13 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state)
assert (!parse_state.text_nodes.empty ());
assert (!parse_state.subtitle_nodes.empty ());
- libdcp::parse::Font effective_font (parse_state.font_nodes);
- libdcp::parse::Text effective_text (*parse_state.text_nodes.back ());
- libdcp::parse::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
+ dcp::Font effective_font (parse_state.font_nodes);
+ dcp::Text effective_text (*parse_state.text_nodes.back ());
+ dcp::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
_subtitles.push_back (
- shared_ptr<Subtitle> (
- new Subtitle (
+ shared_ptr<SubtitleString> (
+ new SubtitleString (
font_id_to_name (effective_font.id),
effective_font.italic.get(),
effective_font.color.get(),
@@ -216,11 +155,11 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state)
);
}
-list<shared_ptr<Subtitle> >
-SubtitleAsset::subtitles_at (Time t) const
+list<shared_ptr<SubtitleString> >
+SubtitleContent::subtitles_at (Time t) const
{
- list<shared_ptr<Subtitle> > s;
- for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+ list<shared_ptr<SubtitleString> > s;
+ for (list<shared_ptr<SubtitleString> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
if ((*i)->in() <= t && t <= (*i)->out ()) {
s.push_back (*i);
}
@@ -230,9 +169,9 @@ SubtitleAsset::subtitles_at (Time t) const
}
std::string
-SubtitleAsset::font_id_to_name (string id) const
+SubtitleContent::font_id_to_name (string id) const
{
- list<shared_ptr<libdcp::parse::LoadFont> >::const_iterator i = _load_font_nodes.begin();
+ list<shared_ptr<dcp::LoadFont> >::const_iterator i = _load_font_nodes.begin();
while (i != _load_font_nodes.end() && (*i)->id != id) {
++i;
}
@@ -241,116 +180,22 @@ SubtitleAsset::font_id_to_name (string id) const
return "";
}
- if ((*i)->uri && (*i)->uri.get() == "arial.ttf") {
+ if ((*i)->uri == "arial.ttf") {
return "Arial";
}
return "";
}
-Subtitle::Subtitle (
- string font,
- bool italic,
- Color color,
- int size,
- Time in,
- Time out,
- float v_position,
- VAlign v_align,
- string text,
- Effect effect,
- Color effect_color,
- Time fade_up_time,
- Time fade_down_time
- )
- : _font (font)
- , _italic (italic)
- , _color (color)
- , _size (size)
- , _in (in)
- , _out (out)
- , _v_position (v_position)
- , _v_align (v_align)
- , _text (text)
- , _effect (effect)
- , _effect_color (effect_color)
- , _fade_up_time (fade_up_time)
- , _fade_down_time (fade_down_time)
-{
-
-}
-
-int
-Subtitle::size_in_pixels (int screen_height) const
-{
- /* Size in the subtitle file is given in points as if the screen
- height is 11 inches, so a 72pt font would be 1/11th of the screen
- height.
- */
-
- return _size * screen_height / (11 * 72);
-}
-
-bool
-libdcp::operator== (Subtitle const & a, Subtitle const & b)
-{
- return (
- a.font() == b.font() &&
- a.italic() == b.italic() &&
- a.color() == b.color() &&
- a.size() == b.size() &&
- a.in() == b.in() &&
- a.out() == b.out() &&
- a.v_position() == b.v_position() &&
- a.v_align() == b.v_align() &&
- a.text() == b.text() &&
- a.effect() == b.effect() &&
- a.effect_color() == b.effect_color() &&
- a.fade_up_time() == b.fade_up_time() &&
- a.fade_down_time() == b.fade_down_time()
- );
-}
-
-ostream&
-libdcp::operator<< (ostream& s, Subtitle const & sub)
-{
- s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
- << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
- << "font " << sub.font() << ", ";
-
- if (sub.italic()) {
- s << "italic";
- } else {
- s << "non-italic";
- }
-
- s << ", size " << sub.size() << ", color " << sub.color() << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ";\n"
- << "effect " << ((int) sub.effect()) << ", effect color " << sub.effect_color();
-
- return s;
-}
-
void
-SubtitleAsset::add (shared_ptr<Subtitle> s)
+SubtitleContent::add (shared_ptr<SubtitleString> s)
{
_subtitles.push_back (s);
_need_sort = true;
}
-void
-SubtitleAsset::write_to_cpl (xmlpp::Element* node) const
-{
- /* XXX: should EditRate, Duration and IntrinsicDuration be in here? */
-
- xmlpp::Node* ms = node->add_child ("MainSubtitle");
- ms->add_child("Id")->add_child_text("urn:uuid:" + _uuid);
- ms->add_child("AnnotationText")->add_child_text (_file_name.string ());
- /* XXX */
- ms->add_child("EntryPoint")->add_child_text ("0");
-}
-
struct SubtitleSorter {
- bool operator() (shared_ptr<Subtitle> a, shared_ptr<Subtitle> b) {
+ bool operator() (shared_ptr<SubtitleString> a, shared_ptr<SubtitleString> b) {
if (a->in() != b->in()) {
return a->in() < b->in();
}
@@ -359,25 +204,23 @@ struct SubtitleSorter {
};
void
-SubtitleAsset::write_xml () const
+SubtitleContent::write_xml () const
{
- FILE* f = fopen_boost (path (), "r");
+ FILE* f = fopen_boost (file (), "r");
Glib::ustring const s = xml_as_string ();
fwrite (s.c_str(), 1, s.length(), f);
fclose (f);
}
Glib::ustring
-SubtitleAsset::xml_as_string () const
+SubtitleContent::xml_as_string () const
{
xmlpp::Document doc;
xmlpp::Element* root = doc.create_root_node ("DCSubtitle");
root->set_attribute ("Version", "1.0");
- root->add_child("SubtitleID")->add_child_text (_uuid);
- if (_movie_title) {
- root->add_child("MovieTitle")->add_child_text (_movie_title.get ());
- }
+ root->add_child("SubtitleID")->add_child_text (_id);
+ root->add_child("MovieTitle")->add_child_text (_movie_title);
root->add_child("ReelNumber")->add_child_text (lexical_cast<string> (_reel_number));
root->add_child("Language")->add_child_text (_language);
@@ -388,12 +231,10 @@ SubtitleAsset::xml_as_string () const
if (!_load_font_nodes.empty ()) {
xmlpp::Element* load_font = root->add_child("LoadFont");
load_font->set_attribute("Id", _load_font_nodes.front()->id);
- if (_load_font_nodes.front()->uri) {
- load_font->set_attribute("URI", _load_font_nodes.front()->uri.get ());
- }
+ load_font->set_attribute("URI", _load_font_nodes.front()->uri);
}
- list<shared_ptr<Subtitle> > sorted = _subtitles;
+ list<shared_ptr<SubtitleString> > sorted = _subtitles;
if (_need_sort) {
sorted.sort (SubtitleSorter ());
}
@@ -415,7 +256,7 @@ SubtitleAsset::xml_as_string () const
xmlpp::Element* font = 0;
xmlpp::Element* subtitle = 0;
- for (list<shared_ptr<Subtitle> >::iterator i = sorted.begin(); i != sorted.end(); ++i) {
+ for (list<shared_ptr<SubtitleString> >::iterator i = sorted.begin(); i != sorted.end(); ++i) {
/* We will start a new <Font>...</Font> whenever some font property changes.
I suppose we should really make an optimal hierarchy of <Font> tags, but
diff --git a/src/subtitle_content.h b/src/subtitle_content.h
new file mode 100644
index 00000000..410c5934
--- /dev/null
+++ b/src/subtitle_content.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_SUBTITLE_CONTENT_H
+#define LIBDCP_SUBTITLE_CONTENT_H
+
+#include "content.h"
+#include "dcp_time.h"
+#include <libcxml/cxml.h>
+
+namespace dcp
+{
+
+class SubtitleString;
+class Font;
+class Text;
+class Subtitle;
+class LoadFont;
+
+/** @class SubtitleContent
+ * @brief A representation of an XML file containing subtitles.
+ */
+class SubtitleContent : public Content
+{
+public:
+ SubtitleContent (boost::filesystem::path file);
+ SubtitleContent (Fraction edit_rate, std::string movie_title, std::string language);
+
+ bool equals (
+ boost::shared_ptr<const Content>,
+ EqualityOptions,
+ boost::function<void (NoteType, std::string)> note
+ ) const {
+ /* XXX */
+ note (ERROR, "subtitle content not compared yet");
+ return true;
+ }
+
+ std::string language () const {
+ return _language;
+ }
+
+ std::list<boost::shared_ptr<SubtitleString> > subtitles_at (Time t) const;
+ std::list<boost::shared_ptr<SubtitleString> > const & subtitles () const {
+ return _subtitles;
+ }
+
+ void add (boost::shared_ptr<SubtitleString>);
+
+ void write_xml () const;
+ Glib::ustring xml_as_string () const;
+
+protected:
+ std::string pkl_type (Standard) const {
+ return "text/xml";
+ }
+
+ std::string asdcp_kind () const {
+ return "Subtitle";
+ }
+
+private:
+ std::string font_id_to_name (std::string id) const;
+
+ struct ParseState {
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+ std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
+ };
+
+ void maybe_add_subtitle (std::string text, ParseState const & parse_state);
+
+ void examine_font_nodes (
+ boost::shared_ptr<const cxml::Node> xml,
+ std::list<boost::shared_ptr<Font> > const & font_nodes,
+ ParseState& parse_state
+ );
+
+ void examine_text_nodes (
+ boost::shared_ptr<const cxml::Node> xml,
+ std::list<boost::shared_ptr<Text> > const & text_nodes,
+ ParseState& parse_state
+ );
+
+ std::string _movie_title;
+ /* strangely, this is sometimes a string */
+ std::string _reel_number;
+ std::string _language;
+ std::list<boost::shared_ptr<LoadFont> > _load_font_nodes;
+
+ std::list<boost::shared_ptr<SubtitleString> > _subtitles;
+ bool _need_sort;
+};
+
+}
+
+#endif
diff --git a/src/subtitle_string.cc b/src/subtitle_string.cc
new file mode 100644
index 00000000..66869fd5
--- /dev/null
+++ b/src/subtitle_string.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "subtitle_string.h"
+#include "xml.h"
+
+using std::string;
+using std::ostream;
+using namespace dcp;
+
+SubtitleString::SubtitleString (
+ string font,
+ bool italic,
+ Color color,
+ int size,
+ Time in,
+ Time out,
+ float v_position,
+ VAlign v_align,
+ string text,
+ Effect effect,
+ Color effect_color,
+ Time fade_up_time,
+ Time fade_down_time
+ )
+ : _font (font)
+ , _italic (italic)
+ , _color (color)
+ , _size (size)
+ , _in (in)
+ , _out (out)
+ , _v_position (v_position)
+ , _v_align (v_align)
+ , _text (text)
+ , _effect (effect)
+ , _effect_color (effect_color)
+ , _fade_up_time (fade_up_time)
+ , _fade_down_time (fade_down_time)
+{
+
+}
+
+int
+SubtitleString::size_in_pixels (int screen_height) const
+{
+ /* Size in the subtitle file is given in points as if the screen
+ height is 11 inches, so a 72pt font would be 1/11th of the screen
+ height.
+ */
+
+ return _size * screen_height / (11 * 72);
+}
+
+bool
+dcp::operator== (SubtitleString const & a, SubtitleString const & b)
+{
+ return (
+ a.font() == b.font() &&
+ a.italic() == b.italic() &&
+ a.color() == b.color() &&
+ a.size() == b.size() &&
+ a.in() == b.in() &&
+ a.out() == b.out() &&
+ a.v_position() == b.v_position() &&
+ a.v_align() == b.v_align() &&
+ a.text() == b.text() &&
+ a.effect() == b.effect() &&
+ a.effect_color() == b.effect_color() &&
+ a.fade_up_time() == b.fade_up_time() &&
+ a.fade_down_time() == b.fade_down_time()
+ );
+}
+
+ostream&
+dcp::operator<< (ostream& s, SubtitleString const & sub)
+{
+ s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
+ << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
+ << "font " << sub.font() << ", ";
+
+ if (sub.italic()) {
+ s << "italic";
+ } else {
+ s << "non-italic";
+ }
+
+ s << ", size " << sub.size() << ", color " << sub.color() << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ";\n"
+ << "effect " << ((int) sub.effect()) << ", effect color " << sub.effect_color();
+
+ return s;
+}
diff --git a/src/subtitle_string.h b/src/subtitle_string.h
new file mode 100644
index 00000000..076a6ec7
--- /dev/null
+++ b/src/subtitle_string.h
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_SUBTITLE_STRING_H
+#define LIBDCP_SUBTITLE_STRING_H
+
+#include "types.h"
+#include "dcp_time.h"
+#include <string>
+
+namespace dcp {
+
+class SubtitleString
+{
+public:
+ SubtitleString (
+ std::string font,
+ bool italic,
+ Color color,
+ int size,
+ Time in,
+ Time out,
+ float v_position,
+ VAlign v_align,
+ std::string text,
+ Effect effect,
+ Color effect_color,
+ Time fade_up_time,
+ Time fade_down_time
+ );
+
+ std::string font () const {
+ return _font;
+ }
+
+ bool italic () const {
+ return _italic;
+ }
+
+ Color color () const {
+ return _color;
+ }
+
+ Time in () const {
+ return _in;
+ }
+
+ Time out () const {
+ return _out;
+ }
+
+ std::string text () const {
+ return _text;
+ }
+
+ float v_position () const {
+ return _v_position;
+ }
+
+ VAlign v_align () const {
+ return _v_align;
+ }
+
+ Effect effect () const {
+ return _effect;
+ }
+
+ Color effect_color () const {
+ return _effect_color;
+ }
+
+ Time fade_up_time () const {
+ return _fade_up_time;
+ }
+
+ Time fade_down_time () const {
+ return _fade_down_time;
+ }
+
+ int size () const {
+ return _size;
+ }
+
+ int size_in_pixels (int screen_height) const;
+
+private:
+ std::string _font;
+ bool _italic;
+ Color _color;
+ /** Size in points as if the screen height is 11 inches, so a 72pt font
+ * would be 1/11th of the screen height.
+ */
+ int _size;
+ Time _in;
+ Time _out;
+ /** Vertical position as a proportion of the screen height from the top
+ * (between 0 and 1)
+ */
+ float _v_position;
+ VAlign _v_align;
+ std::string _text;
+ Effect _effect;
+ Color _effect_color;
+ Time _fade_up_time;
+ Time _fade_down_time;
+};
+
+bool operator== (SubtitleString const & a, SubtitleString const & b);
+std::ostream& operator<< (std::ostream& s, SubtitleString const & sub);
+
+}
+
+#endif
diff --git a/src/text.cc b/src/text.cc
new file mode 100644
index 00000000..888cab29
--- /dev/null
+++ b/src/text.cc
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/text.cc
+ * @brief Text class for parsing subtitle XML.
+ */
+
+#include "text.h"
+#include "xml.h"
+#include "font.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using boost::optional;
+using namespace dcp;
+
+/** Read a &lt;Text&gt; node from a subtitle XML file, noting its contents
+ * in this object's member variables.
+ * @param node Node to read.
+ */
+Text::Text (boost::shared_ptr<const cxml::Node> node)
+ : v_align (CENTER)
+{
+ text = node->content ();
+ v_position = node->number_attribute<float> ("VPosition");
+ optional<string> v = node->optional_string_attribute ("VAlign");
+ if (v) {
+ v_align = string_to_valign (v.get ());
+ }
+
+ font_nodes = type_children<Font> (node, "Font");
+}
diff --git a/src/parse/pkl.h b/src/text.h
index 13d87fa1..268d146c 100644
--- a/src/parse/pkl.h
+++ b/src/text.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,44 +17,40 @@
*/
-/** @file src/parse/pkl.h
- * @brief Classes used to parse a PKL
+/** @file src/text.h
+ * @brief Text class for parsing subtitle XML.
*/
+#include "types.h"
#include <boost/shared_ptr.hpp>
-#include "../xml.h"
+#include <list>
-namespace libdcp {
+namespace cxml {
+ class Node;
+}
-namespace parse {
+namespace dcp {
-class PKLAsset
-{
-public:
- PKLAsset () {}
- PKLAsset (boost::shared_ptr<const cxml::Node>);
-
- std::string id;
- std::string annotation_text;
- std::string hash;
- int64_t size;
- std::string type;
- std::string original_file_name;
-};
+class Font;
-class PKL
+/** @class Text
+ * @brief Parser for Text nodes from subtitle XML.
+ */
+class Text
{
public:
- PKL (std::string file);
-
- std::string id;
- std::string annotation_text;
- std::string issue_date;
- std::string issuer;
- std::string creator;
- std::list<boost::shared_ptr<PKLAsset> > assets;
-};
+ /** Construct a default text node */
+ Text ()
+ : v_position (0)
+ , v_align (TOP)
+ {}
-}
+ Text (boost::shared_ptr<const cxml::Node> node);
+
+ float v_position;
+ VAlign v_align;
+ std::string text;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+};
}
diff --git a/src/types.cc b/src/types.cc
index 693b9ab2..0ecf7a16 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -1,15 +1,37 @@
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "types.h"
+#include "exceptions.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
#include <vector>
#include <cstdio>
#include <iomanip>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include "types.h"
-#include "exceptions.h"
using namespace std;
-using namespace libdcp;
+using namespace dcp;
using namespace boost;
+/** Construct a Fraction from a string of the form <numerator> <denominator>
+ * e.g. "1 3".
+ */
Fraction::Fraction (string s)
{
vector<string> b;
@@ -22,17 +44,18 @@ Fraction::Fraction (string s)
}
bool
-libdcp::operator== (Fraction const & a, Fraction const & b)
+dcp::operator== (Fraction const & a, Fraction const & b)
{
return (a.numerator == b.numerator && a.denominator == b.denominator);
}
bool
-libdcp::operator!= (Fraction const & a, Fraction const & b)
+dcp::operator!= (Fraction const & a, Fraction const & b)
{
return (a.numerator != b.numerator || a.denominator != b.denominator);
}
+/** Construct a Color, initialising it to black. */
Color::Color ()
: r (0)
, g (0)
@@ -41,6 +64,9 @@ Color::Color ()
}
+/** Construct a Color from R, G and B. The values run between
+ * 0 and 255.
+ */
Color::Color (int r_, int g_, int b_)
: r (r_)
, g (g_)
@@ -84,7 +110,7 @@ Color::to_argb_string () const
* @param b Second color to compare.
*/
bool
-libdcp::operator== (Color const & a, Color const & b)
+dcp::operator== (Color const & a, Color const & b)
{
return (a.r == b.r && a.g == b.g && a.b == b.b);
}
@@ -94,20 +120,20 @@ libdcp::operator== (Color const & a, Color const & b)
* @param b Second color to compare.
*/
bool
-libdcp::operator!= (Color const & a, Color const & b)
+dcp::operator!= (Color const & a, Color const & b)
{
return !(a == b);
}
ostream &
-libdcp::operator<< (ostream& s, Color const & c)
+dcp::operator<< (ostream& s, Color const & c)
{
s << "(" << c.r << ", " << c.g << ", " << c.b << ")";
return s;
}
string
-libdcp::effect_to_string (Effect e)
+dcp::effect_to_string (Effect e)
{
switch (e) {
case NONE:
@@ -122,7 +148,7 @@ libdcp::effect_to_string (Effect e)
}
Effect
-libdcp::string_to_effect (string s)
+dcp::string_to_effect (string s)
{
if (s == "none") {
return NONE;
@@ -136,7 +162,7 @@ libdcp::string_to_effect (string s)
}
string
-libdcp::valign_to_string (VAlign v)
+dcp::valign_to_string (VAlign v)
{
switch (v) {
case TOP:
@@ -151,7 +177,7 @@ libdcp::valign_to_string (VAlign v)
}
VAlign
-libdcp::string_to_valign (string s)
+dcp::string_to_valign (string s)
{
if (s == "top") {
return TOP;
diff --git a/src/types.h b/src/types.h
index 013c1863..ece7d44c 100644
--- a/src/types.h
+++ b/src/types.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,10 +24,10 @@
#ifndef LIBDCP_TYPES_H
#define LIBDCP_TYPES_H
-#include <string>
#include <boost/shared_ptr.hpp>
+#include <string>
-namespace libdcp
+namespace dcp
{
namespace parse {
@@ -85,12 +85,20 @@ enum Eye
EYE_LEFT,
EYE_RIGHT
};
-
+
+/** @class Fraction
+ * @brief A fraction (i.e. a thing with an integer numerator and an integer denominator).
+ */
class Fraction
{
public:
+ /** Construct a fraction of 0/0 */
Fraction () : numerator (0), denominator (0) {}
Fraction (std::string s);
+ /** Construct a fraction with a specified numerator and denominator.
+ * @param n Numerator.
+ * @param d Denominator.
+ */
Fraction (int n, int d) : numerator (n), denominator (d) {}
int numerator;
@@ -99,20 +107,33 @@ public:
extern bool operator== (Fraction const & a, Fraction const & b);
extern bool operator!= (Fraction const & a, Fraction const & b);
-
-struct EqualityOptions {
+
+/** @struct EqualityOptions
+ * @brief A class to describe what "equality" means for a particular test.
+ *
+ * When comparing things, we want to be able to ignore some differences;
+ * this class expresses those differences.
+ */
+struct EqualityOptions
+{
+ /** Construct an EqualityOptions where nothing at all can differ */
EqualityOptions ()
: max_mean_pixel_error (0)
, max_std_dev_pixel_error (0)
, max_audio_sample_error (0)
- , cpl_names_can_differ (false)
+ , cpl_annotation_texts_can_differ (false)
, mxf_names_can_differ (false)
{}
+ /** The maximum allowable mean difference in pixel value between two images */
double max_mean_pixel_error;
+ /** The maximum standard deviation of the differences in pixel value between two images */
double max_std_dev_pixel_error;
+ /** The maximum difference in audio sample value between two soundtracks */
int max_audio_sample_error;
- bool cpl_names_can_differ;
+ /** true if the <AnnotationText> nodes of CPLs are allowed to differ */
+ bool cpl_annotation_texts_can_differ;
+ /** true if MXF filenames are allowed to differ */
bool mxf_names_can_differ;
};
@@ -125,6 +146,11 @@ enum NoteType {
NOTE
};
+enum Standard {
+ INTEROP,
+ SMPTE
+};
+
/** @class Color
* @brief An RGB color (aka colour).
*/
diff --git a/src/util.cc b/src/util.cc
index a668b7fc..1e32fbc9 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,22 +21,6 @@
* @brief Utility methods.
*/
-#include <stdexcept>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <openssl/sha.h>
-#include <libxml++/nodes/element.h>
-#include <libxml++/document.h>
-#include <xmlsec/xmldsig.h>
-#include <xmlsec/dl.h>
-#include <xmlsec/app.h>
-#include <xmlsec/crypto.h>
-#include "KM_util.h"
-#include "KM_fileio.h"
-#include "AS_DCP.h"
#include "util.h"
#include "exceptions.h"
#include "types.h"
@@ -44,6 +28,22 @@
#include "certificates.h"
#include "gamma_lut.h"
#include "xyz_frame.h"
+#include "compose.hpp"
+#include "KM_util.h"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/dl.h>
+#include <xmlsec/app.h>
+#include <xmlsec/crypto.h>
+#include <libxml++/nodes/element.h>
+#include <libxml++/document.h>
+#include <openssl/sha.h>
+#include <boost/filesystem.hpp>
+#include <stdexcept>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
using std::string;
using std::wstring;
@@ -54,15 +54,17 @@ using std::max;
using std::list;
using std::setw;
using std::setfill;
+using std::ostream;
using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
+using boost::optional;
+using boost::function;
+using namespace dcp;
/** Create a UUID.
* @return UUID.
*/
string
-libdcp::make_uuid ()
+dcp::make_uuid ()
{
char buffer[64];
Kumu::UUID id;
@@ -74,15 +76,15 @@ libdcp::make_uuid ()
/** Create a digest for a file.
* @param filename File name.
- * @param progress Pointer to a progress reporting function, or 0. The function will be called
+ * @param progress Optional progress reporting function. The function will be called
* with a progress value between 0 and 1.
* @return Digest.
*/
string
-libdcp::make_digest (string filename, boost::function<void (float)>* progress)
+dcp::make_digest (boost::filesystem::path filename, function<void (float)> progress)
{
Kumu::FileReader reader;
- Kumu::Result_t r = reader.OpenRead (filename.c_str ());
+ Kumu::Result_t r = reader.OpenRead (filename.string().c_str ());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open file to compute digest", filename, r));
}
@@ -108,7 +110,7 @@ libdcp::make_digest (string filename, boost::function<void (float)>* progress)
SHA1_Update (&sha, read_buffer.Data(), read);
if (progress) {
- (*progress) (float (done) / size);
+ progress (float (done) / size);
done += read;
}
}
@@ -121,12 +123,12 @@ libdcp::make_digest (string filename, boost::function<void (float)>* progress)
}
/** Convert a content kind to a string which can be used in a
- * <ContentKind> node.
+ * &lt;ContentKind&gt; node.
* @param kind ContentKind.
* @return string.
*/
string
-libdcp::content_kind_to_string (ContentKind kind)
+dcp::content_kind_to_string (ContentKind kind)
{
switch (kind) {
case FEATURE:
@@ -154,35 +156,35 @@ libdcp::content_kind_to_string (ContentKind kind)
assert (false);
}
-/** Convert a string from a <ContentKind> node to a libdcp ContentKind.
+/** Convert a string from a &lt;ContentKind&gt; node to a libdcp ContentKind.
* Reasonably tolerant about varying case.
- * @param type Content kind string.
+ * @param kind Content kind string.
* @return libdcp ContentKind.
*/
-libdcp::ContentKind
-libdcp::content_kind_from_string (string type)
+dcp::ContentKind
+dcp::content_kind_from_string (string kind)
{
- transform (type.begin(), type.end(), type.begin(), ::tolower);
+ transform (kind.begin(), kind.end(), kind.begin(), ::tolower);
- if (type == "feature") {
+ if (kind == "feature") {
return FEATURE;
- } else if (type == "short") {
+ } else if (kind == "short") {
return SHORT;
- } else if (type == "trailer") {
+ } else if (kind == "trailer") {
return TRAILER;
- } else if (type == "test") {
+ } else if (kind == "test") {
return TEST;
- } else if (type == "transitional") {
+ } else if (kind == "transitional") {
return TRANSITIONAL;
- } else if (type == "rating") {
+ } else if (kind == "rating") {
return RATING;
- } else if (type == "teaser") {
+ } else if (kind == "teaser") {
return TEASER;
- } else if (type == "policy") {
+ } else if (kind == "policy") {
return POLICY;
- } else if (type == "psa") {
+ } else if (kind == "psa") {
return PUBLIC_SERVICE_ANNOUNCEMENT;
- } else if (type == "advertisement") {
+ } else if (kind == "advertisement") {
return ADVERTISEMENT;
}
@@ -198,8 +200,8 @@ libdcp::content_kind_from_string (string type)
* This is useful for scaling 4K DCP images down to 2K.
* @return XYZ image.
*/
-shared_ptr<libdcp::XYZFrame>
-libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
+shared_ptr<dcp::XYZFrame>
+dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
{
opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K);
opj_dparameters_t parameters;
@@ -211,7 +213,7 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
if (!image) {
opj_destroy_decompress (decoder);
opj_cio_close (cio);
- boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream of " + lexical_cast<string> (size) + " bytes."));
+ boost::throw_exception (DCPReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
}
opj_destroy_decompress (decoder);
@@ -226,7 +228,7 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
* @return true if the string contains only space, newline or tab characters, or is empty.
*/
bool
-libdcp::empty_or_white_space (string s)
+dcp::empty_or_white_space (string s)
{
for (size_t i = 0; i < s.length(); ++i) {
if (s[i] != ' ' && s[i] != '\n' && s[i] != '\t') {
@@ -237,8 +239,11 @@ libdcp::empty_or_white_space (string s)
return true;
}
+/** Set up various bits that the library needs. Should be called one
+ * by client applications.
+ */
void
-libdcp::init ()
+dcp::init ()
{
if (xmlSecInit() < 0) {
throw MiscError ("could not initialise xmlsec");
@@ -259,21 +264,33 @@ libdcp::init ()
}
}
-bool libdcp::operator== (libdcp::Size const & a, libdcp::Size const & b)
+bool dcp::operator== (dcp::Size const & a, dcp::Size const & b)
{
return (a.width == b.width && a.height == b.height);
}
-bool libdcp::operator!= (libdcp::Size const & a, libdcp::Size const & b)
+bool dcp::operator!= (dcp::Size const & a, dcp::Size const & b)
{
return !(a == b);
}
-/** The base64 decode routine in KM_util.cpp gives different values to both
- * this and the command-line base64 for some inputs. Not sure why.
+ostream& dcp::operator<< (ostream& s, dcp::Size const & a)
+{
+ s << a.width << "x" << a.height;
+ return s;
+}
+
+/** Decode a base64 string. The base64 decode routine in KM_util.cpp
+ * gives different values to both this and the command-line base64
+ * for some inputs. Not sure why.
+ *
+ * @param in base64-encoded string.
+ * @param out Output buffer.
+ * @param out_length Length of output buffer.
+ * @return Number of characters written to the output buffer.
*/
int
-libdcp::base64_decode (string const & in, unsigned char* out, int out_length)
+dcp::base64_decode (string const & in, unsigned char* out, int out_length)
{
BIO* b64 = BIO_new (BIO_f_base64 ());
@@ -297,8 +314,13 @@ libdcp::base64_decode (string const & in, unsigned char* out, int out_length)
return N;
}
+/** Convert a struct tm to a string of the form
+ * 2014-01-26T21:39:00+01:00
+ * @param tm struct tm.
+ * @return Time as a string.
+ */
string
-libdcp::tm_to_string (struct tm* tm)
+dcp::tm_to_string (struct tm* tm)
{
char buffer[64];
strftime (buffer, 64, "%Y-%m-%dT%H:%M:%S", tm);
@@ -320,7 +342,7 @@ libdcp::tm_to_string (struct tm* tm)
* @return string of the form e.g. -01:00.
*/
string
-libdcp::utc_offset_to_string (int b)
+dcp::utc_offset_to_string (int b)
{
bool const negative = (b < 0);
b = negative ? -b : b;
@@ -339,20 +361,29 @@ libdcp::utc_offset_to_string (int b)
return o.str ();
}
+/** Convert a boost::posix_time::ptime to a string of the form
+ * 2014-01-26T21:39:00+01:00.
+ * @param t boost::posix_time::ptime.
+ * @return Time as a string.
+ */
string
-libdcp::ptime_to_string (boost::posix_time::ptime t)
+dcp::ptime_to_string (boost::posix_time::ptime t)
{
struct tm t_tm = boost::posix_time::to_tm (t);
return tm_to_string (&t_tm);
}
-/* Apparently there is no way to create an ofstream using a UTF-8
- filename under Windows. We are hence reduced to using fopen
- with this wrapper.
-*/
+/** @param p Path to open.
+ * @param t mode flags, as for fopen(3).
+ * @return FILE pointer or 0 on error.
+ *
+ * Apparently there is no way to create an ofstream using a UTF-8
+ * filename under Windows. We are hence reduced to using fopen
+ * with this wrapper.
+ */
FILE *
-libdcp::fopen_boost (boost::filesystem::path p, string t)
+dcp::fopen_boost (boost::filesystem::path p, string t)
{
#ifdef LIBDCP_WINDOWS
wstring w (t.begin(), t.end());
@@ -362,3 +393,26 @@ libdcp::fopen_boost (boost::filesystem::path p, string t)
return fopen (p.c_str(), t.c_str ());
#endif
}
+
+optional<boost::filesystem::path>
+dcp::relative_to_root (boost::filesystem::path root, boost::filesystem::path file)
+{
+ boost::filesystem::path::const_iterator i = root.begin ();
+ boost::filesystem::path::const_iterator j = file.begin ();
+
+ while (i != root.end() && j != file.end() && *i == *j) {
+ ++i;
+ ++j;
+ }
+
+ if (i != root.end ()) {
+ return optional<boost::filesystem::path> ();
+ }
+
+ boost::filesystem::path rel;
+ while (j != file.end ()) {
+ rel /= *j++;
+ }
+
+ return rel;
+}
diff --git a/src/util.h b/src/util.h
index 2a6aae1b..ca00ecb9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,27 +24,32 @@
* @brief Utility methods.
*/
-#include <string>
-#include <stdint.h>
+#include "types.h"
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
+#include <boost/optional.hpp>
#include <openjpeg.h>
-#include "types.h"
+#include <string>
+#include <stdint.h>
namespace xmlpp {
class Element;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
class CertificateChain;
class GammaLUT;
class XYZFrame;
-struct Size {
+/** @struct Size
+ * @brief The integer, two-dimensional size of something.
+ */
+struct Size
+{
Size ()
: width (0)
, height (0)
@@ -65,9 +70,10 @@ struct Size {
extern bool operator== (Size const & a, Size const & b);
extern bool operator!= (Size const & a, Size const & b);
+extern std::ostream& operator<< (std::ostream& s, Size const & a);
extern std::string make_uuid ();
-extern std::string make_digest (std::string filename, boost::function<void (float)> *);
+extern std::string make_digest (boost::filesystem::path filename, boost::function<void (float)>);
extern std::string content_kind_to_string (ContentKind kind);
extern ContentKind content_kind_from_string (std::string kind);
extern bool empty_or_white_space (std::string s);
@@ -75,16 +81,31 @@ extern boost::shared_ptr<XYZFrame> decompress_j2k (uint8_t* data, int64_t size,
extern void init ();
-extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, bool interop);
+extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, Standard standard);
extern void add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, std::string const & ns);
extern void add_signer (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & ns);
extern int base64_decode (std::string const & in, unsigned char* out, int out_length);
-
+extern boost::optional<boost::filesystem::path> relative_to_root (boost::filesystem::path root, boost::filesystem::path file);
extern std::string tm_to_string (struct tm *);
extern std::string utc_offset_to_string (int);
extern std::string ptime_to_string (boost::posix_time::ptime);
extern FILE * fopen_boost (boost::filesystem::path, std::string);
+
+template <class F, class T>
+std::list<boost::shared_ptr<T> >
+list_of_type (std::list<boost::shared_ptr<F> > const & from)
+{
+ std::list<boost::shared_ptr<T> > out;
+ for (typename std::list<boost::shared_ptr<F> >::const_iterator i = from.begin(); i != from.end(); ++i) {
+ boost::shared_ptr<T> check = boost::dynamic_pointer_cast<T> (*i);
+ if (check) {
+ out.push_back (check);
+ }
+ }
+
+ return out;
+}
}
diff --git a/src/version.h b/src/version.h
index 52abd13a..9b6dc65f 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,5 +1,5 @@
-namespace libdcp {
+namespace dcp {
extern char const * version;
extern char const * git_commit;
diff --git a/src/wscript b/src/wscript
index cdf3c062..c06ca1bd 100644
--- a/src/wscript
+++ b/src/wscript
@@ -6,51 +6,61 @@ def build(bld):
else:
obj = bld(features = 'cxx cxxshlib')
- obj.name = 'libdcp'
- obj.target = 'dcp'
+ obj.name = 'libdcp%s' % bld.env.API_VERSION
+ obj.target = 'dcp%s' % bld.env.API_VERSION
obj.export_includes = ['.']
obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1'
- obj.use = 'libkumu-libdcp libasdcp-libdcp'
+ obj.use = 'libkumu-libdcp%s libasdcp-libdcp%s' % (bld.env.API_VERSION, bld.env.API_VERSION)
obj.source = """
argb_frame.cc
asset.cc
certificates.cc
colour_matrix.cc
+ content.cc
cpl.cc
dcp.cc
dcp_time.cc
exceptions.cc
+ file.cc
+ font.cc
gamma_lut.cc
image.cc
kdm.cc
key.cc
+ load_font.cc
metadata.cc
- mono_picture_asset.cc
- mono_picture_asset_writer.cc
+ mono_picture_mxf.cc
+ mono_picture_mxf_writer.cc
mono_picture_frame.cc
- mxf_asset.cc
- picture_asset.cc
- picture_asset_writer.cc
- rec709_linearised_gamma_lut.cc
+ mxf.cc
+ mxf_writer.cc
+ object.cc
+ picture_mxf.cc
+ picture_mxf_writer.cc
reel.cc
+ reel_asset.cc
+ reel_mono_picture_asset.cc
+ reel_picture_asset.cc
+ reel_sound_asset.cc
+ reel_stereo_picture_asset.cc
+ reel_subtitle_asset.cc
rgb_xyz.cc
signer.cc
signer_chain.cc
- sound_asset.cc
+ sound_mxf.cc
+ sound_mxf_writer.cc
sound_frame.cc
- srgb_linearised_gamma_lut.cc
- stereo_picture_asset.cc
- stereo_picture_asset_writer.cc
+ stereo_picture_mxf.cc
+ stereo_picture_mxf_writer.cc
stereo_picture_frame.cc
- subtitle_asset.cc
+ subtitle.cc
+ subtitle_content.cc
+ subtitle_string.cc
+ text.cc
types.cc
util.cc
version.cc
xyz_frame.cc
- parse/asset_map.cc
- parse/cpl.cc
- parse/pkl.cc
- parse/subtitle.cc
"""
headers = """
@@ -58,6 +68,7 @@ def build(bld):
certificates.h
colour_matrix.h
cpl.h
+ content.h
dcp.h
dcp_time.h
exceptions.h
@@ -65,32 +76,40 @@ def build(bld):
image.h
kdm.h
key.h
- lut.h
lut_cache.h
metadata.h
- mono_picture_asset.h
+ mono_picture_mxf.h
mono_picture_frame.h
- mxf_asset.h
- picture_asset.h
- picture_asset_writer.h
+ mxf.h
+ mxf_writer.h
+ object.h
+ picture_mxf.h
+ picture_mxf_writer.h
rgb_xyz.h
- rec709_linearised_gamma_lut.h
reel.h
+ reel_asset.h
+ reel_mono_picture_asset.h
+ reel_picture_asset.h
+ reel_sound_asset.h
+ reel_stereo_picture_asset.h
+ ref.h
argb_frame.h
signer.h
signer_chain.h
- sound_asset.h
sound_frame.h
- srgb_linearised_gamma_lut.h
- stereo_picture_asset.h
+ sound_mxf.h
+ sound_mxf_writer.h
+ stereo_picture_mxf.h
stereo_picture_frame.h
- subtitle_asset.h
+ subtitle.h
+ subtitle_content.h
+ subtitle_string.h
types.h
util.h
version.h
xyz_frame.h
"""
- bld.install_files('${PREFIX}/include/libdcp', headers)
+ bld.install_files('${PREFIX}/include/libdcp%s/dcp' % bld.env.API_VERSION, headers)
if bld.env.STATIC:
- bld.install_files('${PREFIX}/lib', 'libdcp.a')
+ bld.install_files('${PREFIX}/lib', 'libdcp%s.a' % bld.env.API_VERSION)
diff --git a/src/xml.h b/src/xml.h
index 5978ff7e..b89d8ccd 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,10 +20,10 @@
#ifndef LIBDCP_XML_H
#define LIBDCP_XML_H
-#include <libcxml/cxml.h>
#include "exceptions.h"
+#include <libcxml/cxml.h>
-namespace libdcp
+namespace dcp
{
template <class T>
diff --git a/src/xyz_frame.cc b/src/xyz_frame.cc
index f5b0ee86..cba90883 100644
--- a/src/xyz_frame.cc
+++ b/src/xyz_frame.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,11 +17,15 @@
*/
+/** @file src/xyz_frame.cc
+ * @brief XZYFrame class.
+ */
+
+#include "xyz_frame.h"
#include <cassert>
#include <stdexcept>
-#include "xyz_frame.h"
-using namespace libdcp;
+using namespace dcp;
/** Construct an XYZFrame, taking ownership of the opj_image_t */
XYZFrame::XYZFrame (opj_image_t* image)
@@ -30,6 +34,9 @@ XYZFrame::XYZFrame (opj_image_t* image)
assert (_opj_image->numcomps == 3);
}
+/** Construct a new XYZFrame with undefined contents.
+ * @param size Size for the frame in pixels.
+ */
XYZFrame::XYZFrame (Size size)
{
opj_image_cmptparm_t cmptparm[3];
@@ -58,11 +65,15 @@ XYZFrame::XYZFrame (Size size)
_opj_image->y1 = size.height;
}
+/** XYZFrame destructor */
XYZFrame::~XYZFrame ()
{
opj_image_destroy (_opj_image);
}
+/** @param c Component index (0, 1 or 2)
+ * @return Pointer to the data for component c.
+ */
int *
XYZFrame::data (int c) const
{
@@ -70,9 +81,10 @@ XYZFrame::data (int c) const
return _opj_image->comps[c].data;
}
-libdcp::Size
+/** @return Size of the image in pixels */
+dcp::Size
XYZFrame::size () const
{
/* XXX: this may not be right; x0 and y0 can presumably be non-zero */
- return libdcp::Size (_opj_image->x1, _opj_image->y1);
+ return dcp::Size (_opj_image->x1, _opj_image->y1);
}
diff --git a/src/xyz_frame.h b/src/xyz_frame.h
index a4dcb2c0..8ba829b2 100644
--- a/src/xyz_frame.h
+++ b/src/xyz_frame.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,12 +17,21 @@
*/
-#include <openjpeg.h>
+/** @file src/xyz_frame.h
+ * @brief XZYFrame class.
+ */
+
#include "util.h"
+#include <openjpeg.h>
-namespace libdcp {
+namespace dcp {
-class XYZFrame
+/** @class XYZFrame
+ * @brief An image in XYZ colour.
+ *
+ * This class is a thin wrapper of libopenjpeg's opj_image_t.
+ */
+class XYZFrame : public boost::noncopyable
{
public:
XYZFrame (opj_image_t *);
@@ -30,14 +39,17 @@ public:
~XYZFrame ();
int* data (int) const;
- libdcp::Size size () const;
+ dcp::Size size () const;
+ /** @return Pointer to opj_image_t struct. The caller
+ * must not delete this.
+ */
opj_image_t* opj_image () const {
return _opj_image;
}
private:
- opj_image_t* _opj_image;
+ opj_image_t* _opj_image; ///< opj_image_t that we are managing
};
}