summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cpl.cc301
-rw-r--r--src/cpl.h96
-rw-r--r--src/dcp.cc286
-rw-r--r--src/dcp.h74
-rw-r--r--src/metadata.cc30
-rw-r--r--src/metadata.h29
-rw-r--r--src/mxf_asset.cc8
-rw-r--r--src/mxf_asset.h6
-rw-r--r--src/picture_asset.cc27
-rw-r--r--src/picture_asset.h14
-rw-r--r--src/sound_asset.cc23
-rw-r--r--src/sound_asset.h15
-rw-r--r--src/test_mode.cc45
-rw-r--r--src/test_mode.h29
-rw-r--r--src/wscript4
15 files changed, 503 insertions, 484 deletions
diff --git a/src/cpl.cc b/src/cpl.cc
new file mode 100644
index 00000000..10a83078
--- /dev/null
+++ b/src/cpl.cc
@@ -0,0 +1,301 @@
+/*
+ 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 "cpl.h"
+#include "cpl_file.h"
+#include "util.h"
+#include "picture_asset.h"
+#include "sound_asset.h"
+#include "subtitle_asset.h"
+#include "asset_map.h"
+#include "reel.h"
+#include "metadata.h"
+
+using std::string;
+using std::stringstream;
+using std::ofstream;
+using std::ostream;
+using std::list;
+using boost::shared_ptr;
+using namespace libdcp;
+
+CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second)
+ : _directory (directory)
+ , _name (name)
+ , _content_kind (content_kind)
+ , _length (length)
+ , _fps (frames_per_second)
+{
+ _uuid = make_uuid ();
+}
+
+/** 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_map The corresponding asset map.
+ * @param require_mxfs true to throw an exception if a required MXF file does not exist.
+ */
+CPL::CPL (string directory, string file, shared_ptr<const AssetMap> asset_map, bool require_mxfs)
+ : _directory (directory)
+ , _content_kind (FEATURE)
+ , _length (0)
+ , _fps (0)
+{
+ /* Read the XML */
+ shared_ptr<CPLFile> cpl;
+ try {
+ cpl.reset (new CPLFile (file));
+ } catch (FileError& e) {
+ boost::throw_exception (FileError ("could not load CPL file", file));
+ }
+
+ /* Now cherry-pick the required bits into our own data structure */
+
+ _name = cpl->annotation_text;
+ _content_kind = cpl->content_kind;
+
+ for (list<shared_ptr<CPLReel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) {
+
+ shared_ptr<Picture> p;
+
+ if ((*i)->asset_list->main_picture) {
+ p = (*i)->asset_list->main_picture;
+ } else {
+ p = (*i)->asset_list->main_stereoscopic_picture;
+ }
+
+ _fps = p->edit_rate.numerator;
+ _length += p->duration;
+
+ shared_ptr<PictureAsset> picture;
+ shared_ptr<SoundAsset> sound;
+ shared_ptr<SubtitleAsset> subtitle;
+
+ /* Some rather twisted logic to decide if we are 3D or not;
+ some DCPs give a MainStereoscopicPicture to indicate 3D, others
+ just have a FrameRate twice the EditRate and apparently
+ expect you to divine the fact that they are hence 3D.
+ */
+
+ if (!(*i)->asset_list->main_stereoscopic_picture && p->edit_rate == p->frame_rate) {
+
+ try {
+ picture.reset (new MonoPictureAsset (
+ _directory,
+ asset_map->asset_from_id (p->id)->chunks.front()->path
+ )
+ );
+
+ picture->set_entry_point (p->entry_point);
+ picture->set_duration (p->duration);
+ } catch (MXFFileError) {
+ if (require_mxfs) {
+ throw;
+ }
+ }
+
+ } else {
+ try {
+ picture.reset (new StereoPictureAsset (
+ _directory,
+ asset_map->asset_from_id (p->id)->chunks.front()->path,
+ _fps,
+ p->duration
+ )
+ );
+
+ picture->set_entry_point (p->entry_point);
+ picture->set_duration (p->duration);
+
+ } catch (MXFFileError) {
+ if (require_mxfs) {
+ throw;
+ }
+ }
+
+ }
+
+ if ((*i)->asset_list->main_sound) {
+
+ try {
+ sound.reset (new SoundAsset (
+ _directory,
+ asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path
+ )
+ );
+
+ sound->set_entry_point ((*i)->asset_list->main_sound->entry_point);
+ sound->set_duration ((*i)->asset_list->main_sound->duration);
+ } catch (MXFFileError) {
+ if (require_mxfs) {
+ throw;
+ }
+ }
+ }
+
+ if ((*i)->asset_list->main_subtitle) {
+
+ subtitle.reset (new SubtitleAsset (
+ _directory,
+ asset_map->asset_from_id ((*i)->asset_list->main_subtitle->id)->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)));
+ }
+}
+
+void
+CPL::add_reel (shared_ptr<const Reel> reel)
+{
+ _reels.push_back (reel);
+}
+
+void
+CPL::write_xml (XMLMetadata const & metadata) const
+{
+ boost::filesystem::path p;
+ p /= _directory;
+ stringstream s;
+ s << _uuid << "_cpl.xml";
+ p /= s.str();
+ ofstream os (p.string().c_str());
+
+ os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ << "<CompositionPlaylist xmlns=\"http://www.smpte-ra.org/schemas/429-7/2006/CPL\">\n"
+ << " <Id>urn:uuid:" << _uuid << "</Id>\n"
+ << " <AnnotationText>" << _name << "</AnnotationText>\n"
+ << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n"
+ << " <Creator>" << metadata.creator << "</Creator>\n"
+ << " <ContentTitleText>" << _name << "</ContentTitleText>\n"
+ << " <ContentKind>" << content_kind_to_string (_content_kind) << "</ContentKind>\n"
+ << " <ContentVersion>\n"
+ << " <Id>urn:uri:" << _uuid << "_" << metadata.issue_date << "</Id>\n"
+ << " <LabelText>" << _uuid << "_" << metadata.issue_date << "</LabelText>\n"
+ << " </ContentVersion>\n"
+ << " <RatingList/>\n"
+ << " <ReelList>\n";
+
+ for (list<shared_ptr<const Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
+ (*i)->write_to_cpl (os);
+ }
+
+ os << " </ReelList>\n"
+ << "</CompositionPlaylist>\n";
+
+ os.close ();
+
+ _digest = make_digest (p.string ());
+ _length = boost::filesystem::file_size (p.string ());
+}
+
+void
+CPL::write_to_pkl (ostream& s) const
+{
+ s << " <Asset>\n"
+ << " <Id>urn:uuid:" << _uuid << "</Id>\n"
+ << " <Hash>" << _digest << "</Hash>\n"
+ << " <Size>" << _length << "</Size>\n"
+ << " <Type>text/xml</Type>\n"
+ << " </Asset>\n";
+}
+
+list<shared_ptr<const Asset> >
+CPL::assets () const
+{
+ list<shared_ptr<const Asset> > a;
+ for (list<shared_ptr<const Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
+ if ((*i)->main_picture ()) {
+ a.push_back ((*i)->main_picture ());
+ }
+ if ((*i)->main_sound ()) {
+ a.push_back ((*i)->main_sound ());
+ }
+ if ((*i)->main_subtitle ()) {
+ a.push_back ((*i)->main_subtitle ());
+ }
+ }
+
+ return a;
+}
+
+void
+CPL::write_to_assetmap (ostream& s) const
+{
+ s << " <Asset>\n"
+ << " <Id>urn:uuid:" << _uuid << "</Id>\n"
+ << " <ChunkList>\n"
+ << " <Chunk>\n"
+ << " <Path>" << _uuid << "_cpl.xml</Path>\n"
+ << " <VolumeIndex>1</VolumeIndex>\n"
+ << " <Offset>0</Offset>\n"
+ << " <Length>" << _length << "</Length>\n"
+ << " </Chunk>\n"
+ << " </ChunkList>\n"
+ << " </Asset>\n";
+}
+
+
+
+bool
+CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (_name != other._name) {
+ note (ERROR, "names differ");
+ return false;
+ }
+
+ if (_content_kind != other._content_kind) {
+ note (ERROR, "content kinds differ");
+ return false;
+ }
+
+ if (_fps != other._fps) {
+ note (ERROR, "frames per second differ");
+ return false;
+ }
+
+ if (_length != other._length) {
+ note (ERROR, "lengths differ");
+ return false;
+ }
+
+ if (_reels.size() != other._reels.size()) {
+ note (ERROR, "reel counts differ");
+ return false;
+ }
+
+ list<shared_ptr<const Reel> >::const_iterator a = _reels.begin ();
+ list<shared_ptr<const Reel> >::const_iterator b = other._reels.begin ();
+
+ while (a != _reels.end ()) {
+ if (!(*a)->equals (*b, opt, note)) {
+ return false;
+ }
+ ++a;
+ ++b;
+ }
+
+ return true;
+}
diff --git a/src/cpl.h b/src/cpl.h
new file mode 100644
index 00000000..0abff749
--- /dev/null
+++ b/src/cpl.h
@@ -0,0 +1,96 @@
+/*
+ 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 <list>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include "types.h"
+
+namespace libdcp {
+
+class AssetMap;
+class Asset;
+class Reel;
+class XMLMetadata;
+
+/** @brief A CPL within a DCP */
+class CPL
+{
+public:
+ CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second);
+ CPL (std::string directory, std::string file, boost::shared_ptr<const AssetMap> asset_map, bool require_mxfs = true);
+
+ void add_reel (boost::shared_ptr<const Reel> reel);
+
+ /** @return the length in frames */
+ int length () const {
+ return _length;
+ }
+
+ /** @return the type of the content, used by media servers
+ * to categorise things (e.g. feature, trailer, etc.)
+ */
+ ContentKind content_kind () const {
+ return _content_kind;
+ }
+
+ std::list<boost::shared_ptr<const Reel> > reels () const {
+ 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 Asset> > assets () const;
+
+ bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
+
+ void write_xml (XMLMetadata const &) const;
+ void write_to_assetmap (std::ostream& s) const;
+ void write_to_pkl (std::ostream& s) const;
+
+private:
+ std::string _directory;
+ /** the name of the DCP */
+ std::string _name;
+ /** the content kind of the CPL */
+ ContentKind _content_kind;
+ /** length in frames */
+ mutable int _length;
+ /** frames per second */
+ int _fps;
+ /** reels */
+ std::list<boost::shared_ptr<const Reel> > _reels;
+
+ /** our UUID */
+ std::string _uuid;
+ /** a SHA1 digest of our XML */
+ mutable std::string _digest;
+};
+
+}
diff --git a/src/dcp.cc b/src/dcp.cc
index 3fe69e40..7af3f353 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -41,6 +41,7 @@
#include "pkl_file.h"
#include "asset_map.h"
#include "reel.h"
+#include "cpl.h"
using std::string;
using std::list;
@@ -57,21 +58,21 @@ DCP::DCP (string directory)
}
void
-DCP::write_xml () const
+DCP::write_xml (XMLMetadata const & metadata) const
{
for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_xml ();
+ (*i)->write_xml (metadata);
}
string pkl_uuid = make_uuid ();
- string pkl_path = write_pkl (pkl_uuid);
+ string pkl_path = write_pkl (pkl_uuid, metadata);
write_volindex ();
- write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path));
+ write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path), metadata);
}
std::string
-DCP::write_pkl (string pkl_uuid) const
+DCP::write_pkl (string pkl_uuid, XMLMetadata const & metadata) const
{
assert (!_cpls.empty ());
@@ -87,9 +88,9 @@ DCP::write_pkl (string pkl_uuid) const
<< " <Id>urn:uuid:" << pkl_uuid << "</Id>\n"
/* XXX: this is a bit of a hack */
<< " <AnnotationText>" << _cpls.front()->name() << "</AnnotationText>\n"
- << " <IssueDate>" << Metadata::instance()->issue_date << "</IssueDate>\n"
- << " <Issuer>" << Metadata::instance()->issuer << "</Issuer>\n"
- << " <Creator>" << Metadata::instance()->creator << "</Creator>\n"
+ << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n"
+ << " <Issuer>" << metadata.issuer << "</Issuer>\n"
+ << " <Creator>" << metadata.creator << "</Creator>\n"
<< " <AssetList>\n";
list<shared_ptr<const Asset> > a = assets ();
@@ -122,7 +123,7 @@ DCP::write_volindex () const
}
void
-DCP::write_assetmap (string pkl_uuid, int pkl_length) const
+DCP::write_assetmap (string pkl_uuid, int pkl_length, XMLMetadata const & metadata) const
{
boost::filesystem::path p;
p /= _directory;
@@ -132,10 +133,10 @@ DCP::write_assetmap (string pkl_uuid, int pkl_length) const
am << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
<< "<AssetMap xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n"
<< " <Id>urn:uuid:" << make_uuid() << "</Id>\n"
- << " <Creator>" << Metadata::instance()->creator << "</Creator>\n"
+ << " <Creator>" << metadata.creator << "</Creator>\n"
<< " <VolumeCount>1</VolumeCount>\n"
- << " <IssueDate>" << Metadata::instance()->issue_date << "</IssueDate>\n"
- << " <Issuer>" << Metadata::instance()->issuer << "</Issuer>\n"
+ << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n"
+ << " <Issuer>" << metadata.issuer << "</Issuer>\n"
<< " <AssetList>\n";
am << " <Asset>\n"
@@ -298,264 +299,3 @@ DCP::assets () const
return a;
}
-CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second)
- : _directory (directory)
- , _name (name)
- , _content_kind (content_kind)
- , _length (length)
- , _fps (frames_per_second)
-{
- _uuid = make_uuid ();
-}
-
-/** 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_map The corresponding asset map.
- * @param require_mxfs true to throw an exception if a required MXF file does not exist.
- */
-CPL::CPL (string directory, string file, shared_ptr<const AssetMap> asset_map, bool require_mxfs)
- : _directory (directory)
- , _content_kind (FEATURE)
- , _length (0)
- , _fps (0)
-{
- /* Read the XML */
- shared_ptr<CPLFile> cpl;
- try {
- cpl.reset (new CPLFile (file));
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load CPL file", file));
- }
-
- /* Now cherry-pick the required bits into our own data structure */
-
- _name = cpl->annotation_text;
- _content_kind = cpl->content_kind;
-
- for (list<shared_ptr<CPLReel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) {
-
- shared_ptr<Picture> p;
-
- if ((*i)->asset_list->main_picture) {
- p = (*i)->asset_list->main_picture;
- } else {
- p = (*i)->asset_list->main_stereoscopic_picture;
- }
-
- _fps = p->edit_rate.numerator;
- _length += p->duration;
-
- shared_ptr<PictureAsset> picture;
- shared_ptr<SoundAsset> sound;
- shared_ptr<SubtitleAsset> subtitle;
-
- /* Some rather twisted logic to decide if we are 3D or not;
- some DCPs give a MainStereoscopicPicture to indicate 3D, others
- just have a FrameRate twice the EditRate and apparently
- expect you to divine the fact that they are hence 3D.
- */
-
- if (!(*i)->asset_list->main_stereoscopic_picture && p->edit_rate == p->frame_rate) {
-
- try {
- picture.reset (new MonoPictureAsset (
- _directory,
- asset_map->asset_from_id (p->id)->chunks.front()->path
- )
- );
-
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- } else {
-
- try {
- picture.reset (new StereoPictureAsset (
- _directory,
- asset_map->asset_from_id (p->id)->chunks.front()->path,
- _fps,
- p->duration
- )
- );
-
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
-
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- }
-
- if ((*i)->asset_list->main_sound) {
-
- try {
- sound.reset (new SoundAsset (
- _directory,
- asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path
- )
- );
-
- sound->set_entry_point ((*i)->asset_list->main_sound->entry_point);
- sound->set_duration ((*i)->asset_list->main_sound->duration);
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
- }
-
- if ((*i)->asset_list->main_subtitle) {
-
- subtitle.reset (new SubtitleAsset (
- _directory,
- asset_map->asset_from_id ((*i)->asset_list->main_subtitle->id)->chunks.front()->path
- )
- );
- }
-
- _reels.push_back (shared_ptr<Reel> (new Reel (picture, sound, subtitle)));
- }
-}
-
-void
-CPL::add_reel (shared_ptr<const Reel> reel)
-{
- _reels.push_back (reel);
-}
-
-void
-CPL::write_xml () const
-{
- boost::filesystem::path p;
- p /= _directory;
- stringstream s;
- s << _uuid << "_cpl.xml";
- p /= s.str();
- ofstream os (p.string().c_str());
-
- os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- << "<CompositionPlaylist xmlns=\"http://www.smpte-ra.org/schemas/429-7/2006/CPL\">\n"
- << " <Id>urn:uuid:" << _uuid << "</Id>\n"
- << " <AnnotationText>" << _name << "</AnnotationText>\n"
- << " <IssueDate>" << Metadata::instance()->issue_date << "</IssueDate>\n"
- << " <Creator>" << Metadata::instance()->creator << "</Creator>\n"
- << " <ContentTitleText>" << _name << "</ContentTitleText>\n"
- << " <ContentKind>" << content_kind_to_string (_content_kind) << "</ContentKind>\n"
- << " <ContentVersion>\n"
- << " <Id>urn:uri:" << _uuid << "_" << Metadata::instance()->issue_date << "</Id>\n"
- << " <LabelText>" << _uuid << "_" << Metadata::instance()->issue_date << "</LabelText>\n"
- << " </ContentVersion>\n"
- << " <RatingList/>\n"
- << " <ReelList>\n";
-
- for (list<shared_ptr<const Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->write_to_cpl (os);
- }
-
- os << " </ReelList>\n"
- << "</CompositionPlaylist>\n";
-
- os.close ();
-
- _digest = make_digest (p.string ());
- _length = boost::filesystem::file_size (p.string ());
-}
-
-void
-CPL::write_to_pkl (ostream& s) const
-{
- s << " <Asset>\n"
- << " <Id>urn:uuid:" << _uuid << "</Id>\n"
- << " <Hash>" << _digest << "</Hash>\n"
- << " <Size>" << _length << "</Size>\n"
- << " <Type>text/xml</Type>\n"
- << " </Asset>\n";
-}
-
-list<shared_ptr<const Asset> >
-CPL::assets () const
-{
- list<shared_ptr<const Asset> > a;
- for (list<shared_ptr<const Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- if ((*i)->main_picture ()) {
- a.push_back ((*i)->main_picture ());
- }
- if ((*i)->main_sound ()) {
- a.push_back ((*i)->main_sound ());
- }
- if ((*i)->main_subtitle ()) {
- a.push_back ((*i)->main_subtitle ());
- }
- }
-
- return a;
-}
-
-void
-CPL::write_to_assetmap (ostream& s) const
-{
- s << " <Asset>\n"
- << " <Id>urn:uuid:" << _uuid << "</Id>\n"
- << " <ChunkList>\n"
- << " <Chunk>\n"
- << " <Path>" << _uuid << "_cpl.xml</Path>\n"
- << " <VolumeIndex>1</VolumeIndex>\n"
- << " <Offset>0</Offset>\n"
- << " <Length>" << _length << "</Length>\n"
- << " </Chunk>\n"
- << " </ChunkList>\n"
- << " </Asset>\n";
-}
-
-
-
-bool
-CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (_name != other._name) {
- note (ERROR, "names differ");
- return false;
- }
-
- if (_content_kind != other._content_kind) {
- note (ERROR, "content kinds differ");
- return false;
- }
-
- if (_fps != other._fps) {
- note (ERROR, "frames per second differ");
- return false;
- }
-
- if (_length != other._length) {
- note (ERROR, "lengths differ");
- return false;
- }
-
- if (_reels.size() != other._reels.size()) {
- note (ERROR, "reel counts differ");
- return false;
- }
-
- list<shared_ptr<const Reel> >::const_iterator a = _reels.begin ();
- list<shared_ptr<const Reel> >::const_iterator b = other._reels.begin ();
-
- while (a != _reels.end ()) {
- if (!(*a)->equals (*b, opt, note)) {
- return false;
- }
- ++a;
- ++b;
- }
-
- return true;
-}
diff --git a/src/dcp.h b/src/dcp.h
index 9e2e8a02..42c0c6d9 100644
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -44,72 +44,10 @@ class SoundAsset;
class SubtitleAsset;
class Reel;
class AssetMap;
+class CPL;
+class XMLMetadata;
-/** @brief A CPL within a DCP */
-class CPL
-{
-public:
- CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second);
- CPL (std::string directory, std::string file, boost::shared_ptr<const AssetMap> asset_map, bool require_mxfs = true);
-
- void add_reel (boost::shared_ptr<const Reel> reel);
-
- /** @return the length in frames */
- int length () const {
- return _length;
- }
-
- /** @return the type of the content, used by media servers
- * to categorise things (e.g. feature, trailer, etc.)
- */
- ContentKind content_kind () const {
- return _content_kind;
- }
-
- std::list<boost::shared_ptr<const Reel> > reels () const {
- 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 Asset> > assets () const;
-
- bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
-
- void write_xml () const;
- void write_to_assetmap (std::ostream& s) const;
- void write_to_pkl (std::ostream& s) const;
-
-private:
- std::string _directory;
- /** the name of the DCP */
- std::string _name;
- /** the content kind of the CPL */
- ContentKind _content_kind;
- /** length in frames */
- mutable int _length;
- /** frames per second */
- int _fps;
- /** reels */
- std::list<boost::shared_ptr<const Reel> > _reels;
-
- /** our UUID */
- std::string _uuid;
- /** a SHA1 digest of our XML */
- mutable std::string _digest;
-};
-
-/** @class DCP dcp.h libdcp/dcp.h
+/** @class DCP
* @brief A class to create or read a DCP.
*/
@@ -137,7 +75,7 @@ public:
/** Write the required XML files to the directory that was
* passed into the constructor.
*/
- void write_xml () const;
+ void write_xml (XMLMetadata const &) const;
/** Compare this DCP with another, according to various options.
* @param other DCP to compare this one to.
@@ -166,7 +104,7 @@ private:
/** Write the PKL file.
* @param pkl_uuid UUID to use.
*/
- std::string write_pkl (std::string pkl_uuid) const;
+ std::string write_pkl (std::string pkl_uuid, XMLMetadata const &) const;
/** Write the VOLINDEX file */
void write_volindex () const;
@@ -175,7 +113,7 @@ private:
* @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) const;
+ void write_assetmap (std::string pkl_uuid, int pkl_length, XMLMetadata const &) const;
/** @return Assets in all this CPLs in this DCP */
std::list<boost::shared_ptr<const Asset> > assets () const;
diff --git a/src/metadata.cc b/src/metadata.cc
index 7e900e50..2967ac1d 100644
--- a/src/metadata.cc
+++ b/src/metadata.cc
@@ -27,16 +27,25 @@
using namespace std;
using namespace libdcp;
-Metadata* Metadata::_instance = 0;
-
-/** Construct a Metadata object with some default values */
-Metadata::Metadata ()
+MXFMetadata::MXFMetadata ()
: company_name ("libdcp")
, product_name ("libdcp")
, product_version (LIBDCP_VERSION)
- , issuer ("libdcp" LIBDCP_VERSION)
+{
+
+}
+
+
+XMLMetadata::XMLMetadata ()
+ : issuer ("libdcp" LIBDCP_VERSION)
, creator ("libdcp" LIBDCP_VERSION)
{
+ set_issue_date_now ();
+}
+
+void
+XMLMetadata::set_issue_date_now ()
+{
char buffer[64];
time_t now;
time (&now);
@@ -44,15 +53,4 @@ Metadata::Metadata ()
strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S+00:00", tm);
issue_date = string (buffer);
}
-
-/** @return Singleton Metadata instance */
-Metadata *
-Metadata::instance ()
-{
- if (_instance == 0) {
- _instance = new Metadata;
- }
-
- return _instance;
-}
diff --git a/src/metadata.h b/src/metadata.h
index 1610491e..7336766d 100644
--- a/src/metadata.h
+++ b/src/metadata.h
@@ -17,6 +17,9 @@
*/
+#ifndef LIBDCP_METADATA_H
+#define LIBDCP_METADATA_H
+
/** @file src/metadata.h
* @brief Metadata for writing to the DCP.
*/
@@ -26,28 +29,28 @@
namespace libdcp
{
-/** @brief A class to hold various metadata that will be written
- * to the DCP.
- *
- * The values are initialised, and can be modified if desired.
- */
-class Metadata
+class MXFMetadata
{
public:
- static Metadata* instance ();
+ MXFMetadata ();
std::string company_name;
std::string product_name;
std::string product_version;
+};
+
+class XMLMetadata
+{
+public:
+ XMLMetadata ();
+
+ void set_issue_date_now ();
+
std::string issuer;
std::string creator;
std::string issue_date;
-
-private:
- Metadata ();
-
- /** Singleton instance of Metadata */
- static Metadata* _instance;
};
}
+
+#endif
diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc
index 229c332f..cfb02c85 100644
--- a/src/mxf_asset.cc
+++ b/src/mxf_asset.cc
@@ -50,11 +50,11 @@ MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal<
}
void
-MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid)
+MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid, MXFMetadata const & metadata)
{
- writer_info->ProductVersion = Metadata::instance()->product_version;
- writer_info->CompanyName = Metadata::instance()->company_name;
- writer_info->ProductName = Metadata::instance()->product_name.c_str();
+ writer_info->ProductVersion = metadata.product_version;
+ writer_info->CompanyName = metadata.company_name;
+ writer_info->ProductName = metadata.product_name.c_str();
writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
unsigned int c;
diff --git a/src/mxf_asset.h b/src/mxf_asset.h
index 5815fd90..55aa889a 100644
--- a/src/mxf_asset.h
+++ b/src/mxf_asset.h
@@ -26,6 +26,8 @@
namespace libdcp
{
+class MXFMetadata;
+
/** @brief Parent class for assets which have MXF files */
class MXFAsset : public Asset
{
@@ -55,10 +57,10 @@ public:
* @param w struct to fill in.
* @param uuid uuid to use.
*/
- static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid);
+ static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid, MXFMetadata const & metadata);
protected:
-
+
/** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
};
diff --git a/src/picture_asset.cc b/src/picture_asset.cc
index a505dc63..788e3dc4 100644
--- a/src/picture_asset.cc
+++ b/src/picture_asset.cc
@@ -146,10 +146,12 @@ MonoPictureAsset::MonoPictureAsset (
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- Size size)
+ Size size,
+ MXFMetadata const & metadata
+ )
: PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
{
- construct (get_path);
+ construct (get_path, metadata);
}
MonoPictureAsset::MonoPictureAsset (
@@ -159,10 +161,12 @@ MonoPictureAsset::MonoPictureAsset (
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- Size size)
+ Size size,
+ MXFMetadata const & metadata
+ )
: PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
{
- construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
+ construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files), metadata);
}
MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size)
@@ -192,7 +196,7 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name)
}
void
-MonoPictureAsset::construct (boost::function<string (int)> get_path)
+MonoPictureAsset::construct (boost::function<string (int)> get_path, MXFMetadata const & metadata)
{
ASDCP::JP2K::CodestreamParser j2k_parser;
ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
@@ -205,7 +209,7 @@ MonoPictureAsset::construct (boost::function<string (int)> get_path)
picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
ASDCP::WriterInfo writer_info;
- fill_writer_info (&writer_info, _uuid);
+ fill_writer_info (&writer_info, _uuid, metadata);
ASDCP::JP2K::MXFWriter mxf_writer;
if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) {
@@ -407,10 +411,10 @@ StereoPictureAsset::get_frame (int n) const
}
shared_ptr<MonoPictureAssetWriter>
-MonoPictureAsset::start_write (bool overwrite)
+MonoPictureAsset::start_write (bool overwrite, MXFMetadata const & metadata)
{
- /* XXX: can't we use a shared_ptr here? */
- return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite));
+ /* XXX: can't we use shared_ptr here? */
+ return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite, metadata));
}
FrameInfo::FrameInfo (istream& s)
@@ -441,13 +445,14 @@ struct MonoPictureAssetWriter::ASDCPState
/** @param a Asset to write to. `a' must not be deleted while
* this writer class still exists, or bad things will happen.
*/
-MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite)
+MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite, MXFMetadata const & m)
: _state (new MonoPictureAssetWriter::ASDCPState)
, _asset (a)
, _frames_written (0)
, _started (false)
, _finalized (false)
, _overwrite (overwrite)
+ , _metadata (m)
{
}
@@ -463,7 +468,7 @@ MonoPictureAssetWriter::start (uint8_t* data, int size)
_state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor);
_state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
- MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid());
+ MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid(), _metadata);
if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (
_asset->path().string().c_str(),
diff --git a/src/picture_asset.h b/src/picture_asset.h
index c9226b1f..59c4dc00 100644
--- a/src/picture_asset.h
+++ b/src/picture_asset.h
@@ -27,6 +27,7 @@
#include <openjpeg.h>
#include "mxf_asset.h"
#include "util.h"
+#include "metadata.h"
namespace libdcp
{
@@ -121,7 +122,7 @@ public:
private:
friend class MonoPictureAsset;
- MonoPictureAssetWriter (MonoPictureAsset *, bool);
+ MonoPictureAssetWriter (MonoPictureAsset *, bool, MXFMetadata const &);
void start (uint8_t *, int);
/* no copy construction */
@@ -142,6 +143,7 @@ private:
/** true if finalize() has been called */
bool _finalized;
bool _overwrite;
+ MXFMetadata _metadata;
};
/** A 2D (monoscopic) picture asset */
@@ -166,7 +168,8 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- Size size
+ Size size,
+ MXFMetadata const & metadata = MXFMetadata ()
);
/** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files.
@@ -187,7 +190,8 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- Size size
+ Size size,
+ MXFMetadata const & metadata = MXFMetadata ()
);
/** Construct a MonoPictureAsset, reading the MXF from disk.
@@ -207,14 +211,14 @@ public:
MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size);
/** Start a progressive write to a MonoPictureAsset */
- boost::shared_ptr<MonoPictureAssetWriter> start_write (bool);
+ boost::shared_ptr<MonoPictureAssetWriter> start_write (bool, MXFMetadata const & metadata = MXFMetadata ());
boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
private:
std::string path_from_list (int f, std::vector<std::string> const & files) const;
- void construct (boost::function<std::string (int)>);
+ void construct (boost::function<std::string (int)>, MXFMetadata const &);
};
/** A 3D (stereoscopic) picture asset */
diff --git a/src/sound_asset.cc b/src/sound_asset.cc
index 6e29aadf..9b6b48aa 100644
--- a/src/sound_asset.cc
+++ b/src/sound_asset.cc
@@ -46,7 +46,8 @@ SoundAsset::SoundAsset (
string directory,
string mxf_name,
boost::signals2::signal<void (float)>* progress,
- int fps, int intrinsic_duration
+ int fps, int intrinsic_duration,
+ MXFMetadata const & metadata
)
: MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
, _channels (files.size ())
@@ -54,7 +55,7 @@ SoundAsset::SoundAsset (
{
assert (_channels);
- construct (boost::bind (&SoundAsset::path_from_channel, this, _1, files));
+ construct (boost::bind (&SoundAsset::path_from_channel, this, _1, files), metadata);
}
SoundAsset::SoundAsset (
@@ -62,7 +63,8 @@ SoundAsset::SoundAsset (
string directory,
string mxf_name,
boost::signals2::signal<void (float)>* progress,
- int fps, int intrinsic_duration, int channels
+ int fps, int intrinsic_duration, int channels,
+ MXFMetadata const & metadata
)
: MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
, _channels (channels)
@@ -70,7 +72,7 @@ SoundAsset::SoundAsset (
{
assert (_channels);
- construct (get_path);
+ construct (get_path, metadata);
}
SoundAsset::SoundAsset (string directory, string mxf_name)
@@ -111,7 +113,7 @@ SoundAsset::path_from_channel (Channel channel, vector<string> const & files)
}
void
-SoundAsset::construct (boost::function<string (Channel)> get_path)
+SoundAsset::construct (boost::function<string (Channel)> get_path, MXFMetadata const & metadata)
{
ASDCP::Rational asdcp_edit_rate (_edit_rate, 1);
@@ -164,7 +166,7 @@ SoundAsset::construct (boost::function<string (Channel)> get_path)
frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
ASDCP::WriterInfo writer_info;
- MXFAsset::fill_writer_info (&writer_info, _uuid);
+ MXFAsset::fill_writer_info (&writer_info, _uuid, metadata);
ASDCP::PCM::MXFWriter mxf_writer;
if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) {
@@ -303,10 +305,10 @@ SoundAsset::get_frame (int n) const
}
shared_ptr<SoundAssetWriter>
-SoundAsset::start_write ()
+SoundAsset::start_write (MXFMetadata const & metadata)
{
/* XXX: can't we use a shared_ptr here? */
- return shared_ptr<SoundAssetWriter> (new SoundAssetWriter (this));
+ return shared_ptr<SoundAssetWriter> (new SoundAssetWriter (this, metadata));
}
struct SoundAssetWriter::ASDCPState
@@ -317,12 +319,13 @@ struct SoundAssetWriter::ASDCPState
ASDCP::PCM::AudioDescriptor audio_desc;
};
-SoundAssetWriter::SoundAssetWriter (SoundAsset* a)
+SoundAssetWriter::SoundAssetWriter (SoundAsset* a, MXFMetadata const & m)
: _state (new SoundAssetWriter::ASDCPState)
, _asset (a)
, _finalized (false)
, _frames_written (0)
, _frame_buffer_offset (0)
+ , _metadata (m)
{
/* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
_state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
@@ -339,7 +342,7 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* a)
_state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
- MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid ());
+ MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid (), _metadata);
if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc))) {
boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string()));
diff --git a/src/sound_asset.h b/src/sound_asset.h
index 9e6e75cf..5c230e06 100644
--- a/src/sound_asset.h
+++ b/src/sound_asset.h
@@ -26,12 +26,12 @@
#include "mxf_asset.h"
#include "types.h"
+#include "metadata.h"
namespace libdcp
{
class SoundFrame;
-
class SoundAsset;
class SoundAssetWriter
@@ -45,7 +45,7 @@ public:
private:
friend class SoundAsset;
- SoundAssetWriter (SoundAsset *);
+ SoundAssetWriter (SoundAsset *, MXFMetadata const &);
/* no copy construction */
SoundAssetWriter (SoundAssetWriter const &);
@@ -64,6 +64,7 @@ private:
bool _finalized;
int _frames_written;
int _frame_buffer_offset;
+ MXFMetadata _metadata;
};
/** @brief An asset made up of WAV files */
@@ -86,7 +87,8 @@ public:
std::string mxf_name,
boost::signals2::signal<void (float)>* progress,
int fps,
- int intrinsic_duration
+ int intrinsic_duration,
+ MXFMetadata const & metadata = MXFMetadata ()
);
/** Construct a SoundAsset, generating the MXF from some WAV files.
@@ -106,7 +108,8 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- int channels
+ int channels,
+ MXFMetadata const & metadata = MXFMetadata ()
);
SoundAsset (
@@ -122,7 +125,7 @@ public:
int sampling_rate
);
- boost::shared_ptr<SoundAssetWriter> start_write ();
+ boost::shared_ptr<SoundAssetWriter> start_write (MXFMetadata const & metadata = MXFMetadata ());
/** Write details of this asset to a CPL stream.
* @param s Stream.
@@ -142,7 +145,7 @@ public:
}
private:
- void construct (boost::function<std::string (Channel)> get_path);
+ void construct (boost::function<std::string (Channel)> get_path, MXFMetadata const &);
std::string path_from_channel (Channel channel, std::vector<std::string> const & files);
/** Number of channels in the asset */
diff --git a/src/test_mode.cc b/src/test_mode.cc
deleted file mode 100644
index bfe10fee..00000000
--- a/src/test_mode.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/test_mode.cc
- * @brief A method to enable test mode for libdcp.
- */
-
-#include "KM_prng.h"
-#include "test_mode.h"
-#include "metadata.h"
-
-/** Calling this will seed the random number generator used to
- * generate UUIDs with a known value, and set the DCP issue
- * date to 1st January 2012 at midnight. This means that
- * two runs of libdcp with the same inputs will produce
- * the same output.
- */
-
-void
-libdcp::enable_test_mode ()
-{
- Kumu::libdcp_test = true;
- Metadata::instance()->issue_date = "2012-01-01T00:00:00+00:00";
-
- /* Remove version strings */
- Metadata::instance()->issuer = "libdcp-test";
- Metadata::instance()->creator = "libdcp-test";
- Metadata::instance()->product_version = "test";
-}
diff --git a/src/test_mode.h b/src/test_mode.h
deleted file mode 100644
index b2e671d5..00000000
--- a/src/test_mode.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/test_mode.h
- * @brief A method to enable test mode for libdcp.
- */
-
-namespace libdcp
-{
-
-extern void enable_test_mode ();
-
-}
diff --git a/src/wscript b/src/wscript
index 3960f2b0..81c39926 100644
--- a/src/wscript
+++ b/src/wscript
@@ -14,6 +14,7 @@ def build(bld):
asset_map.cc
cpl_file.cc
dcp.cc
+ cpl.cc
dcp_time.cc
gamma_lut.cc
metadata.cc
@@ -26,7 +27,6 @@ def build(bld):
sound_asset.cc
sound_frame.cc
subtitle_asset.cc
- test_mode.cc
types.cc
util.cc
version.cc
@@ -35,6 +35,7 @@ def build(bld):
headers = """
asset.h
+ cpl.h
dcp.h
dcp_time.h
exceptions.h
@@ -47,7 +48,6 @@ def build(bld):
sound_asset.h
sound_frame.h
subtitle_asset.h
- test_mode.h
types.h
util.h
version.h