summaryrefslogtreecommitdiff
path: root/src/dcp.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2012-07-16 19:24:44 +0100
committerCarl Hetherington <cth@carlh.net>2012-07-16 19:24:44 +0100
commit7d48446b5efdf795df1ce22d6d9ed3ebe85d3381 (patch)
treef492aebd71fae087e7903dafc097d3899cff8481 /src/dcp.cc
Import.
Diffstat (limited to 'src/dcp.cc')
-rw-r--r--src/dcp.cc270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/dcp.cc b/src/dcp.cc
new file mode 100644
index 00000000..0ba4ed72
--- /dev/null
+++ b/src/dcp.cc
@@ -0,0 +1,270 @@
+/*
+ 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 <sstream>
+#include <fstream>
+#include <iomanip>
+#include <cassert>
+#include <boost/filesystem.hpp>
+#include "dcp.h"
+#include "asset.h"
+#include "sound_asset.h"
+#include "picture_asset.h"
+#include "util.h"
+#include "tags.h"
+
+using namespace std;
+using namespace boost;
+using namespace libdcp;
+
+/** Construct a DCP.
+ * @param d Directory to write files to.
+ */
+DCP::DCP (string d, string n, ContentType c, int fps, int length)
+ : _directory (d)
+ , _name (n)
+ , _content_type (c)
+ , _fps (fps)
+ , _length (length)
+{
+ char buffer[64];
+ time_t now;
+ time (&now);
+ struct tm* tm = localtime (&now);
+ strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S+00:00", tm);
+ _date = string (buffer);
+}
+
+void
+DCP::add_sound_asset (list<string> const & files)
+{
+ filesystem::path p;
+ p /= _directory;
+ p /= "audio.mxf";
+ _assets.push_back (shared_ptr<SoundAsset> (new SoundAsset (files, p.string(), _fps, _length)));
+}
+
+void
+DCP::add_picture_asset (list<string> const & files, int w, int h)
+{
+ filesystem::path p;
+ p /= _directory;
+ p /= "video.mxf";
+ _assets.push_back (shared_ptr<PictureAsset> (new PictureAsset (files, p.string(), _fps, _length, w, h)));
+}
+
+/** Write the required XML files to the directory that was
+ * passed into the constructor.
+ */
+void
+DCP::write_xml () const
+{
+ string cpl_uuid = make_uuid ();
+ string cpl_path = write_cpl (cpl_uuid);
+ int cpl_length = filesystem::file_size (cpl_path);
+ string cpl_digest = make_digest (cpl_path);
+
+ string pkl_uuid = make_uuid ();
+ string pkl_path = write_pkl (pkl_uuid, cpl_uuid, cpl_digest, cpl_length);
+
+ write_volindex ();
+ write_assetmap (cpl_uuid, cpl_length, pkl_uuid, filesystem::file_size (pkl_path));
+}
+
+/** Write the CPL file.
+ * @param cpl_uuid UUID to use.
+ * @return CPL pathname.
+ */
+string
+DCP::write_cpl (string cpl_uuid) const
+{
+ filesystem::path p;
+ p /= _directory;
+ stringstream s;
+ s << cpl_uuid << "_cpl.xml";
+ p /= s.str();
+ ofstream cpl (p.string().c_str());
+
+ cpl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ << "<CompositionPlaylist xmlns=\"http://www.smpte-ra.org/schemas/429-7/2006/CPL\">\n"
+ << " <Id>urn:uuid:" << cpl_uuid << "</Id>\n"
+ << " <AnnotationText>" << _name << "</AnnotationText>\n"
+ << " <IssueDate>" << _date << "</IssueDate>\n"
+ << " <Creator>libdcp " << Tags::instance()->creator << "</Creator>\n"
+ << " <ContentTitleText>" << _name << "</ContentTitleText>\n"
+ << " <ContentKind>" << _content_type << "</ContentKind>\n"
+ << " <ContentVersion>\n"
+ << " <Id>urn:uri:" << cpl_uuid << "_" << _date << "</Id>\n"
+ << " <LabelText>" << cpl_uuid << "_" << _date << "</LabelText>\n"
+ << " </ContentVersion>\n"
+ << " <RatingList/>\n"
+ << " <ReelList>\n";
+
+ cpl << " <Reel>\n"
+ << " <Id>urn:uuid:" << make_uuid() << "</Id>\n"
+ << " <AssetList>\n";
+
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_cpl (cpl);
+ }
+
+ cpl << " </AssetList>\n"
+ << " </Reel>\n"
+ << " </ReelList>\n"
+ << "</CompositionPlaylist>\n";
+
+ return p.string ();
+}
+
+/** Write the PKL file.
+ * @param pkl_uuid UUID to use.
+ * @param cpl_uuid UUID of the CPL file.
+ * @param cpl_digest SHA digest of the CPL file.
+ * @param cpl_length Length of the CPL file in bytes.
+ */
+std::string
+DCP::write_pkl (string pkl_uuid, string cpl_uuid, string cpl_digest, int cpl_length) const
+{
+ filesystem::path p;
+ p /= _directory;
+ stringstream s;
+ s << pkl_uuid << "_pkl.xml";
+ p /= s.str();
+ ofstream pkl (p.string().c_str());
+
+ pkl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ << "<PackingList xmlns=\"http://www.smpte-ra.org/schemas/429-8/2007/PKL\">\n"
+ << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n"
+ << " <AnnotationText>" << _name << "</AnnotationText>\n"
+ << " <IssueDate>" << _date << "</IssueDate>\n"
+ << " <Issuer>" << Tags::instance()->issuer << "</Issuer>\n"
+ << " <Creator>" << Tags::instance()->creator << "</Creator>\n"
+ << " <AssetList>\n";
+
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_pkl (pkl);
+ }
+
+ pkl << " <Asset>\n"
+ << " <Id>urn:uuid" << cpl_uuid << "</Id>\n"
+ << " <Hash>" << cpl_digest << "</Hash>\n"
+ << " <Size>" << cpl_length << "</Size>\n"
+ << " <Type>text/xml</Type>\n"
+ << " </Asset>\n";
+
+ pkl << " </AssetList>\n"
+ << "</PackingList>\n";
+
+ return p.string ();
+}
+
+void
+DCP::write_volindex () const
+{
+ filesystem::path p;
+ p /= _directory;
+ p /= "VOLINDEX.xml";
+ ofstream vi (p.string().c_str());
+
+ vi << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ << "<VolumeIndex xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n"
+ << " <Index>1</Index>\n"
+ << "</VolumeIndex>\n";
+}
+
+void
+DCP::write_assetmap (string cpl_uuid, int cpl_length, string pkl_uuid, int pkl_length) const
+{
+ filesystem::path p;
+ p /= _directory;
+ p /= "ASSETMAP.xml";
+ ofstream am (p.string().c_str());
+
+ 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>" << Tags::instance()->creator << "</Creator>\n"
+ << " <VolumeCount>1</VolumeCount>\n"
+ << " <IssueDate>" << _date << "</IssueDate>\n"
+ << " <Issuer>" << Tags::instance()->issuer << "</Issuer>\n"
+ << " <AssetList>\n";
+
+ am << " <Asset>\n"
+ << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n"
+ << " <PackingList>true</PackingList>\n"
+ << " <ChunkList>\n"
+ << " <Chunk>\n"
+ << " <Path>" << pkl_uuid << "_pkl.xml</Path>\n"
+ << " <VolumeIndex>1</VolumeIndex>\n"
+ << " <Offset>0</Offset>\n"
+ << " <Length>" << pkl_length << "</Length>\n"
+ << " </Chunk>\n"
+ << " </ChunkList>\n"
+ << " </Asset>\n";
+
+ am << " <Asset>\n"
+ << " <Id>urn:uuid:" << cpl_uuid << "</Id>\n"
+ << " <ChunkList>\n"
+ << " <Chunk>\n"
+ << " <Path>" << cpl_uuid << "_cpl.xml</Path>\n"
+ << " <VolumeIndex>1</VolumeIndex>\n"
+ << " <Offset>0</Offset>\n"
+ << " <Length>" << cpl_length << "</Length>\n"
+ << " </Chunk>\n"
+ << " </ChunkList>\n"
+ << " </Asset>\n";
+
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_assetmap (am);
+ }
+
+ am << " </AssetList>\n"
+ << "</AssetMap>\n";
+}
+
+
+string
+DCP::content_type_string (ContentType t)
+{
+ switch (t) {
+ case FEATURE:
+ return "feature";
+ case SHORT:
+ return "short";
+ case TRAILER:
+ return "trailer";
+ case TEST:
+ return "test";
+ case TRANSITIONAL:
+ return "transitional";
+ case RATING:
+ return "rating";
+ case TEASER:
+ return "teaser";
+ case POLICY:
+ return "policy";
+ case PUBLIC_SERVICE_ANNOUNCEMENT:
+ return "psa";
+ case ADVERTISEMENT:
+ return "advertisement";
+ }
+
+ assert (false);
+}
+