#include "mono_picture_mxf.h"
#include "mono_picture_mxf_writer.h"
#include "sound_mxf.h"
+#include "sound_mxf_writer.h"
#include "reel.h"
+#include "file.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_sound_asset.h"
int
main ()
per second.
*/
- boost::shared_ptr<dcp::MonoPictureMXF> picture_mxf (new dcp::MonoPictureMXF (24));
+ boost::shared_ptr<dcp::MonoPictureMXF> picture_mxf (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
/* Start off a write to it */
- boost::shared_ptr<dcp::MonoPictureMXFWriter> picture_writer = picture_mxf->start_write ("DCP/picture.mxf", false);
+ boost::shared_ptr<dcp::PictureMXFWriter> picture_writer = picture_mxf->start_write ("DCP/picture.mxf", dcp::SMPTE, false);
/* Write 24 frames of the same JPEG2000 file */
dcp::File picture ("examples/help.j2c");
/* Now create a sound MXF. As before, create an object and a writer.
When creating the object we specify the sampling rate (48kHz) and the number of channels (2).
*/
- boost::shared_ptr<dcp::SoundMXF> sound_mxf (new dcp::SoundMXF (48000, 2));
- boost::shared_ptr<dcp::SoundMXFWriter> sound_writer = sound_mxf->start_write ("DCP/sound.mxf", false);
+ boost::shared_ptr<dcp::SoundMXF> sound_mxf (new dcp::SoundMXF (dcp::Fraction (24, 1), 48000, 2));
+ boost::shared_ptr<dcp::SoundMXFWriter> sound_writer = sound_mxf->start_write ("DCP/sound.mxf", dcp::SMPTE);
/* Write some sine waves */
float* audio[2];
sound_writer->finalize ();
/* Now create a reel */
- shared_ptr<dcp::Reel> reel (new dcp::Reel ());
+ boost::shared_ptr<dcp::Reel> reel (new dcp::Reel ());
/* Add picture and sound to it. The zeros are the `entry points', i.e. the first
(video) frame from the MXFs that the reel should play.
*/
- reel->add (picture, 0);
- reel->add (sound, 0);
+ reel->add (boost::shared_ptr<dcp::ReelPictureAsset> (new dcp::ReelMonoPictureAsset (picture_mxf, 0)));
+ reel->add (boost::shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (sound_mxf, 0)));
/* Make a CPL with this reel */
- shared_ptr<dcp::CPL> cpl (new dcp::CPL ("My film", dcp::FEATURE));
+ boost::shared_ptr<dcp::CPL> cpl (new dcp::CPL ("My film", dcp::FEATURE));
cpl->add (reel);
/* Write the DCP */
- list<shared_ptr<dcp::Asset> > assets;
- asset.push_back (cpl);
- asset.push_back (picture);
- asset.push_back (sound);
- dcp::write ("DCP", assets);
+ dcp::DCP dcp ("DCP");
+ dcp.add (cpl);
+ dcp.add (picture_mxf);
+ dcp.add (sound_mxf);
+ dcp.write_xml (dcp::SMPTE);
return 0;
}
/*
- 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
*/
+/** @file src/argb_frame.cc
+ * @brief ARGBFrame class.
+ */
+
#include "argb_frame.h"
using namespace dcp;
/*
- 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
*/
/** @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 dcp
{
*
* Lines are packed so that the second row directly follows the first.
*/
-class ARGBFrame
+class ARGBFrame : boost::noncopyable
{
public:
ARGBFrame (Size size);
}
private:
- Size _size;
- uint8_t* _data;
+ Size _size; ///< frame size in pixels
+ uint8_t* _data; ///< pointer to image data
};
}
*/
+/** @file src/asset.cc
+ * @brief Asset class.
+ */
+
#include "asset.h"
+#include "util.h"
+#include <libxml++/libxml++.h>
+#include <boost/lexical_cast.hpp>
using std::string;
+using boost::lexical_cast;
+using boost::function;
using namespace dcp;
+/** Create an Asset with a randomly-generated ID */
Asset::Asset ()
{
}
+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) const
+{
+ xmlpp::Node* asset = node->add_child ("Asset");
+ asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ asset->add_child("AnnotationText")->add_child_text (_id);
+ asset->add_child("Hash")->add_child_text (hash ());
+ asset->add_child("Size")->add_child_text (lexical_cast<string> (boost::filesystem::file_size (_file)));
+ asset->add_child("Type")->add_child_text (pkl_type ());
+}
+
+void
+Asset::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 (_file.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> (boost::filesystem::file_size (_file)));
+}
+
+string
+Asset::hash () const
+{
+ if (!_hash.empty ()) {
+ _hash = make_digest (_file, 0);
+ }
+
+ return _hash;
+}
+
+bool
+Asset::equals (boost::shared_ptr<const Asset> other, EqualityOptions, function<void (NoteType, string)> note) const
+{
+ if (_hash != other->_hash) {
+ note (ERROR, "Asset hashes differ");
+ return false;
+ }
+
+ return true;
+}
*/
+/** @file src/asset.h
+ * @brief Asset class.
+ */
+
#ifndef LIBDCP_ASSET_H
#define LIBDCP_ASSET_H
#include "object.h"
+#include "types.h"
+#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+
+namespace xmlpp {
+ class Node;
+}
namespace dcp {
/** @class Asset
- * @brief Parent class for DCP assets, i.e. picture/sound/subtitles, CPLs and PKLs.
+ * @brief Parent class for DCP assets, i.e. picture/sound/subtitles and CPLs.
+ *
+ * Note that this class is not used for ReelAssets; they are just for the metadata
+ * that gets put into <Reel>s.
*/
-
class Asset : public Object
{
public:
Asset ();
+ Asset (boost::filesystem::path file);
Asset (std::string id);
+ virtual std::string pkl_type () const = 0;
+ 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 PKL AssetList node.
+ * @param node Parent node.
+ */
+ void write_to_pkl (xmlpp::Node* node) const;
+ void write_to_assetmap (xmlpp::Node* node) const;
+
+ boost::filesystem::path file () const {
+ return _file;
+ }
+
+ void set_file (boost::filesystem::path file) {
+ _file = file;
+ }
+
+ std::string hash () const;
+
+protected:
+ friend class MXFWriter;
+
+ boost::filesystem::path _file;
+ mutable std::string _hash;
};
}
/*
- 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
*/
-#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>
#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 dcp;
}
+/** Load an X509 certificate from a file.
+ * @param filename File to load.
+ */
Certificate::Certificate (boost::filesystem::path filename)
: _certificate (0)
, _public_key (0)
}
}
+/** Load an X509 certificate from a string.
+ * @param cert String to read from.
+ */
Certificate::Certificate (string cert)
: _certificate (0)
, _public_key (0)
read_string (cert);
}
+/** Copy constructor.
+ * @param other Certificate to copy.
+ */
Certificate::Certificate (Certificate const & other)
: _certificate (0)
, _public_key (0)
read_string (other.certificate (true));
}
+/** Read a certificate from a string.
+ * @param cert String to read.
+ */
void
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)
{
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
{
return s;
}
+/** @return Certificate's issuer, in the form
+ * dnqualifier=<dnQualififer>,CN=<commonName>,OU=<organizationalUnitName>,O=organizationName
+ * and with + signs escaped to \+
+ */
string
Certificate::issuer () 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
{
return _public_key;
}
+/** @return Root certificate */
shared_ptr<Certificate>
CertificateChain::root () const
{
return _certificates.front ();
}
+/** @return Leaf certificate */
shared_ptr<Certificate>
CertificateChain::leaf () const
{
return _certificates.back ();
}
+/** @return Certificates in order from leaf to root */
list<shared_ptr<Certificate> >
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)
{
/*
- 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
*/
+/** @file src/certificates.h
+ * @brief Certificate and CertificateChain classes.
+ */
+
#ifndef LIBDCP_CERTIFICATES_H
#define LIBDCP_CERTIFICATES_H
-#include <string>
-#include <list>
+#undef X509_NAME
+#include <openssl/x509.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
-#undef X509_NAME
-#include <openssl/x509.h>
+#include <string>
+#include <list>
class certificates;
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:
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;
mutable RSA* _public_key;
};
+/** @class CertificateChain
+ * @brief A chain of any number of certificates, from root to leaf.
+ */
class CertificateChain
{
public:
/*
- 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
using namespace dcp;
Content::Content (boost::filesystem::path file)
- : _file (file)
- , _edit_rate (0)
+ : Asset (file)
+ , _edit_rate (24, 1)
, _intrinsic_duration (0)
{
}
-Content::Content (int edit_rate)
+Content::Content (Fraction edit_rate)
: _edit_rate (edit_rate)
, _intrinsic_duration (0)
{
}
-void
-Content::write_to_pkl (xmlpp::Node* node) const
-{
- xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- asset->add_child("AnnotationText")->add_child_text (_id);
-//XXX asset->add_child("Hash")->add_child_text (digest ());
- asset->add_child("Size")->add_child_text (lexical_cast<string> (filesystem::file_size (_file)));
- asset->add_child("Type")->add_child_text ("application/mxf");
-}
-
-void
-Content::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 (_file.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 (_file)));
-}
-
bool
-Content::equals (shared_ptr<const Content> other, EqualityOptions, boost::function<void (NoteType, string)> note) const
+Content::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- // if (_edit_rate != other->_edit_rate) {
- // note (ERROR, "asset edit rates differ");
- // return false;
- // }
+ if (!Asset::equals (other, opt, note)) {
+ return false;
+ }
- // if (_intrinsic_duration != other->_intrinsic_duration) {
- // note (ERROR, "asset intrinsic durations differ");
- // }
-
- // if (_duration != other->_duration) {
- // note (ERROR, "asset durations differ");
- // }
+ 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;
+ return true;
}
/*
- 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
*/
+/** @file src/content.h
+ * @brief Content class.
+ */
+
#ifndef LIBDCP_CONTENT_H
#define LIBDCP_CONTENT_H
-#include <string>
-#include <list>
-#include <boost/filesystem.hpp>
-#include <boost/function.hpp>
-#include <libxml++/libxml++.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;
{
public:
Content (boost::filesystem::path file);
- Content (int edit_rate);
+ Content (Fraction edit_rate);
virtual ~Content () {}
- /** Write details of the asset to a PKL AssetList node.
- * @param p Parent node.
- */
- void write_to_pkl (xmlpp::Node *) const;
-
- /** Write details of the asset to a ASSETMAP stream.
- * @param s Stream.
- */
- void write_to_assetmap (xmlpp::Node *) const;
-
- boost::filesystem::path file () const {
- return _file;
- }
-
- void set_file (boost::filesystem::path file) {
- _file = file;
- }
-
- int edit_rate () const {
+ Fraction edit_rate () const {
return _edit_rate;
}
- void set_edit_rate (int r) {
- _edit_rate = r;
- }
-
- void set_entry_point (int64_t p) {
- _entry_point = p;
- }
-
int64_t intrinsic_duration () const {
return _intrinsic_duration;
}
- void set_intrinsic_duration (int64_t d) {
- _intrinsic_duration = d;
- }
-
- int64_t duration () const {
- return _duration;
- }
-
- void set_duration (int64_t d) {
- _duration = d;
- }
-
virtual bool equals (boost::shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, std::string)>) const;
protected:
- boost::filesystem::path _file;
- /** The edit rate; this is normally equal to the number of video frames per second */
- int _edit_rate;
- int64_t _entry_point;
+ friend class MXFWriter;
+
+ Fraction _edit_rate;
int64_t _intrinsic_duration;
- int64_t _duration;
};
}
*/
-#include <libxml/parser.h>
#include "cpl.h"
-#include "parse/cpl.h"
#include "util.h"
#include "mono_picture_mxf.h"
#include "stereo_picture_mxf.h"
#include "sound_mxf.h"
-#include "subtitle_asset.h"
-#include "parse/asset_map.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;
using boost::optional;
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)
, _content_kind (content_kind)
- , _length (length)
- , _fps (frames_per_second)
+ , _length (0)
{
}
-/** 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)
- , _content_kind (FEATURE)
+/** Construct a CPL object from a XML file */
+CPL::CPL (boost::filesystem::path 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<PictureMXF> picture;
- shared_ptr<SoundMXF> 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 MonoPictureMXF (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;
- }
- }
-
- } else {
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
-
-// picture.reset (new StereoPictureMXF (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 SoundMXF (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);
-
-// subtitle.reset (new SubtitleAsset (asset.first, asset.second->chunks.front()->path));
-
-// 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)));
- }
+ 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"));
+ shared_ptr<cxml::Node> content_version = f.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");
+
+ f.ignore_child ("Issuer");
+ f.ignore_child ("Signer");
+ f.ignore_child ("Signature");
+
+ f.done ();
}
void
-CPL::add_reel (shared_ptr<Reel> reel)
+CPL::add (shared_ptr<Reel> reel)
{
_reels.push_back (reel);
}
void
-CPL::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+CPL::write_xml (boost::filesystem::path file, Standard standard, XMLMetadata metadata, 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");
}
root->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- root->add_child("AnnotationText")->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 (_name);
+ root->add_child("ContentTitleText")->add_child_text (_content_version_label_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");
-
- _digest = make_digest (p.string (), 0);
- _length = boost::filesystem::file_size (p.string ());
-}
+ doc.write_to_file (file.string (), "UTF-8");
-void
-CPL::write_to_pkl (xmlpp::Node* node) 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));
- asset->add_child("Type")->add_child_text ("text/xml");
+ _digest = make_digest (file.string (), 0);
+ _length = boost::filesystem::file_size (file.string ());
}
list<shared_ptr<const Content> >
list<shared_ptr<const Content> > 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 ());
+ a.push_back ((*i)->main_picture()->mxf ());
}
if ((*i)->main_sound ()) {
- a.push_back ((*i)->main_sound ());
+ a.push_back ((*i)->main_sound()->mxf ());
}
if ((*i)->main_subtitle ()) {
- a.push_back ((*i)->main_subtitle ());
+ a.push_back ((*i)->main_subtitle()->subtitle_content ());
}
}
chunk->add_child("Length")->add_child_text(lexical_cast<string> (_length));
}
-
-
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;
}
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;
}
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);
}
}
-pair<string, shared_ptr<const parse::AssetMapAsset> >
-CPL::asset_from_id (list<PathAssetMap> asset_maps, string id) const
-{
- 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);
- }
- }
-
- return make_pair ("", shared_ptr<const parse::AssetMapAsset> ());
-}
-
void
CPL::set_mxf_keys (Key key)
{
#include "asset.h"
namespace dcp {
-
-namespace parse {
- class AssetMap;
- class AssetMapAsset;
-}
class Content;
class Reel;
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);
-
- /** @return the length in frames */
- int length () const {
- return _length;
+ std::string pkl_type () const {
+ return "text/xml";
}
+ void add (boost::shared_ptr<Reel> reel);
+
+ std::string annotation_text () const {
+ return _annotation_text;
+ }
+
+ std::string content_title_text () const {
+ return _content_title_text;
+ }
+
/** @return the type of the content, used by media servers
* to categorise things (e.g. feature, trailer, etc.)
*/
return _reels;
}
- /** @return the CPL's name, as will be presented on projector
- * media servers and theatre management systems.
- */
- 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 Content> > assets () const;
bool encrypted () const;
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_xml (boost::filesystem::path file, Standard standard, XMLMetadata, boost::shared_ptr<const Signer>) const;
void write_to_assetmap (xmlpp::Node *) const;
- void write_to_pkl (xmlpp::Node *) const;
- void add_kdm (KDM const &);
+ void add (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 */
+ std::string _annotation_text;
+ std::string _issue_date;
+ std::string _creator;
+ std::string _content_title_text;
ContentKind _content_kind;
- /** length in frames */
- mutable int _length;
- /** frames per second */
- int _fps;
+ std::string _content_version_id;
+ std::string _content_version_label_text;
/** reels */
std::list<boost::shared_ptr<Reel> > _reels;
/** a SHA1 digest of our XML */
mutable std::string _digest;
+ /** length in bytes of the XML that we last wrote to disk */
+ mutable int64_t _length;
};
}
/*
- 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
*/
/** @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 "sound_mxf.h"
#include "picture_mxf.h"
-#include "subtitle_asset.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/lexical_cast.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::copy;
using std::back_inserter;
using std::make_pair;
+using std::map;
using boost::shared_ptr;
using boost::lexical_cast;
+using boost::dynamic_pointer_cast;
using namespace dcp;
DCP::DCP (boost::filesystem::path 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"));
+ }
+
+ cxml::Document asset_map ("AssetMap");
+ asset_map.read_file (asset_map_file);
+ list<shared_ptr<cxml::Node> > assets = asset_map.node_child("AssetList")->node_children ("Asset");
+ map<string, boost::filesystem::path> paths;
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = assets.begin(); i != assets.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")
+ ));
}
- string pkl_uuid = make_uuid ();
- string pkl_path = write_pkl (pkl_uuid, interop, metadata, signer);
+ /* 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) {
+ if (boost::algorithm::ends_with (i->second.string(), ".xml")) {
+ xmlpp::DomParser* p = new xmlpp::DomParser;
+ try {
+ p->parse_file (i->second.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 (i->second)));
+ } else if (root == "DCSubtitle") {
+ _assets.push_back (shared_ptr<SubtitleContent> (new SubtitleContent (i->second)));
+ }
+ } else if (boost::algorithm::ends_with (i->second.string(), ".mxf")) {
+ ASDCP::EssenceType_t type;
+ if (ASDCP::EssenceType (i->second.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 (i->second)));
+ break;
+ case ASDCP::ESS_PCM_24b_48k:
+ case ASDCP::ESS_PCM_24b_96k:
+ _assets.push_back (shared_ptr<SoundMXF> (new SoundMXF (i->second)));
+ break;
+ case ASDCP::ESS_JPEG_2000_S:
+ _assets.push_back (shared_ptr<StereoPictureMXF> (new StereoPictureMXF (i->second)));
+ break;
+ default:
+ throw DCPReadError ("Unknown MXF essence type");
+ }
+ }
+ }
+}
+
+bool
+DCP::equals (DCP const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ 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 (shared_ptr<Asset> asset)
+{
+ _assets.push_back (asset);
}
-std::string
-DCP::write_pkl (string pkl_uuid, bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+class AssetComparator
{
- assert (!_cpls.empty ());
+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");
}
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());
+ list<shared_ptr<Asset> >::const_iterator i = _assets.begin();
+ shared_ptr<CPL> first_cpl;
+ while (i != _assets.end()) {
+ first_cpl = dynamic_pointer_cast<CPL> (*i);
+ if (first_cpl) {
+ break;
+ }
+ }
+
+ assert (first_cpl);
+ pkl->add_child("AnnotationText")->add_child_text (first_cpl->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 Content> > a = assets ();
- for (list<shared_ptr<const Content> >::const_iterator i = a.begin(); i != a.end(); ++i) {
- (*i)->write_to_pkl (asset_list);
- }
-
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_to_pkl (asset_list);
+
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ shared_ptr<Content> c = dynamic_pointer_cast<Content> (*i);
+ if (c) {
+ c->write_to_pkl (asset_list);
+ }
}
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;
+ if (standard == INTEROP) {
p /= "VOLINDEX";
} else {
p /= "VOLINDEX.xml";
}
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;
+ if (standard == INTEROP) {
p /= "ASSETMAP";
} else {
p /= "ASSETMAP.xml";
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+ if (standard == INTEROP) {
root = doc.create_root_node ("AssetMap", "http://www.digicine.com/PROTO-ASDCP-AM-20040311#");
} else {
root = doc.create_root_node ("AssetMap", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
root->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
root->add_child("AnnotationText")->add_child_text ("Created by " + metadata.creator);
- if (interop) {
+ if (standard == 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);
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 Content> > a = assets ();
- for (list<shared_ptr<const Content> >::const_iterator i = a.begin(); i != a.end(); ++i) {
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
(*i)->write_to_assetmap (asset_list);
}
}
void
-DCP::read (bool require_mxfs)
+DCP::write_xml (
+ Standard standard,
+ XMLMetadata metadata,
+ shared_ptr<const Signer> signer
+ )
{
- 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 dcp::parse::AssetMap (p.string ()));
- } else {
- p = _directory;
- p /= "ASSETMAP.xml";
- if (boost::filesystem::exists (p)) {
- asset_map.reset (new dcp::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<dcp::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"));
- }
- }
- }
+ string const pkl_uuid = make_uuid ();
+ boost::filesystem::path const pkl_path = write_pkl (standard, pkl_uuid, metadata, signer);
- 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;
+ write_volindex (standard);
+ write_assetmap (standard, pkl_uuid, boost::filesystem::file_size (pkl_path), metadata);
+
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ shared_ptr<CPL> c = dynamic_pointer_cast<CPL> (*i);
+ if (c) {
+ string const filename = c->id() + "_cpl.xml";
+ c->write_xml (_directory / filename, standard, metadata, signer);
}
- ++a;
- ++b;
- }
-
- return true;
-}
-
-void
-DCP::add_cpl (shared_ptr<CPL> cpl)
-{
- _cpls.push_back (cpl);
-}
-
-class AssetComparator
-{
-public:
- bool operator() (shared_ptr<const Content> a, shared_ptr<const Content> b) {
- return a->id() < b->id();
- }
-};
-
-list<shared_ptr<const Content> >
-DCP::assets () const
-{
- list<shared_ptr<const Content> > a;
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- list<shared_ptr<const Content> > t = (*i)->assets ();
- a.merge (t);
}
-
- a.sort (AssetComparator ());
- a.unique ();
- return a;
}
-bool
-DCP::encrypted () const
+list<shared_ptr<CPL> >
+DCP::cpls () const
{
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- if ((*i)->encrypted ()) {
- return true;
+ list<shared_ptr<CPL> > cpls;
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ shared_ptr<CPL> c = dynamic_pointer_cast<CPL> (*i);
+ if (c) {
+ cpls.push_back (c);
}
}
- return false;
+ return cpls;
}
-void
-DCP::add_kdm (KDM const & kdm)
-{
- list<KDMKey> keys = kdm.keys ();
- 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);
- }
- }
- }
-}
-
-void
-DCP::add_assets_from (DCP const & ov)
-{
- copy (ov._asset_maps.begin(), ov._asset_maps.end(), back_inserter (_asset_maps));
-}
#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;
{
class Content;
-class PictureAsset;
-class SoundAsset;
-class SubtitleAsset;
class Reel;
class CPL;
class XMLMetadata;
class Signer;
class KDM;
+class Asset;
namespace parse {
class AssetMap;
*/
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.
*/
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);
-
- /** @return The list of CPLs in this DCP */
- std::list<boost::shared_ptr<CPL> > cpls () const {
- return _cpls;
- }
+ void add (boost::shared_ptr<Asset> asset);
- /** 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 (DCP const &);
+ std::list<boost::shared_ptr<CPL> > cpls () const;
bool encrypted () const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
+
+ void write_xml (
+ Standard standard,
+ XMLMetadata metadata = XMLMetadata (),
+ boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()
+ );
/** Emitted with a parameter between 0 and 1 to indicate progress
* for long jobs.
/** 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 Content> > 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;
+ std::list<boost::shared_ptr<Asset> > _assets;
};
}
*/
+/** @file src/exceptions.cc
+ * @brief Exceptions thrown by libdcp.
+ */
+
#include "exceptions.h"
#include "compose.hpp"
using std::string;
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)
}
+UnresolvedRefError::UnresolvedRefError (string id)
+ : _message (String::compose ("Unresolved reference to asset id %1", id))
+{
+
+}
+
/*
- 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
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 */
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)
{}
};
class MiscError : public std::exception
{
public:
- MiscError (std::string const & message) : _message (message) {}
+ MiscError (std::string message) : _message (message) {}
~MiscError () throw () {}
/** @return error message */
class DCPReadError : public std::exception
{
public:
- DCPReadError (std::string const & message) : _message (message) {}
+ DCPReadError (std::string message) : _message (message) {}
~DCPReadError () throw () {}
/** @return error message */
class XMLError : public std::exception
{
public:
- XMLError (std::string const & message) : _message (message) {}
+ XMLError (std::string message) : _message (message) {}
~XMLError () throw () {}
/** @return error message */
/** error message */
std::string _message;
};
+
+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;
+};
}
--- /dev/null
+/*
+ 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 "file.h"
+#include "util.h"
+
+using namespace dcp;
+
+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::~File ()
+{
+ delete[] _data;
+}
--- /dev/null
+/*
+ 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 <boost/filesystem.hpp>
+
+namespace dcp {
+
+class File
+{
+public:
+ File (boost::filesystem::path file);
+ ~File ();
+
+ uint8_t* data () const {
+ return _data;
+ }
+
+ int64_t size () const {
+ return _size;
+ }
+
+private:
+ uint8_t* _data;
+ int64_t _size;
+};
+
+}
--- /dev/null
+/*
+ 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 "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 namespace dcp;
+
+Font::Font (shared_ptr<const cxml::Node> node)
+{
+ text = node->content ();
+
+ id = node->optional_string_attribute ("Id").get_value_or ("");
+ size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0);
+ italic = node->optional_bool_attribute ("Italic");
+ optional<string> c = node->optional_string_attribute ("Color");
+ if (c) {
+ color = Color (c.get ());
+ }
+ optional<string> const e = node->optional_string_attribute ("Effect");
+ if (e) {
+ effect = string_to_effect (e.get ());
+ }
+ c = node->optional_string_attribute ( "EffectColor");
+ if (c) {
+ effect_color = Color (c.get ());
+ }
+ subtitle_nodes = type_children<Subtitle> (node, "Subtitle");
+ font_nodes = type_children<Font> (node, "Font");
+ text_nodes = type_children<Text> (node, "Text");
+}
+
+Font::Font (list<shared_ptr<Font> > const & font_nodes)
+ : size (0)
+ , italic (false)
+ , color ("FFFFFFFF")
+ , effect_color ("FFFFFFFF")
+{
+ for (list<shared_ptr<Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
+ if (!(*i)->id.empty ()) {
+ id = (*i)->id;
+ }
+ if ((*i)->size != 0) {
+ size = (*i)->size;
+ }
+ if ((*i)->italic) {
+ italic = (*i)->italic.get ();
+ }
+ if ((*i)->color) {
+ color = (*i)->color.get ();
+ }
+ if ((*i)->effect) {
+ effect = (*i)->effect.get ();
+ }
+ if ((*i)->effect_color) {
+ effect_color = (*i)->effect_color.get ();
+ }
+ }
+}
--- /dev/null
+/*
+ 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 "subtitle.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font
+{
+public:
+ Font ()
+ : size (0)
+ {}
+
+ Font (boost::shared_ptr<const cxml::Node> node);
+ Font (std::list<boost::shared_ptr<Font> > const & font_nodes);
+
+ std::string text;
+ std::string id;
+ int size;
+ boost::optional<bool> italic;
+ boost::optional<Color> color;
+ boost::optional<Effect> effect;
+ boost::optional<Color> effect_color;
+
+ std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+};
+
+}
*/
-#include <cmath>
#include "gamma_lut.h"
#include "lut_cache.h"
+#include <cmath>
using namespace dcp;
LUTCache<GammaLUT> GammaLUT::cache;
-GammaLUT::GammaLUT(int bits, float gamma)
+GammaLUT::GammaLUT (int bits, float gamma)
: LUT (bits, gamma)
{
- int const bit_length = pow(2, bits);
+ int const bit_length = pow (2, bits);
for (int i = 0; i < bit_length; ++i) {
_lut[i] = pow(float(i) / (bit_length - 1), gamma);
}
/*
- 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
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 ();
#define LIBDCP_KEY_H
#include <stdint.h>
+#include <string>
namespace dcp {
--- /dev/null
+/*
+ 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 "load_font.h"
+#include <libcxml/cxml.h>
+
+using boost::shared_ptr;
+using namespace dcp;
+
+LoadFont::LoadFont (shared_ptr<const cxml::Node> node)
+{
+ id = node->string_attribute ("Id");
+ uri = node->string_attribute ("URI");
+}
--- /dev/null
+/*
+ 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 <boost/shared_ptr.hpp>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class LoadFont
+{
+public:
+ LoadFont () {}
+ LoadFont (boost::shared_ptr<const cxml::Node> node);
+
+ std::string id;
+ std::string uri;
+};
+
+}
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;
+ read_picture_descriptor (desc);
}
-MonoPictureMXF::MonoPictureMXF (int edit_rate)
+MonoPictureMXF::MonoPictureMXF (Fraction edit_rate)
: PictureMXF (edit_rate)
{
}
shared_ptr<PictureMXFWriter>
-MonoPictureMXF::start_write (boost::filesystem::path file, bool overwrite)
+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, overwrite));
+ return shared_ptr<MonoPictureMXFWriter> (new MonoPictureMXFWriter (this, file, standard, overwrite));
}
string
namespace dcp {
+class MonoPictureMXFWriter;
+
/** @class MonoPictureMXF
* @brief A 2D (monoscopic) picture MXF.
*/
/** Create a MonoPictureMXF with a given edit rate.
* @param edit_rate Edit rate (i.e. frame rate) in frames per second.
*/
- MonoPictureMXF (int edit_rate);
+ MonoPictureMXF (Fraction edit_rate);
/** Start a progressive write to a MonoPictureMXF */
- boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path, bool);
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path, Standard standard, bool);
boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
bool equals (boost::shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
/** @param a Asset to write to. `a' must not be deleted while
* this writer class still exists, or bad things will happen.
*/
-MonoPictureMXFWriter::MonoPictureMXFWriter (PictureMXF* asset, boost::filesystem::path file, bool overwrite)
- : PictureMXFWriter (asset, file, overwrite)
+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
MonoPictureMXFWriter::start (uint8_t* data, int size)
{
- dcp::start (this, _state, _mxf, data, size);
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
}
FrameInfo
void
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", _mxf->file().string(), r));
}
- _finalized = true;
- _mxf->set_intrinsic_duration (_frames_written);
- _mxf->set_duration (_frames_written);
+ PictureMXFWriter::finalize ();
}
private:
friend class MonoPictureMXF;
- MonoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, 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
* @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 "metadata.h"
#include "exceptions.h"
#include "kdm.h"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
using std::string;
using std::list;
using boost::dynamic_pointer_cast;
using namespace dcp;
+MXF::MXF (Fraction edit_rate)
+ : Content (edit_rate)
+ , _progress (0)
+ , _encryption_context (0)
+ , _decryption_context (0)
+{
+
+}
+
MXF::MXF (boost::filesystem::path file)
: Content (file)
, _progress (0)
, _encryption_context (0)
, _decryption_context (0)
- , _interop (false)
{
}
}
void
-MXF::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;
return true;
}
-void
-MXF::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:" + _id);
- a->add_child ("AnnotationText")->add_child_text (_file.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
MXF::set_key (Key key)
{
#ifndef LIBDCP_MXF_ASSET_H
#define LIBDCP_MXF_ASSET_H
-#include <boost/signals2.hpp>
#include "content.h"
#include "key.h"
#include "metadata.h"
+#include <boost/signals2.hpp>
namespace ASDCP {
class AESEncContext;
class MXF : public Content
{
public:
+ MXF (Fraction edit_rate);
MXF (boost::filesystem::path file);
- MXF (int edit_rate);
~MXF ();
virtual bool equals (boost::shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
- virtual void write_to_cpl (xmlpp::Element *) const;
virtual std::string key_type () const = 0;
+
+ std::string pkl_type () const {
+ return "application/x-smpte-mxf";
+ }
/** 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 fill_writer_info (ASDCP::WriterInfo* w, Standard standard);
void set_progress (boost::signals2::signal<void (float)>* progress) {
_progress = progress;
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 ("", "");
- }
-
/** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
ASDCP::AESEncContext* _encryption_context;
std::string _key_id;
boost::optional<Key> _key;
MXFMetadata _metadata;
- bool _interop;
};
}
--- /dev/null
+/*
+ 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 "mxf.h"
+
+using namespace dcp;
+
+MXFWriter::MXFWriter (MXF* mxf, boost::filesystem::path file)
+ : _mxf (mxf)
+ , _file (file)
+ , _frames_written (0)
+ , _finalized (false)
+{
+ mxf->_file = file;
+ mxf->_hash.clear ();
+}
+
+MXFWriter::~MXFWriter ()
+{
+ assert (_finalized);
+}
+
+void
+MXFWriter::finalize ()
+{
+ assert (!_finalized);
+ _finalized = true;
+ _mxf->_intrinsic_duration = _frames_written;
+}
--- /dev/null
+/*
+ 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_MXF_WRITER_H
+#define LIBDCP_MXF_WRITER_H
+
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class MXF;
+
+class MXFWriter : public boost::noncopyable
+{
+public:
+ virtual ~MXFWriter ();
+ virtual void finalize ();
+
+protected:
+ MXFWriter (MXF* mxf, boost::filesystem::path file);
+
+ MXF* _mxf;
+ boost::filesystem::path _file;
+ int64_t _frames_written;
+ bool _finalized;
+};
+
+}
+
+#endif
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 to use.
+ */
Object::Object (string id)
: _id (id)
{
namespace dcp {
-/** Some part of a DCP that has a UUID */
+/** @class Object
+ * @brief Some part of a DCP that has a UUID.
+ */
class Object
{
public:
Object (std::string id);
virtual ~Object () {}
+ /** @return ID */
std::string id () const {
return _id;
}
protected:
+ /** ID */
std::string _id;
};
+++ /dev/null
-/*
- 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 dcp::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> ();
-}
+++ /dev/null
-/*
- 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 dcp {
-
-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;
-};
-
-}
-
-}
+++ /dev/null
-/*
- 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 dcp::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 ();
-}
+++ /dev/null
-/*
- 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 dcp {
-
-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;
-};
-
-}
-
-}
-
+++ /dev/null
-/*
- 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 dcp::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 ("");
-}
+++ /dev/null
-/*
- 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/pkl.h
- * @brief Classes used to parse a PKL
- */
-
-#include <boost/shared_ptr.hpp>
-#include "../xml.h"
-
-namespace dcp {
-
-namespace parse {
-
-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 PKL
-{
-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;
-};
-
-}
-
-}
+++ /dev/null
-/*
- 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 <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-#include "subtitle.h"
-#include "../types.h"
-
-using std::string;
-using std::list;
-using boost::shared_ptr;
-using boost::optional;
-using boost::lexical_cast;
-using namespace dcp;
-using namespace dcp::parse;
-
-Font::Font (shared_ptr<const cxml::Node> node)
-{
- text = node->content ();
-
- id = node->optional_string_attribute ("Id").get_value_or ("");
- size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0);
- italic = node->optional_bool_attribute ("Italic");
- optional<string> c = node->optional_string_attribute ("Color");
- if (c) {
- color = Color (c.get ());
- }
- optional<string> const e = node->optional_string_attribute ("Effect");
- if (e) {
- effect = string_to_effect (e.get ());
- }
- c = node->optional_string_attribute ( "EffectColor");
- if (c) {
- effect_color = Color (c.get ());
- }
- subtitle_nodes = type_children<Subtitle> (node, "Subtitle");
- font_nodes = type_children<Font> (node, "Font");
- text_nodes = type_children<Text> (node, "Text");
-}
-
-Font::Font (list<shared_ptr<Font> > const & font_nodes)
- : size (0)
- , italic (false)
- , color ("FFFFFFFF")
- , effect_color ("FFFFFFFF")
-{
- for (list<shared_ptr<Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
- if (!(*i)->id.empty ()) {
- id = (*i)->id;
- }
- if ((*i)->size != 0) {
- size = (*i)->size;
- }
- if ((*i)->italic) {
- italic = (*i)->italic.get ();
- }
- if ((*i)->color) {
- color = (*i)->color.get ();
- }
- if ((*i)->effect) {
- effect = (*i)->effect.get ();
- }
- if ((*i)->effect_color) {
- effect_color = (*i)->effect_color.get ();
- }
- }
-}
-
-LoadFont::LoadFont (shared_ptr<const cxml::Node> node)
-{
- id = node->string_attribute ("Id");
- uri = node->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)
-{
- 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");
-}
-
+++ /dev/null
-/*
- 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.
-
-*/
-
-#include "../xml.h"
-#include "../dcp_time.h"
-#include "../types.h"
-
-namespace dcp
-{
-
-namespace parse
-{
-
-class Font;
-
-class Text
-{
-public:
- 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;
-};
-
-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:
- Font ()
- : size (0)
- {}
-
- Font (boost::shared_ptr<const cxml::Node> node);
- Font (std::list<boost::shared_ptr<Font> > const & font_nodes);
-
- std::string text;
- std::string id;
- int size;
- boost::optional<bool> italic;
- boost::optional<Color> color;
- boost::optional<Effect> effect;
- boost::optional<Color> effect_color;
-
- std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
- std::list<boost::shared_ptr<Font> > font_nodes;
- std::list<boost::shared_ptr<Text> > text_nodes;
-};
-
-class LoadFont
-{
-public:
- LoadFont () {}
- LoadFont (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string uri;
-};
-
-}
-
-}
*/
-/** @file src/picture_asset.cc
- * @brief An asset made up of JPEG2000 files
- */
-
#include <list>
#include <stdexcept>
#include <iostream>
}
-PictureMXF::PictureMXF (int edit_rate)
+PictureMXF::PictureMXF (Fraction edit_rate)
: MXF (edit_rate)
{
}
void
-PictureMXF::write_to_cpl (xmlpp::Element* node) const
+PictureMXF::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
{
- MXF::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));
- }
+ _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
{
return "MDIK";
}
-
-
-
{
public:
PictureMXF (boost::filesystem::path file);
- PictureMXF (int edit_rate);
+ PictureMXF (Fraction edit_rate);
- virtual boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, bool overwrite) = 0;
+ virtual boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, Standard standard, bool overwrite) = 0;
+
+ void write_to_pkl (xmlpp::Node* node) const;
Size size () const {
return _size;
}
- void set_size (Size s) {
- _size = s;
+ Fraction frame_rate () const {
+ return _frame_rate;
}
- void write_to_cpl (xmlpp::Element *) const;
+ Fraction screen_aspect_ratio () const {
+ return _screen_aspect_ratio;
+ }
+
+ Fraction edit_rate () const {
+ return _edit_rate;
+ }
protected:
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;
/*
- 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
*/
-#include <inttypes.h>
-#include <stdint.h>
-#include "AS_DCP.h"
#include "KM_fileio.h"
#include "picture_mxf_writer.h"
#include "exceptions.h"
#include "picture_mxf.h"
+#include "AS_DCP.h"
+#include <inttypes.h>
+#include <stdint.h>
using std::istream;
using std::ostream;
#endif
}
-
-PictureMXFWriter::PictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, bool overwrite)
- : _mxf (mxf)
- , _file (file)
- , _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)
{
-
+
}
/*
- 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
*/
+#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 dcp {
std::string hash;
};
-class PictureMXFWriter : public boost::noncopyable
+class PictureMXFWriter : public MXFWriter
{
public:
- virtual ~PictureMXFWriter () {}
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 (PictureMXFWriter *, boost::shared_ptr<P>, Q *, uint8_t *, int);
-
- PictureMXFWriter (PictureMXF *, boost::filesystem::path, bool);
+ friend void start (PictureMXFWriter *, boost::shared_ptr<P>, Standard, Q *, uint8_t *, int);
- PictureMXF* _mxf;
+ PictureMXFWriter (PictureMXF *, boost::filesystem::path, Standard standard, bool);
- boost::filesystem::path _file;
- /** 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;
};
};
template <class P, class Q>
-void dcp::start (PictureMXFWriter* writer, shared_ptr<P> state, Q* mxf, 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);
}
state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
- state->picture_descriptor.EditRate = ASDCP::Rational (mxf->edit_rate(), 1);
+ state->picture_descriptor.EditRate = ASDCP::Rational (mxf->edit_rate().numerator, mxf->edit_rate().denominator);
- mxf->fill_writer_info (&state->writer_info);
+ mxf->fill_writer_info (&state->writer_info, standard);
Kumu::Result_t r = state->mxf_writer.OpenWrite (
mxf->file().string().c_str(),
*/
-#include <libxml++/nodes/element.h>
#include "reel.h"
#include "util.h"
#include "picture_mxf.h"
#include "mono_picture_mxf.h"
#include "stereo_picture_mxf.h"
#include "sound_mxf.h"
-#include "subtitle_asset.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 boost::dynamic_pointer_cast;
using namespace dcp;
+Reel::Reel (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());
if (_main_picture && dynamic_pointer_cast<MonoPictureMXF> (_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<StereoPictureMXF> (_main_picture)) {
/* ... but stereo pictures must come after */
- _main_picture->write_to_cpl (asset_list);
+ _main_picture->write_to_cpl (asset_list, standard);
}
}
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 ());
}
}
}
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;
+ }
+}
#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 dcp {
-class PictureMXF;
-class SoundMXF;
-class SubtitleAsset;
-class KDM;
+class KDM;
+class ReelAsset;
+class ReelPictureAsset;
+class ReelSoundAsset;
+class ReelSubtitleAsset;
/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */
-class Reel
+class Reel : public Object
{
public:
+ Reel () {}
+
Reel (
- boost::shared_ptr<PictureMXF> picture,
- boost::shared_ptr<SoundMXF> 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 PictureMXF> main_picture () const {
+ boost::shared_ptr<ReelPictureAsset> main_picture () const {
return _main_picture;
}
- boost::shared_ptr<const SoundMXF> 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 add_kdm (KDM const &);
private:
- boost::shared_ptr<PictureMXF> _main_picture;
- boost::shared_ptr<SoundMXF> _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;
};
}
--- /dev/null
+/*
+ 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)
+{
+
+}
+
+ReelAsset::ReelAsset (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))
+{
+
+}
+
+ReelAsset::ReelAsset (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->string_child ("Hash"))
+ , _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);
+ }
+
+ node->done ();
+}
+
+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 ("", "");
+}
--- /dev/null
+/*
+ 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 : public Object
+{
+public:
+ ReelAsset ();
+ ReelAsset (boost::shared_ptr<Content> content, int64_t entry_point);
+ ReelAsset (boost::shared_ptr<const cxml::Node>);
+
+ Ref<Content> content () const {
+ return _content;
+ }
+
+ bool encrypted () const {
+ return !_key_id.empty ();
+ }
+
+ std::string key_id () const {
+ return _key_id;
+ }
+
+ 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;
+ }
+
+protected:
+ virtual std::string cpl_node_name () const = 0;
+ virtual std::pair<std::string, std::string> cpl_node_attribute () const;
+
+ Ref<Content> _content;
+
+private:
+ std::string _annotation_text;
+ Fraction _edit_rate;
+ int64_t _intrinsic_duration;
+ int64_t _entry_point;
+ int64_t _duration;
+ std::string _hash;
+ std::string _key_id;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ 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_mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelMonoPictureAsset::ReelMonoPictureAsset ()
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (shared_ptr<MonoPictureMXF> mxf, int64_t entry_point)
+ : ReelPictureAsset (mxf, entry_point)
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+
+}
+
+string
+ReelMonoPictureAsset::cpl_node_name () const
+{
+ return "MainPicture";
+}
+
--- /dev/null
+/*
+ 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_picture_asset.h"
+
+namespace dcp {
+
+class MonoPictureMXF;
+
+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;
+};
+
+}
+
+
+
--- /dev/null
+/*
+ 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 "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 boost::lexical_cast;
+using namespace dcp;
+
+ReelPictureAsset::ReelPictureAsset ()
+ : _frame_rate (Fraction (24, 1))
+ , _screen_aspect_ratio (Fraction (1998, 1080))
+{
+
+}
+
+ReelPictureAsset::ReelPictureAsset (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 (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)
+ );
+ }
+}
--- /dev/null
+/*
+ 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_PICTURE_ASSET_H
+#define LIBDCP_REEL_PICTURE_ASSET_H
+
+#include "reel_asset.h"
+#include "picture_mxf.h"
+
+namespace dcp {
+
+class ReelPictureAsset : public ReelAsset
+{
+public:
+ ReelPictureAsset ();
+ ReelPictureAsset (boost::shared_ptr<PictureMXF> content, int64_t entry_point);
+ ReelPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<PictureMXF> mxf () {
+ return boost::dynamic_pointer_cast<PictureMXF> (_content.object ());
+ }
+
+ void set_screen_aspect_ratio (Fraction a) {
+ _screen_aspect_ratio = a;
+ }
+
+ virtual void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
+private:
+ Fraction _frame_rate;
+ Fraction _screen_aspect_ratio;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ 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_sound_asset.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSoundAsset::ReelSoundAsset (shared_ptr<Content> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSoundAsset::ReelSoundAsset (shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSoundAsset::cpl_node_name () const
+{
+ return "MainSound";
+}
--- /dev/null
+/*
+ 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 "sound_mxf.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+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 ());
+ }
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
--- /dev/null
+/*
+ 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_stereo_picture_asset.h"
+
+using std::string;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelStereoPictureAsset::ReelStereoPictureAsset (shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+
+}
+
+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 ("", "");
+}
--- /dev/null
+/*
+ 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_picture_asset.h"
+
+namespace dcp {
+
+class ReelStereoPictureAsset : public ReelPictureAsset
+{
+public:
+ 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;
+};
+
+}
+
+
+
--- /dev/null
+/*
+ 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_content.h"
+#include "reel_subtitle_asset.h"
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSubtitleAsset::ReelSubtitleAsset (shared_ptr<SubtitleContent> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSubtitleAsset::ReelSubtitleAsset (shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSubtitleAsset::cpl_node_name () const
+{
+ return "MainSubtitle";
+}
--- /dev/null
+/*
+ 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.
+
+*/
+
+#include "reel_asset.h"
+
+namespace dcp {
+
+class SubtitleContent;
+
+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;
+};
+
+}
--- /dev/null
+/*
+ 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_REF_H
+#define LIBDCP_REF_H
+
+#include "exceptions.h"
+#include "object.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+template<class T>
+class Ref
+{
+public:
+ Ref (std::string id)
+ : _id (id)
+ {}
+
+ Ref (boost::shared_ptr<T> object)
+ : _id (object->id ())
+ , _object (object)
+ {}
+
+ void set_id (std::string id)
+ {
+ _id = id;
+ }
+
+ 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);
+ }
+ }
+
+ std::string id () const {
+ return _id;
+ }
+
+ boost::shared_ptr<T> object () const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object;
+ }
+
+ T * operator->() const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object.get ();
+ }
+
+ bool resolved () const {
+ return _object;
+ }
+
+private:
+ std::string _id;
+ boost::shared_ptr<T> _object;
+};
+
+}
+
+#endif
/*
- 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
*/
+/** @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 boost::shared_ptr;
using namespace dcp;
-/** @param signer_key Filename of private key to sign with */
+/** Add a <Signer> and <ds:Signature> nodes to an XML node.
+ * @param parent XML node to add to.
+ * @param interop true to use Interop standards, false for 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");
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());
- }
-}
*/
-#include <boost/filesystem.hpp>
+/** @file src/signer.h
+ * @brief Signer class.
+ */
+
#include "certificates.h"
+#include "types.h"
+#include <boost/filesystem.hpp>
namespace xmlpp {
class Element;
namespace dcp {
+/** @class Signer
+ * @brief A class which can sign XML files.
+ */
class Signer
{
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 {
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;
#include "util.h"
#include "exceptions.h"
#include "sound_frame.h"
+#include "sound_mxf_writer.h"
using std::string;
using std::stringstream;
_sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
_channels = desc.ChannelCount;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+
_intrinsic_duration = desc.ContainerDuration;
}
-string
-SoundMXF::cpl_node_name () const
+SoundMXF::SoundMXF (Fraction edit_rate, int sampling_rate, int channels)
+ : MXF (edit_rate)
+ , _channels (channels)
+ , _sampling_rate (sampling_rate)
{
- return "MainSound";
+
}
bool
}
shared_ptr<SoundMXFWriter>
-SoundMXF::start_write ()
+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));
-}
-
-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* a)
- : _state (new SoundMXFWriter::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->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", _asset->file().string(), r));
- }
-}
-
-void
-SoundMXFWriter::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
-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 ("could not write audio MXF frame (" + lexical_cast<string> (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"));
- }
-
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written);
- _asset->set_duration (_frames_written);
+ return shared_ptr<SoundMXFWriter> (new SoundMXFWriter (this, file, standard));
}
string
/*
- 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
*/
-#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
- */
+#ifndef LIBDCP_SOUND_MXF_H
+#define LIBDCP_SOUND_MXF_H
#include "mxf.h"
#include "types.h"
{
class SoundFrame;
-class SoundMXF;
-
-class SoundMXFWriter
-{
-public:
- void write (float const * const *, int);
- void finalize ();
-
-private:
- friend class SoundMXF;
-
- SoundMXFWriter (SoundMXF *);
-
- /* no copy construction */
- SoundMXFWriter (SoundMXFWriter const &);
- SoundMXFWriter& operator= (SoundMXFWriter 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;
-
- SoundMXF* _asset;
- bool _finalized;
- int _frames_written;
- int _frame_buffer_offset;
-};
+class SoundMXFWriter;
-/** @brief An asset made up of WAV files */
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::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;
private:
std::string key_type () const;
- std::string cpl_node_name () const;
/** Number of channels in the asset */
int _channels;
--- /dev/null
+/*
+ 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"
+#include <boost/lexical_cast.hpp>
+
+using boost::lexical_cast;
+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 ();
+}
--- /dev/null
+/*
+ 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;
+};
+
+}
+
* @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 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
using boost::dynamic_pointer_cast;
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);
+}
+
+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));
+}
+
+int
+StereoPictureMXF::edit_rate_factor () const
+{
+ return 2;
+}
+
bool
StereoPictureMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
return true;
}
-
-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"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
-}
-
-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, bool overwrite)
-{
- return shared_ptr<StereoPictureMXFWriter> (new StereoPictureMXFWriter (this, file, overwrite));
-}
-
-string
-StereoPictureMXF::cpl_node_name () const
-{
- return "msp-cpl:MainStereoscopicPicture";
-}
-
-pair<string, string>
-StereoPictureMXF::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
-StereoPictureMXF::edit_rate_factor () const
-{
- return 2;
-}
{
public:
StereoPictureMXF (boost::filesystem::path file);
+ StereoPictureMXF (Fraction edit_rate);
/** Start a progressive write to a StereoPictureMXF */
- boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, bool);
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, Standard, bool);
boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
bool equals (boost::shared_ptr<const Content> 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;
};
ASDCP::JP2K::MXFSWriter mxf_writer;
};
-StereoPictureMXFWriter::StereoPictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, bool overwrite)
- : PictureMXFWriter (mxf, file, overwrite)
+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)
{
void
StereoPictureMXFWriter::start (uint8_t* data, int size)
{
- dcp::start (this, _state, _mxf, data, size);
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
}
/** Write a frame for one eye. Frames must be written left, then right, then left etc.
_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);
}
}
_next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
- ++_frames_written;
+ if (_next_eye == EYE_LEFT) {
+ ++_frames_written;
+ }
}
void
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", _mxf->file().string(), r));
}
- _finalized = true;
- _mxf->set_intrinsic_duration (_frames_written / 2);
- _mxf->set_duration (_frames_written / 2);
+ PictureMXFWriter::finalize ();
}
*/
+#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_mxf_writer.h"
namespace dcp {
private:
friend class StereoPictureMXF;
- StereoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, 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
--- /dev/null
+/*
+ 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 (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;
+}
--- /dev/null
+/*
+ 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_H
+#define LIBDCP_SUBTITLE_H
+
+#include "dcp_time.h"
+#include <boost/shared_ptr.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font;
+class Text;
+
+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);
+};
+
+}
+
+#endif
+++ /dev/null
-/*
- 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.
-
-*/
-
-#include <fstream>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <libxml++/nodes/element.h>
-#include "subtitle_asset.h"
-#include "parse/subtitle.h"
-#include "util.h"
-#include "xml.h"
-
-using std::string;
-using std::list;
-using std::ostream;
-using std::ofstream;
-using std::stringstream;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using boost::optional;
-using namespace dcp;
-
-SubtitleAsset::SubtitleAsset (boost::filesystem::path file)
- : Content (file)
- , _need_sort (false)
-{
- shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
- xml->read_file (file);
-
- _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<dcp::parse::Font> > font_nodes = type_children<dcp::parse::Font> (xml, "Font");
- _load_font_nodes = type_children<dcp::parse::LoadFont> (xml, "LoadFont");
-
- /* Now make Subtitle objects to represent the raw XML nodes
- in a sane way.
- */
-
- ParseState parse_state;
- examine_font_nodes (xml, font_nodes, parse_state);
-}
-
-SubtitleAsset::SubtitleAsset (string directory, string movie_title, string language)
- : Content (directory)
- , _movie_title (movie_title)
- , _reel_number ("1")
- , _language (language)
- , _need_sort (false)
-{
-
-}
-
-void
-SubtitleAsset::examine_font_nodes (
- shared_ptr<const cxml::Node> xml,
- list<shared_ptr<dcp::parse::Font> > const & font_nodes,
- ParseState& parse_state
- )
-{
- for (list<shared_ptr<dcp::parse::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<dcp::parse::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);
- parse_state.subtitle_nodes.pop_back ();
- }
-
- examine_font_nodes (xml, (*i)->font_nodes, parse_state);
- examine_text_nodes (xml, (*i)->text_nodes, parse_state);
-
- parse_state.font_nodes.pop_back ();
- }
-}
-
-void
-SubtitleAsset::examine_text_nodes (
- shared_ptr<const cxml::Node> xml,
- list<shared_ptr<dcp::parse::Text> > const & text_nodes,
- ParseState& parse_state
- )
-{
- for (list<shared_ptr<dcp::parse::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);
- parse_state.text_nodes.pop_back ();
- }
-}
-
-void
-SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state)
-{
- if (empty_or_white_space (text)) {
- return;
- }
-
- if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
- return;
- }
-
- assert (!parse_state.text_nodes.empty ());
- assert (!parse_state.subtitle_nodes.empty ());
-
- dcp::parse::Font effective_font (parse_state.font_nodes);
- dcp::parse::Text effective_text (*parse_state.text_nodes.back ());
- dcp::parse::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
-
- _subtitles.push_back (
- shared_ptr<Subtitle> (
- new Subtitle (
- font_id_to_name (effective_font.id),
- effective_font.italic.get(),
- effective_font.color.get(),
- effective_font.size,
- effective_subtitle.in,
- effective_subtitle.out,
- effective_text.v_position,
- effective_text.v_align,
- text,
- effective_font.effect ? effective_font.effect.get() : NONE,
- effective_font.effect_color.get(),
- effective_subtitle.fade_up_time,
- effective_subtitle.fade_down_time
- )
- )
- );
-}
-
-list<shared_ptr<Subtitle> >
-SubtitleAsset::subtitles_at (Time t) const
-{
- list<shared_ptr<Subtitle> > s;
- for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
- if ((*i)->in() <= t && t <= (*i)->out ()) {
- s.push_back (*i);
- }
- }
-
- return s;
-}
-
-std::string
-SubtitleAsset::font_id_to_name (string id) const
-{
- list<shared_ptr<dcp::parse::LoadFont> >::const_iterator i = _load_font_nodes.begin();
- while (i != _load_font_nodes.end() && (*i)->id != id) {
- ++i;
- }
-
- if (i == _load_font_nodes.end ()) {
- return "";
- }
-
- 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
-dcp::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&
-dcp::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)
-{
- _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:" + _id);
- ms->add_child("AnnotationText")->add_child_text (_file.string ());
- /* XXX */
- ms->add_child("EntryPoint")->add_child_text ("0");
-}
-
-struct SubtitleSorter {
- bool operator() (shared_ptr<Subtitle> a, shared_ptr<Subtitle> b) {
- if (a->in() != b->in()) {
- return a->in() < b->in();
- }
- return a->v_position() < b->v_position();
- }
-};
-
-void
-SubtitleAsset::write_xml () const
-{
- 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
-{
- xmlpp::Document doc;
- xmlpp::Element* root = doc.create_root_node ("DCSubtitle");
- root->set_attribute ("Version", "1.0");
-
- 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);
-
- if (_load_font_nodes.size() > 1) {
- boost::throw_exception (MiscError ("multiple LoadFont nodes not supported"));
- }
-
- if (!_load_font_nodes.empty ()) {
- xmlpp::Element* load_font = root->add_child("LoadFont");
- load_font->set_attribute("Id", _load_font_nodes.front()->id);
- load_font->set_attribute("URI", _load_font_nodes.front()->uri);
- }
-
- list<shared_ptr<Subtitle> > sorted = _subtitles;
- if (_need_sort) {
- sorted.sort (SubtitleSorter ());
- }
-
- /* XXX: multiple fonts not supported */
- /* XXX: script, underlined, weight not supported */
-
- bool italic = false;
- Color color;
- int size = 0;
- Effect effect = NONE;
- Color effect_color;
- int spot_number = 1;
- Time last_in;
- Time last_out;
- Time last_fade_up_time;
- Time last_fade_down_time;
-
- xmlpp::Element* font = 0;
- xmlpp::Element* subtitle = 0;
-
- for (list<shared_ptr<Subtitle> >::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
- that seems hard.
- */
-
- bool const font_changed =
- italic != (*i)->italic() ||
- color != (*i)->color() ||
- size != (*i)->size() ||
- effect != (*i)->effect() ||
- effect_color != (*i)->effect_color();
-
- if (font_changed) {
- italic = (*i)->italic ();
- color = (*i)->color ();
- size = (*i)->size ();
- effect = (*i)->effect ();
- effect_color = (*i)->effect_color ();
- }
-
- if (!font || font_changed) {
- font = root->add_child ("Font");
- string id = "theFontId";
- if (!_load_font_nodes.empty()) {
- id = _load_font_nodes.front()->id;
- }
- font->set_attribute ("Id", id);
- font->set_attribute ("Italic", italic ? "yes" : "no");
- font->set_attribute ("Color", color.to_argb_string());
- font->set_attribute ("Size", lexical_cast<string> (size));
- font->set_attribute ("Effect", effect_to_string (effect));
- font->set_attribute ("EffectColor", effect_color.to_argb_string());
- font->set_attribute ("Script", "normal");
- font->set_attribute ("Underlined", "no");
- font->set_attribute ("Weight", "normal");
- }
-
- if (!subtitle || font_changed ||
- (last_in != (*i)->in() ||
- last_out != (*i)->out() ||
- last_fade_up_time != (*i)->fade_up_time() ||
- last_fade_down_time != (*i)->fade_down_time()
- )) {
-
- subtitle = font->add_child ("Subtitle");
- subtitle->set_attribute ("SpotNumber", lexical_cast<string> (spot_number++));
- subtitle->set_attribute ("TimeIn", (*i)->in().to_string());
- subtitle->set_attribute ("TimeOut", (*i)->out().to_string());
- subtitle->set_attribute ("FadeUpTime", lexical_cast<string> ((*i)->fade_up_time().to_ticks()));
- subtitle->set_attribute ("FadeDownTime", lexical_cast<string> ((*i)->fade_down_time().to_ticks()));
-
- last_in = (*i)->in ();
- last_out = (*i)->out ();
- last_fade_up_time = (*i)->fade_up_time ();
- last_fade_down_time = (*i)->fade_down_time ();
- }
-
- xmlpp::Element* text = subtitle->add_child ("Text");
- text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
- text->set_attribute ("VPosition", lexical_cast<string> ((*i)->v_position()));
- text->add_child_text ((*i)->text());
- }
-
- return doc.write_to_string_formatted ("UTF-8");
-}
-
+++ /dev/null
-/*
- 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 "content.h"
-#include "dcp_time.h"
-
-namespace dcp
-{
-
-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 Content
-{
-public:
- SubtitleAsset (boost::filesystem::path 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 Content>, 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 write_xml () const;
- Glib::ustring xml_as_string () const;
-
-private:
- std::string font_id_to_name (std::string id) const;
-
- 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
- );
-
- 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
--- /dev/null
+/*
+ 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_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;
+using std::ostream;
+using std::ofstream;
+using std::stringstream;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using boost::optional;
+using namespace dcp;
+
+SubtitleContent::SubtitleContent (boost::filesystem::path file)
+ : Content (file)
+ , _need_sort (false)
+{
+ shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
+ xml->read_file (file);
+
+ _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<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.
+ */
+
+ 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
+SubtitleContent::examine_font_nodes (
+ shared_ptr<const cxml::Node> xml,
+ list<shared_ptr<dcp::Font> > const & font_nodes,
+ ParseState& parse_state
+ )
+{
+ 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<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);
+ parse_state.subtitle_nodes.pop_back ();
+ }
+
+ examine_font_nodes (xml, (*i)->font_nodes, parse_state);
+ examine_text_nodes (xml, (*i)->text_nodes, parse_state);
+
+ parse_state.font_nodes.pop_back ();
+ }
+}
+
+void
+SubtitleContent::examine_text_nodes (
+ shared_ptr<const cxml::Node> xml,
+ list<shared_ptr<dcp::Text> > const & text_nodes,
+ ParseState& parse_state
+ )
+{
+ 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);
+ parse_state.text_nodes.pop_back ();
+ }
+}
+
+void
+SubtitleContent::maybe_add_subtitle (string text, ParseState const & parse_state)
+{
+ if (empty_or_white_space (text)) {
+ return;
+ }
+
+ if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
+ return;
+ }
+
+ assert (!parse_state.text_nodes.empty ());
+ assert (!parse_state.subtitle_nodes.empty ());
+
+ 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<SubtitleString> (
+ new SubtitleString (
+ font_id_to_name (effective_font.id),
+ effective_font.italic.get(),
+ effective_font.color.get(),
+ effective_font.size,
+ effective_subtitle.in,
+ effective_subtitle.out,
+ effective_text.v_position,
+ effective_text.v_align,
+ text,
+ effective_font.effect ? effective_font.effect.get() : NONE,
+ effective_font.effect_color.get(),
+ effective_subtitle.fade_up_time,
+ effective_subtitle.fade_down_time
+ )
+ )
+ );
+}
+
+list<shared_ptr<SubtitleString> >
+SubtitleContent::subtitles_at (Time t) const
+{
+ 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);
+ }
+ }
+
+ return s;
+}
+
+std::string
+SubtitleContent::font_id_to_name (string id) const
+{
+ list<shared_ptr<dcp::LoadFont> >::const_iterator i = _load_font_nodes.begin();
+ while (i != _load_font_nodes.end() && (*i)->id != id) {
+ ++i;
+ }
+
+ if (i == _load_font_nodes.end ()) {
+ return "";
+ }
+
+ if ((*i)->uri == "arial.ttf") {
+ return "Arial";
+ }
+
+ return "";
+}
+
+void
+SubtitleContent::add (shared_ptr<SubtitleString> s)
+{
+ _subtitles.push_back (s);
+ _need_sort = true;
+}
+
+struct SubtitleSorter {
+ bool operator() (shared_ptr<SubtitleString> a, shared_ptr<SubtitleString> b) {
+ if (a->in() != b->in()) {
+ return a->in() < b->in();
+ }
+ return a->v_position() < b->v_position();
+ }
+};
+
+void
+SubtitleContent::write_xml () const
+{
+ 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
+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 (_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);
+
+ if (_load_font_nodes.size() > 1) {
+ boost::throw_exception (MiscError ("multiple LoadFont nodes not supported"));
+ }
+
+ if (!_load_font_nodes.empty ()) {
+ xmlpp::Element* load_font = root->add_child("LoadFont");
+ load_font->set_attribute("Id", _load_font_nodes.front()->id);
+ load_font->set_attribute("URI", _load_font_nodes.front()->uri);
+ }
+
+ list<shared_ptr<SubtitleString> > sorted = _subtitles;
+ if (_need_sort) {
+ sorted.sort (SubtitleSorter ());
+ }
+
+ /* XXX: multiple fonts not supported */
+ /* XXX: script, underlined, weight not supported */
+
+ bool italic = false;
+ Color color;
+ int size = 0;
+ Effect effect = NONE;
+ Color effect_color;
+ int spot_number = 1;
+ Time last_in;
+ Time last_out;
+ Time last_fade_up_time;
+ Time last_fade_down_time;
+
+ xmlpp::Element* font = 0;
+ xmlpp::Element* subtitle = 0;
+
+ 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
+ that seems hard.
+ */
+
+ bool const font_changed =
+ italic != (*i)->italic() ||
+ color != (*i)->color() ||
+ size != (*i)->size() ||
+ effect != (*i)->effect() ||
+ effect_color != (*i)->effect_color();
+
+ if (font_changed) {
+ italic = (*i)->italic ();
+ color = (*i)->color ();
+ size = (*i)->size ();
+ effect = (*i)->effect ();
+ effect_color = (*i)->effect_color ();
+ }
+
+ if (!font || font_changed) {
+ font = root->add_child ("Font");
+ string id = "theFontId";
+ if (!_load_font_nodes.empty()) {
+ id = _load_font_nodes.front()->id;
+ }
+ font->set_attribute ("Id", id);
+ font->set_attribute ("Italic", italic ? "yes" : "no");
+ font->set_attribute ("Color", color.to_argb_string());
+ font->set_attribute ("Size", lexical_cast<string> (size));
+ font->set_attribute ("Effect", effect_to_string (effect));
+ font->set_attribute ("EffectColor", effect_color.to_argb_string());
+ font->set_attribute ("Script", "normal");
+ font->set_attribute ("Underlined", "no");
+ font->set_attribute ("Weight", "normal");
+ }
+
+ if (!subtitle || font_changed ||
+ (last_in != (*i)->in() ||
+ last_out != (*i)->out() ||
+ last_fade_up_time != (*i)->fade_up_time() ||
+ last_fade_down_time != (*i)->fade_down_time()
+ )) {
+
+ subtitle = font->add_child ("Subtitle");
+ subtitle->set_attribute ("SpotNumber", lexical_cast<string> (spot_number++));
+ subtitle->set_attribute ("TimeIn", (*i)->in().to_string());
+ subtitle->set_attribute ("TimeOut", (*i)->out().to_string());
+ subtitle->set_attribute ("FadeUpTime", lexical_cast<string> ((*i)->fade_up_time().to_ticks()));
+ subtitle->set_attribute ("FadeDownTime", lexical_cast<string> ((*i)->fade_down_time().to_ticks()));
+
+ last_in = (*i)->in ();
+ last_out = (*i)->out ();
+ last_fade_up_time = (*i)->fade_up_time ();
+ last_fade_down_time = (*i)->fade_down_time ();
+ }
+
+ xmlpp::Element* text = subtitle->add_child ("Text");
+ text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
+ text->set_attribute ("VPosition", lexical_cast<string> ((*i)->v_position()));
+ text->add_child_text ((*i)->text());
+ }
+
+ return doc.write_to_string_formatted ("UTF-8");
+}
+
--- /dev/null
+/*
+ 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);
+
+ std::string pkl_type () const {
+ return "text/xml";
+ }
+
+ virtual 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;
+
+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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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 "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);
+
+}
--- /dev/null
+/*
+ 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 "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;
+
+Text::Text (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");
+}
--- /dev/null
+/*
+ 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 <boost/shared_ptr.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font;
+
+class Text
+{
+public:
+ 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;
+};
+
+}
: 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)
{}
double max_mean_pixel_error;
double max_std_dev_pixel_error;
int max_audio_sample_error;
- bool cpl_names_can_differ;
+ bool cpl_annotation_texts_can_differ;
bool mxf_names_can_differ;
};
NOTE
};
+enum Standard {
+ INTEROP,
+ SMPTE
+};
+
/** @class Color
* @brief An RGB color (aka colour).
*/
* @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"
#include "certificates.h"
#include "gamma_lut.h"
#include "xyz_frame.h"
+#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 <boost/lexical_cast.hpp>
+#include <stdexcept>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
using std::string;
using std::wstring;
* @return Digest.
*/
string
-dcp::make_digest (string filename, boost::function<void (float)>* progress)
+dcp::make_digest (boost::filesystem::path filename, boost::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));
}
extern bool operator!= (Size const & a, Size const & b);
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);
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);
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_mxf.cc
mono_picture_mxf_writer.cc
mono_picture_frame.cc
mxf.cc
+ mxf_writer.cc
object.cc
picture_mxf.cc
picture_mxf_writer.cc
rec709_linearised_gamma_lut.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_mxf.cc
+ sound_mxf_writer.cc
sound_frame.cc
srgb_linearised_gamma_lut.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 = """
+++ /dev/null
-/*
- 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 <boost/test/unit_test.hpp>
-#include <libcxml/cxml.h>
-#include "cpl.h"
-#include "mono_picture_mxf.h"
-
-using boost::shared_ptr;
-
-/* Test for a reported bug where <ScreenAspectRatio> in Interop files uses
- excessive decimal places and (sometimes) the wrong decimal point character.
-*/
-BOOST_AUTO_TEST_CASE (cpl_sar)
-{
- shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF ("build/test/foo/video.mxf"));
- mp->set_interop (true);
-
- {
- mp->set_size (dcp::Size (1998, 1080));
- xmlpp::Document doc;
- xmlpp::Element* el = doc.create_root_node ("Test");
- mp->write_to_cpl (el);
-
- cxml::Node node (el);
- BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "1.85");
- }
-
- {
- mp->set_size (dcp::Size (2048, 858));
- xmlpp::Document doc;
- xmlpp::Element* el = doc.create_root_node ("Test");
- mp->write_to_cpl (el);
-
- cxml::Node node (el);
- BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
- }
-}
--- /dev/null
+/*
+ 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 "cpl.h"
+#include "reel_mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+#include <libcxml/cxml.h>
+#include <boost/test/unit_test.hpp>
+
+using boost::shared_ptr;
+
+/* Test for a reported bug where <ScreenAspectRatio> in Interop files uses
+ excessive decimal places and (sometimes) the wrong decimal point character.
+*/
+BOOST_AUTO_TEST_CASE (cpl_sar)
+{
+ shared_ptr<dcp::ReelMonoPictureAsset> pa (new dcp::ReelMonoPictureAsset ());
+
+ {
+ pa->set_screen_aspect_ratio (dcp::Fraction (1998, 1080));
+ xmlpp::Document doc;
+ xmlpp::Element* el = doc.create_root_node ("Test");
+ pa->write_to_cpl (el, dcp::INTEROP);
+
+ cxml::Node node (el);
+ BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "1.85");
+ }
+
+ {
+ pa->set_screen_aspect_ratio (dcp::Fraction (2048, 858));
+ xmlpp::Document doc;
+ xmlpp::Element* el = doc.create_root_node ("Test");
+ pa->write_to_cpl (el, dcp::INTEROP);
+
+ cxml::Node node (el);
+ BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
+ }
+}
#include "cpl.h"
#include "argb_frame.h"
#include "mono_picture_mxf.h"
+#include "reel_picture_asset.h"
#include "reel.h"
#include "test.h"
get_frame (dcp::DCP const & dcp)
{
shared_ptr<const dcp::Reel> reel = dcp.cpls().front()->reels().front ();
- shared_ptr<const dcp::PictureMXF> picture = reel->main_picture ();
+ shared_ptr<dcp::PictureMXF> picture = reel->main_picture()->mxf ();
BOOST_CHECK (picture);
shared_ptr<const dcp::MonoPictureMXF> mono_picture = dynamic_pointer_cast<const dcp::MonoPictureMXF> (picture);
"test/data/private.key"
);
- encrypted.add_kdm (kdm);
+ encrypted.add (kdm);
shared_ptr<const dcp::ARGBFrame> plaintext_frame = get_frame (plaintext);
shared_ptr<const dcp::ARGBFrame> encrypted_frame = get_frame (encrypted);
list<shared_ptr<dcp::CPL> > cpls = d.cpls ();
BOOST_CHECK_EQUAL (cpls.size(), 1);
- BOOST_CHECK_EQUAL (cpls.front()->name(), "A Test DCP");
+ BOOST_CHECK_EQUAL (cpls.front()->annotation_text(), "A Test DCP");
BOOST_CHECK_EQUAL (cpls.front()->content_kind(), dcp::FEATURE);
- BOOST_CHECK_EQUAL (cpls.front()->frames_per_second(), 24);
- BOOST_CHECK_EQUAL (cpls.front()->length(), 24);
}
boost::filesystem::remove_all ("build/test/baz");
boost::filesystem::create_directories ("build/test/baz");
- shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF (24));
- mp->set_size (dcp::Size (32, 32));
- shared_ptr<dcp::PictureMXFWriter> writer = mp->start_write ("build/test/baz/video1.mxf", false);
+ shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ shared_ptr<dcp::PictureMXFWriter> writer = mp->start_write ("build/test/baz/video1.mxf", dcp::SMPTE, false);
int written_size = 0;
for (int i = 0; i < 24; ++i) {
Kumu::ResetTestRNG ();
#endif
- mp.reset (new dcp::MonoPictureMXF (24));
- mp->set_size (dcp::Size (32, 32));
- writer = mp->start_write ("build/test/baz/video2.mxf", true);
+ mp.reset (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ writer = mp->start_write ("build/test/baz/video2.mxf", dcp::SMPTE, true);
writer->write (data, size);
+/*
+ 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 <iostream>
#include "dcp.h"
#include "cpl.h"
#include "reel.h"
-#include "subtitle_asset.h"
+#include "subtitle_content.h"
+#include "reel_subtitle_asset.h"
#include "exceptions.h"
using std::cout;
}
DCP* dcp = new DCP (argv[1]);
- dcp->read (false);
+ dcp->read ();
list<shared_ptr<CPL> > cpls = dcp->cpls ();
for (list<boost::shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
for (list<shared_ptr<Reel> >::iterator j = reels.begin(); j != reels.end(); ++j) {
if ((*j)->main_subtitle()) {
- (*j)->main_subtitle()->write_xml ();
+ (*j)->main_subtitle()->subtitle_content()->write_xml ();
}
}
}
#include "mono_picture_frame.h"
#include "argb_frame.h"
#include "signer_chain.h"
+#include "mono_picture_mxf_writer.h"
+#include "reel_picture_asset.h"
+#include "file.h"
using std::list;
using boost::shared_ptr;
boost::filesystem::path work_dir = "build/test/round_trip_test";
boost::filesystem::create_directory (work_dir);
- shared_ptr<dcp::MonoPictureMXF> asset_A (new dcp::MonoPictureMXF (work_dir, "video.mxf"));
- asset_A->set_edit_rate (24);
- shared_ptr<PictureMXFWriter> writer;
- boost::filesystem::path mxf = work_dir + "video.mxf";
- writer->start_write (mxf, false);
- TestFile j2c ("test/data/32x32_red_square.j2c");
+ shared_ptr<dcp::MonoPictureMXF> mxf_A (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ shared_ptr<dcp::PictureMXFWriter> writer = mxf_A->start_write (work_dir / "video.mxf", dcp::SMPTE, false);
+ dcp::File j2c ("test/data/32x32_red_square.j2c");
for (int i = 0; i < 24; ++i) {
writer->write (j2c.data (), j2c.size ());
}
dcp::Key key;
- asset_A->set_key (key);
+ mxf_A->set_key (key);
- shared_ptr<dcp::CPL> cpl (new dcp::CPL (work_dir, "A Test DCP", dcp::FEATURE, 24, 24));
- cpl->add_reel (shared_ptr<dcp::Reel> (new dcp::Reel (asset_A, shared_ptr<dcp::SoundMXF> (), shared_ptr<dcp::SubtitleAsset> ())));
+ shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
+ shared_ptr<dcp::Reel> reel (new dcp::Reel ());
+ reel->add (shared_ptr<dcp::ReelPictureAsset> (mxf_A, 0));
+ cpl->add (reel);
/* A KDM using our certificate chain's leaf key pair */
dcp::KDM kdm_A (
}
/* Reload the picture MXF */
- shared_ptr<dcp::MonoPictureMXF> asset_B (
- new dcp::MonoPictureMXF (work_dir, "video.mxf")
+ shared_ptr<dcp::MonoPictureMXF> mxf_B (
+ new dcp::MonoPictureMXF (work_dir / "video.mxf")
);
- asset_B->set_key (kdm_B.keys().front().key());
+ mxf_B->set_key (kdm_B.keys().front().key());
- shared_ptr<dcp::ARGBFrame> frame_A = asset_A->get_frame(0)->argb_frame ();
- shared_ptr<dcp::ARGBFrame> frame_B = asset_B->get_frame(0)->argb_frame ();
+ shared_ptr<dcp::ARGBFrame> frame_A = mxf_A->get_frame(0)->argb_frame ();
+ shared_ptr<dcp::ARGBFrame> frame_B = mxf_B->get_frame(0)->argb_frame ();
BOOST_CHECK_EQUAL (frame_A->size().width, frame_B->size().width);
BOOST_CHECK_EQUAL (frame_A->size().height, frame_B->size().height);
BOOST_CHECK_EQUAL (memcmp (frame_A->data(), frame_B->data(), frame_A->size().width * frame_A->size().height), 0);
#include <iostream>
-#include "subtitle_asset.h"
+#include "subtitle_content.h"
using namespace std;
exit (EXIT_FAILURE);
}
- dcp::SubtitleAsset s (argv[1]);
+ dcp::SubtitleContent s (argv[1]);
cout << s.xml_as_string ();
return 0;
}
/*
- 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
*/
+#include "subtitle_content.h"
+#include "subtitle_string.h"
#include <boost/test/unit_test.hpp>
-#include "subtitle_asset.h"
using std::list;
using boost::shared_ptr;
-/* Load a subtitle asset from XML and check that it is read correctly */
+/* Load some subtitle content from XML and check that it is read correctly */
BOOST_AUTO_TEST_CASE (subtitles1)
{
- dcp::SubtitleAsset subs ("test/data/subs1.xml");
+ dcp::SubtitleContent subs ("test/data/subs1.xml");
BOOST_CHECK_EQUAL (subs.language(), "French");
- list<shared_ptr<dcp::Subtitle> > s = subs.subtitles_at (dcp::Time (0, 0, 6, 1));
+ list<shared_ptr<dcp::SubtitleString> > s = subs.subtitles_at (dcp::Time (0, 0, 6, 1));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 0, 7, 190));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 1),
dcp::Time (0, 0, 0, 1)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 0, 11, 95));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 0, 14, 42));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
/** And similarly for another one */
BOOST_AUTO_TEST_CASE (subtitles2)
{
- dcp::SubtitleAsset subs ("test/data/subs2.xml");
+ dcp::SubtitleContent subs ("test/data/subs2.xml");
- list<shared_ptr<dcp::Subtitle> > s = subs.subtitles_at (dcp::Time (0, 0, 42, 100));
+ list<shared_ptr<dcp::SubtitleString> > s = subs.subtitles_at (dcp::Time (0, 0, 42, 100));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 0, 50, 50));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 2, 300));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 15, 50));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 27, 200));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 42, 300));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 45, 200));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 1, 47, 249));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
dcp::Color (255, 255, 255),
s = subs.subtitles_at (dcp::Time (0, 2, 6, 210));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
dcp::Time (0, 0, 0, 0),
dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), dcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
dcp::Color (255, 255, 255),
string test_corpus = "../libdcp-test";
-TestFile::TestFile (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);
-}
-
-TestFile::~TestFile ()
-{
- delete[] _data;
-}
*/
extern std::string test_corpus;
-
-class TestFile
-{
-public:
- TestFile (boost::filesystem::path file);
- ~TestFile ();
-
- uint8_t* data () const {
- return _data;
- }
-
- int64_t size () const {
- return _size;
- }
-
-private:
- uint8_t* _data;
- int64_t _size;
-};
obj.source = """
certificates_test.cc
color_test.cc
- cpl_sar.cc
+ cpl_sar_test.cc
dcp_time_test.cc
decryption_test.cc
frame_info_test.cc
+/*
+ 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 <iostream>
#include <cstdlib>
#include <boost/filesystem.hpp>
#include "reel.h"
#include "sound_mxf.h"
#include "picture_mxf.h"
-#include "subtitle_asset.h"
+#include "subtitle_content.h"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
+#include "subtitle_string.h"
#include "cpl.h"
using std::string;
DCP* dcp = 0;
try {
dcp = new DCP (argv[optind]);
- dcp->read (false);
+ dcp->read ();
} catch (FileError& e) {
cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << " " << e.filename() << "\n";
exit (EXIT_FAILURE);
list<shared_ptr<CPL> > cpls = dcp->cpls ();
for (list<shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
- cout << " CPL: " << (*i)->name() << "\n"
- << " Length: " << (*i)->length() << "\n"
- << " Frames per second: " << (*i)->frames_per_second() << "\n";
+ cout << " CPL: " << (*i)->annotation_text() << "\n";
list<shared_ptr<Reel> > reels = (*i)->reels ();
cout << " Reel " << R << "\n";
if ((*j)->main_picture()) {
- cout << " Picture: " << (*j)->main_picture()->size().width << "x" << (*j)->main_picture()->size().height << "\n";
+ cout << " Picture: "
+ << (*j)->main_picture()->mxf()->size().width
+ << "x"
+ << (*j)->main_picture()->mxf()->size().height << "\n";
}
if ((*j)->main_sound()) {
- cout << " Sound: " << (*j)->main_sound()->channels() << " channels at " << (*j)->main_sound()->sampling_rate() << "Hz\n";
+ cout << " Sound: "
+ << (*j)->main_sound()->mxf()->channels()
+ << " channels at "
+ << (*j)->main_sound()->mxf()->sampling_rate() << "Hz\n";
}
if ((*j)->main_subtitle()) {
- list<shared_ptr<Subtitle> > subs = (*j)->main_subtitle()->subtitles ();
- cout << " Subtitle: " << subs.size() << " subtitles in " << (*j)->main_subtitle()->language() << "\n";
+ list<shared_ptr<SubtitleString> > subs = (*j)->main_subtitle()->subtitle_content()->subtitles ();
+ cout << " Subtitle: " << subs.size() << " subtitles in " << (*j)->main_subtitle()->subtitle_content()->language() << "\n";
if (subtitles) {
- for (list<shared_ptr<Subtitle> >::const_iterator k = subs.begin(); k != subs.end(); ++k) {
+ for (list<shared_ptr<SubtitleString> >::const_iterator k = subs.begin(); k != subs.end(); ++k) {
cout << " " << (*k)->text() << "\n";
cout << " "
<< "font:" << (*k)->font() << "; "