Import.
authorCarl Hetherington <cth@carlh.net>
Mon, 16 Jul 2012 18:24:44 +0000 (19:24 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 16 Jul 2012 18:24:44 +0000 (19:24 +0100)
56 files changed:
.gitignore [new file with mode: 0644]
run-tests.sh [new file with mode: 0755]
src/asset.cc [new file with mode: 0644]
src/asset.h [new file with mode: 0644]
src/dcp.cc [new file with mode: 0644]
src/dcp.h [new file with mode: 0644]
src/picture_asset.cc [new file with mode: 0644]
src/picture_asset.h [new file with mode: 0644]
src/sound_asset.cc [new file with mode: 0644]
src/sound_asset.h [new file with mode: 0644]
src/tags.cc [new file with mode: 0644]
src/tags.h [new file with mode: 0644]
src/util.cc [new file with mode: 0644]
src/util.h [new file with mode: 0644]
src/wscript [new file with mode: 0644]
test/data/1s_24-bit_48k_silence.wav [new file with mode: 0644]
test/data/32x32_red_square.j2c [new file with mode: 0644]
test/data/32x32_red_square.png [new file with mode: 0644]
test/ref/DCP/02020202-0202-0202-0202-020202020202_cpl.xml [new file with mode: 0644]
test/ref/DCP/04040404-0404-0404-0404-040404040404_pkl.xml [new file with mode: 0644]
test/ref/DCP/ASSETMAP.xml [new file with mode: 0644]
test/ref/DCP/VOLINDEX.xml [new file with mode: 0644]
test/ref/DCP/audio.mxf [new file with mode: 0644]
test/ref/DCP/video.dump [new file with mode: 0644]
test/ref/DCP/video.mxf [new file with mode: 0644]
test/ref/j2c/1.j2c [new symlink]
test/ref/j2c/10.j2c [new symlink]
test/ref/j2c/11.j2c [new symlink]
test/ref/j2c/12.j2c [new symlink]
test/ref/j2c/13.j2c [new symlink]
test/ref/j2c/14.j2c [new symlink]
test/ref/j2c/15.j2c [new symlink]
test/ref/j2c/16.j2c [new symlink]
test/ref/j2c/17.j2c [new symlink]
test/ref/j2c/18.j2c [new symlink]
test/ref/j2c/19.j2c [new symlink]
test/ref/j2c/2.j2c [new symlink]
test/ref/j2c/20.j2c [new symlink]
test/ref/j2c/21.j2c [new symlink]
test/ref/j2c/22.j2c [new symlink]
test/ref/j2c/23.j2c [new symlink]
test/ref/j2c/24.j2c [new symlink]
test/ref/j2c/3.j2c [new symlink]
test/ref/j2c/4.j2c [new symlink]
test/ref/j2c/5.j2c [new symlink]
test/ref/j2c/6.j2c [new symlink]
test/ref/j2c/7.j2c [new symlink]
test/ref/j2c/8.j2c [new symlink]
test/ref/j2c/9.j2c [new symlink]
test/ref/make.sh [new file with mode: 0644]
test/ref/wav/1.wav [new symlink]
test/ref/wav/2.wav [new symlink]
test/tests.cc [new file with mode: 0644]
test/wscript [new file with mode: 0644]
waf [new file with mode: 0755]
wscript [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..62449d4
--- /dev/null
@@ -0,0 +1,5 @@
+core
+*~
+build
+.waf*
+.lock*
\ No newline at end of file
diff --git a/run-tests.sh b/run-tests.sh
new file mode 100755 (executable)
index 0000000..08db5a8
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+LD_LIBRARY_PATH=build/src
+build/test/tests
+diff -ur build/test/foo test/ref/DCP
\ No newline at end of file
diff --git a/src/asset.cc b/src/asset.cc
new file mode 100644 (file)
index 0000000..2101e4b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+    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 <boost/filesystem.hpp>
+#include <AS_DCP.h>
+#include <KM_util.h>
+#include "asset.h"
+#include "util.h"
+#include "tags.h"
+
+using namespace std;
+using namespace boost;
+using namespace libdcp;
+
+/** Construct an Asset.
+ *  @param p Pathname of MXF file.
+ *  @param fps Frames per second.
+ *  @param len Length in frames.
+ */
+
+Asset::Asset (string p, int fps, int len)
+       : _mxf_path (p)
+       , _fps (fps)
+       , _length (len)
+       , _uuid (make_uuid ())
+{
+       
+}
+
+void
+Asset::write_to_pkl (ostream& s) const
+{
+       s << "      <Id>urn:uuid:" << _uuid << "</Id>\n"
+         << "      <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n"
+         << "      <Hash>" << _digest << "</Hash>\n"
+         << "      <Size>" << filesystem::file_size(_mxf_path) << "</Size>\n"
+         << "      <Type>application/mxf</Type>\n";
+}
+
+void
+Asset::write_to_assetmap (ostream& s) const
+{
+       s << "    <Asset>\n"
+         << "      <Id>urn:uuid:" << _uuid << "</Id>\n"
+         << "      <ChunkList>\n"
+         << "        <Chunk>\n"
+         << "          <Path>" << filesystem::path(_mxf_path).filename() << "</Path>\n"
+         << "          <VolumeIndex>1</VolumeIndex>\n"
+         << "          <Offset>0</Offset>\n"
+         << "          <Length>" << filesystem::file_size(_mxf_path) << "</Length>\n"
+         << "        </Chunk>\n"
+         << "      </ChunkList>\n"
+         << "    </Asset>\n";
+}
+
+void
+Asset::fill_writer_info (ASDCP::WriterInfo* writer_info) const
+{
+       writer_info->ProductVersion = Tags::instance()->product_version;
+       writer_info->CompanyName = Tags::instance()->company_name;
+       writer_info->ProductName = Tags::instance()->product_name.c_str();
+
+       writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
+       Kumu::GenRandomUUID (writer_info->AssetUUID);
+}
diff --git a/src/asset.h b/src/asset.h
new file mode 100644 (file)
index 0000000..ce742d1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    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_ASSET_H
+#define LIBDCP_ASSET_H
+
+#include <string>
+#include <sigc++/sigc++.h>
+
+namespace ASDCP {
+       class WriterInfo;
+}
+
+namespace libdcp
+{
+
+class Asset
+{
+public:
+       Asset (std::string, int, int);
+
+       virtual void write_to_cpl (std::ostream &) const = 0;
+       void write_to_pkl (std::ostream &) const;
+       void write_to_assetmap (std::ostream &) const;
+
+       sigc::signal1<void, float> Progress;
+
+protected:
+       void fill_writer_info (ASDCP::WriterInfo *) const;
+
+       std::string _mxf_path;
+       int _fps;
+       int _length;
+       std::string _uuid;
+       std::string _digest;
+};
+
+}
+
+#endif
diff --git a/src/dcp.cc b/src/dcp.cc
new file mode 100644 (file)
index 0000000..0ba4ed7
--- /dev/null
@@ -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);
+}
+               
diff --git a/src/dcp.h b/src/dcp.h
new file mode 100644 (file)
index 0000000..27be9ec
--- /dev/null
+++ b/src/dcp.h
@@ -0,0 +1,72 @@
+/*
+    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 <string>
+#include <list>
+#include <boost/shared_ptr.hpp>
+
+namespace libdcp
+{
+
+class Asset;   
+
+class DCP
+{
+public:
+       enum ContentType
+       {
+               FEATURE,
+               SHORT,
+               TRAILER,
+               TEST,
+               TRANSITIONAL,
+               RATING,
+               TEASER,
+               POLICY,
+               PUBLIC_SERVICE_ANNOUNCEMENT,
+               ADVERTISEMENT
+       };
+       
+       DCP (std::string, std::string, ContentType, int, int);
+
+       void add_sound_asset (std::list<std::string> const &);
+       void add_picture_asset (std::list<std::string> const &, int, int);
+
+       void write_xml () const;
+
+private:
+
+       std::string write_cpl (std::string) const;
+       std::string write_pkl (std::string, std::string, std::string, int) const;
+       void write_volindex () const;
+       void write_assetmap (std::string, int, std::string, int) const;
+
+       static std::string content_type_string (ContentType);
+
+       std::string _directory;
+       std::string _name;
+       ContentType _content_type;
+       int _fps;
+       int _length;
+       std::list<boost::shared_ptr<Asset> > _assets;
+
+       std::string _date;
+};
+
+}
diff --git a/src/picture_asset.cc b/src/picture_asset.cc
new file mode 100644 (file)
index 0000000..4e3b022
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+    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 <stdexcept>
+#include <iostream>
+#include <boost/filesystem.hpp>
+#include <AS_DCP.h>
+#include <KM_fileio.h>
+#include "picture_asset.h"
+#include "util.h"
+
+using namespace std;
+using namespace boost;
+using namespace libdcp;
+
+PictureAsset::PictureAsset (list<string> const & files, string p, int fps, int len, int w, int h)
+       : Asset (p, fps, len)
+       , _width (w)
+       , _height (h)
+{
+       ASDCP::JP2K::CodestreamParser j2k_parser;
+       ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
+       if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (files.front().c_str(), frame_buffer))) {
+               throw runtime_error ("could not open J2K file for reading");
+       }
+       
+       ASDCP::JP2K::PictureDescriptor picture_desc;
+       j2k_parser.FillPictureDescriptor (picture_desc);
+       /* XXX: we round for DCP: not sure if this is right */
+       picture_desc.EditRate = ASDCP::Rational (_fps, 1);
+       
+       ASDCP::WriterInfo writer_info;
+       fill_writer_info (&writer_info);
+       
+       ASDCP::JP2K::MXFWriter mxf_writer;
+       if (ASDCP_FAILURE (mxf_writer.OpenWrite (_mxf_path.c_str(), writer_info, picture_desc))) {
+               throw runtime_error ("could not open MXF for writing");
+       }
+
+       int j = 0;
+       for (list<string>::const_iterator i = files.begin(); i != files.end(); ++i) {
+               if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (i->c_str(), frame_buffer))) {
+                       throw runtime_error ("could not open J2K file for reading");
+               }
+
+               /* XXX: passing 0 to WriteFrame ok? */
+               if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) {
+                       throw runtime_error ("error in writing video MXF");
+               }
+               
+               ++j;
+               Progress (float (j) / files.size ());
+       }
+       
+       if (ASDCP_FAILURE (mxf_writer.Finalize())) {
+               throw runtime_error ("error in finalising video MXF");
+       }
+
+       _digest = make_digest (_mxf_path);
+}
+
+void
+PictureAsset::write_to_cpl (ostream& s) const
+{
+       s << "        <MainPicture>\n"
+         << "          <Id>" << _uuid << "</Id>\n"
+         << "          <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n"
+         << "          <EditRate>" << _fps << "</EditRate>\n"
+         << "          <IntrinsicDuration>" << _length << "</IntrinsicDuration>\n"
+         << "          <EntryPoint>0</EntryPoint>\n"
+         << "          <Duration>" << _length << "</Duration>\n"
+         << "          <FrameRate>" << _fps << "</FrameRate>\n"
+         << "          <ScreenAspectRatio>" << _width << " " << _height << "</ScreenAspectRatio>\n"
+         << "        </MainPicture>\n";
+}
diff --git a/src/picture_asset.h b/src/picture_asset.h
new file mode 100644 (file)
index 0000000..cef5367
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    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 "asset.h"
+
+namespace libdcp
+{
+
+class PictureAsset : public Asset
+{
+public:
+       PictureAsset (std::list<std::string> const &, std::string, int, int, int, int);
+
+       void write_to_cpl (std::ostream &) const;
+
+private:
+       int _width;
+       int _height;
+};
+
+}
diff --git a/src/sound_asset.cc b/src/sound_asset.cc
new file mode 100644 (file)
index 0000000..3008371
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+    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 <iostream>
+#include <stdexcept>
+#include <boost/filesystem.hpp>
+#include <AS_DCP.h>
+#include "sound_asset.h"
+#include "util.h"
+
+using namespace std;
+using namespace boost;
+using namespace libdcp;
+
+SoundAsset::SoundAsset (list<string> const & files, string p, int fps, int len)
+       : Asset (p, fps, len)
+{
+       ASDCP::Rational asdcp_fps (_fps, 1);
+       
+       ASDCP::PCM::WAVParser pcm_parser_channel[files.size()];
+       if (pcm_parser_channel[0].OpenRead (files.front().c_str(), asdcp_fps)) {
+               throw runtime_error ("could not open WAV file for reading");
+       }
+       
+       ASDCP::PCM::AudioDescriptor audio_desc;
+       pcm_parser_channel[0].FillAudioDescriptor (audio_desc);
+       audio_desc.ChannelCount = 0;
+       audio_desc.BlockAlign = 0;
+       audio_desc.EditRate = asdcp_fps;
+       audio_desc.AvgBps = audio_desc.AvgBps * files.size ();
+
+       ASDCP::PCM::FrameBuffer frame_buffer_channel[files.size()];
+       ASDCP::PCM::AudioDescriptor audio_desc_channel[files.size()];
+       
+       int j = 0;
+       for (list<string>::const_iterator i = files.begin(); i != files.end(); ++i) {
+               
+               if (ASDCP_FAILURE (pcm_parser_channel[j].OpenRead (i->c_str(), asdcp_fps))) {
+                       throw runtime_error ("could not open WAV file for reading");
+               }
+
+               pcm_parser_channel[j].FillAudioDescriptor (audio_desc_channel[j]);
+               frame_buffer_channel[j].Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc_channel[j]));
+
+               audio_desc.ChannelCount += audio_desc_channel[j].ChannelCount;
+               audio_desc.BlockAlign += audio_desc_channel[j].BlockAlign;
+               ++j;
+       }
+
+       ASDCP::PCM::FrameBuffer frame_buffer;
+       frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
+       frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
+
+       ASDCP::WriterInfo writer_info;
+       fill_writer_info (&writer_info);
+
+       ASDCP::PCM::MXFWriter mxf_writer;
+       if (ASDCP_FAILURE (mxf_writer.OpenWrite (_mxf_path.c_str(), writer_info, audio_desc))) {
+               throw runtime_error ("could not open audio MXF for writing");
+       }
+
+       for (int i = 0; i < _length; ++i) {
+
+               byte_t *data_s = frame_buffer.Data();
+               byte_t *data_e = data_s + frame_buffer.Capacity();
+               byte_t sample_size = ASDCP::PCM::CalcSampleSize (audio_desc_channel[0]);
+               int offset = 0;
+
+               for (list<string>::size_type j = 0; j < files.size(); ++j) {
+                       memset (frame_buffer_channel[j].Data(), 0, frame_buffer_channel[j].Capacity());
+                       if (ASDCP_FAILURE (pcm_parser_channel[j].ReadFrame (frame_buffer_channel[j]))) {
+                               throw runtime_error ("could not read audio frame");
+                       }
+                       
+                       if (frame_buffer_channel[j].Size() != frame_buffer_channel[j].Capacity()) {
+                               throw runtime_error ("short audio frame");
+                       }
+               }
+
+               while (data_s < data_e) {
+                       for (list<string>::size_type j = 0; j < files.size(); ++j) {
+                               byte_t* frame = frame_buffer_channel[j].Data() + offset;
+                               memcpy (data_s, frame, sample_size);
+                               data_s += sample_size;
+                       }
+                       offset += sample_size;
+               }
+
+               if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) {
+                       throw runtime_error ("could not write audio MXF frame");
+               }
+
+               Progress (float (i) / _length);
+       }
+
+       if (ASDCP_FAILURE (mxf_writer.Finalize())) {
+               throw runtime_error ("could not finalise audio MXF");
+       }
+
+       _digest = make_digest (_mxf_path);
+}
+
+void
+SoundAsset::write_to_cpl (ostream& s) const
+{
+       s << "        <MainSound>\n"
+         << "          <Id>" << _uuid << "</Id>\n"
+         << "          <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n"
+         << "          <EditRate>" << _fps << "</EditRate>\n"
+         << "          <IntrinsicDuration>" << _length << "</IntrinsicDuration>\n"
+         << "          <EntryPoint>0</EntryPoint>\n"
+         << "          <Duration>" << _length << "</Duration>\n"
+         << "        </MainSound>\n";
+}
+
diff --git a/src/sound_asset.h b/src/sound_asset.h
new file mode 100644 (file)
index 0000000..8c63b53
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    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 "asset.h"
+
+namespace libdcp
+{
+
+class SoundAsset : public Asset
+{
+public:
+       SoundAsset (std::list<std::string> const &, std::string, int, int);
+
+       void write_to_cpl (std::ostream &) const;
+};
+
+}
diff --git a/src/tags.cc b/src/tags.cc
new file mode 100644 (file)
index 0000000..40aeeea
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    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 "tags.h"
+
+using namespace std;
+using namespace libdcp;
+
+Tags* Tags::_instance = 0;
+
+Tags::Tags ()
+       : company_name ("libdcp")
+       , product_name ("libdcp")
+       , product_version (LIBDCP_VERSION)
+       , issuer ("libdcp" LIBDCP_VERSION)
+       , creator ("libdcp" LIBDCP_VERSION)
+{
+
+}
+
+Tags *
+Tags::instance ()
+{
+       if (_instance == 0) {
+               _instance = new Tags;
+       }
+
+       return _instance;
+}
+               
diff --git a/src/tags.h b/src/tags.h
new file mode 100644 (file)
index 0000000..036bd4e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+    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 <string>
+
+namespace libdcp
+{
+
+class Tags
+{
+public:
+       static Tags* instance ();
+
+       std::string company_name;
+       std::string product_name;
+       std::string product_version;
+       std::string issuer;
+       std::string creator;
+
+private:
+       Tags ();
+       
+       static Tags* _instance;
+};
+
+}
diff --git a/src/util.cc b/src/util.cc
new file mode 100644 (file)
index 0000000..aab2e18
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+    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 <stdexcept>
+#include <sstream>
+#include <iomanip>
+#include <openssl/sha.h>
+#include "KM_util.h"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include "util.h"
+
+using namespace std;
+
+bool libdcp::libdcp_test = false;
+
+/** Create a UUID.
+ *  @return UUID.
+ */
+string
+libdcp::make_uuid ()
+{
+       char buffer[64];
+       Kumu::UUID id;
+
+       if (libdcp_test) {
+               static int N = 0;
+               byte_t t[16];
+               for (int i = 0; i < 16; ++i) {
+                       t[i] = N;
+               }
+               ++N;
+               
+               id = Kumu::UUID (t);
+       } else {
+               Kumu::GenRandomValue (id);
+       }
+       
+       id.EncodeHex (buffer, 64);
+       return string (buffer);
+}
+
+/** Create a digest for a file.
+ *  @param filename File name.
+ *  @return Digest.
+ */
+string
+libdcp::make_digest (string filename)
+{
+       Kumu::FileReader reader;
+       if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) {
+               throw runtime_error ("could not open file to compute digest");
+       }
+       
+       SHA_CTX sha;
+       SHA1_Init (&sha);
+       
+       Kumu::ByteString read_buffer (65536);
+       while (1) {
+               ui32_t read = 0;
+               Kumu::Result_t r = reader.Read (read_buffer.Data(), read_buffer.Capacity(), &read);
+               
+               if (r == Kumu::RESULT_ENDOFFILE) {
+                       break;
+               } else if (ASDCP_FAILURE (r)) {
+                       throw runtime_error ("could not read file to compute digest");
+               }
+               
+               SHA1_Update (&sha, read_buffer.Data(), read);
+       }
+
+       byte_t byte_buffer[20];
+       SHA1_Final (byte_buffer, &sha);
+
+       stringstream s;
+       char digest[64];
+       s << setfill('0') << setw(36) << Kumu::base64encode (byte_buffer, 20, digest, 64);
+       return s.str ();
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644 (file)
index 0000000..fcb6d73
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    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 <string>
+
+namespace libdcp {
+       
+extern std::string make_uuid ();
+extern std::string make_digest (std::string);
+extern bool libdcp_test;
+
+}
diff --git a/src/wscript b/src/wscript
new file mode 100644 (file)
index 0000000..22b75b9
--- /dev/null
@@ -0,0 +1,14 @@
+def build(bld):
+    obj = bld(features = 'cxx cxxshlib')
+    obj.name = 'libdcp'
+    obj.export_includes = ['.']
+    obj.uselib = 'ASDCP KUMU BOOST_FILESYSTEM OPENSSL SIGC++'
+    obj.source = """
+                 dcp.cc
+                 asset.cc
+                 sound_asset.cc
+                 picture_asset.cc
+                 util.cc
+                 tags.cc
+                 """
+    obj.target = 'libdcp'
diff --git a/test/data/1s_24-bit_48k_silence.wav b/test/data/1s_24-bit_48k_silence.wav
new file mode 100644 (file)
index 0000000..5bfc14d
Binary files /dev/null and b/test/data/1s_24-bit_48k_silence.wav differ
diff --git a/test/data/32x32_red_square.j2c b/test/data/32x32_red_square.j2c
new file mode 100644 (file)
index 0000000..027929b
Binary files /dev/null and b/test/data/32x32_red_square.j2c differ
diff --git a/test/data/32x32_red_square.png b/test/data/32x32_red_square.png
new file mode 100644 (file)
index 0000000..49cd2be
Binary files /dev/null and b/test/data/32x32_red_square.png differ
diff --git a/test/ref/DCP/02020202-0202-0202-0202-020202020202_cpl.xml b/test/ref/DCP/02020202-0202-0202-0202-020202020202_cpl.xml
new file mode 100644 (file)
index 0000000..cc5e933
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:488d58ab-474e-4b01-a2cb-a6ce1e5e70b3</Id>
+  <AnnotationText>A Test DCP</AnnotationText>
+  <IssueDate>2012-07-16T06:28:27+00:00</IssueDate>
+  <Creator>OpenDCP 0.0.25</Creator>
+  <ContentTitleText>A Test DCP</ContentTitleText>
+  <ContentKind>feature</ContentKind>
+  <ContentVersion>
+    <Id>urn:uri:488d58ab-474e-4b01-a2cb-a6ce1e5e70b3_2012-07-16T06:28:27+00:00</Id>
+    <LabelText>488d58ab-474e-4b01-a2cb-a6ce1e5e70b3_2012-07-16T06:28:27+00:00</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:b4f8f14e-63d9-4d34-9b8d-11d158d77115</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:0a2335fe-09a3-4a19-b5ea-2e0308e727b3</Id>
+          <AnnotationText>video.mxf</AnnotationText>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>32 32</ScreenAspectRatio>
+        </MainPicture>
+        <MainSound>
+          <Id>urn:uuid:ac884d5a-1d72-425b-a45b-d0c0bce4f6f4</Id>
+          <AnnotationText>audio.mxf</AnnotationText>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+        </MainSound>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/ref/DCP/04040404-0404-0404-0404-040404040404_pkl.xml b/test/ref/DCP/04040404-0404-0404-0404-040404040404_pkl.xml
new file mode 100644 (file)
index 0000000..76f1292
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PackingList xmlns="http://www.smpte-ra.org/schemas/429-8/2007/PKL">
+  <Id>urn:uuid:caaf9bfe-2a00-4b95-b6d3-d6c0b181e17b</Id>
+  <AnnotationText>A Test DCP</AnnotationText>
+  <IssueDate>2012-07-16T06:28:27+00:00</IssueDate>
+  <Issuer>OpenDCP 0.0.25</Issuer>
+  <Creator>OpenDCP 0.0.25</Creator>
+  <AssetList>
+    <Asset>
+      <Id>urn:uuid:0a2335fe-09a3-4a19-b5ea-2e0308e727b3</Id>
+      <AnnotationText>video.mxf</AnnotationText>
+      <Hash>ETDlJzvJT98gAc2Y84/4AoXQuhs=</Hash>
+      <Size>26080</Size>
+      <Type>application/mxf</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:ac884d5a-1d72-425b-a45b-d0c0bce4f6f4</Id>
+      <AnnotationText>audio.mxf</AnnotationText>
+      <Hash>duYsdzeBVwuv5EfxvLmshyBQdo0=</Hash>
+      <Size>305326</Size>
+      <Type>application/mxf</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:488d58ab-474e-4b01-a2cb-a6ce1e5e70b3</Id>
+      <Hash>RanewioDBtecLpvB7W2v/g9/vos=</Hash>
+      <Size>1526</Size>
+      <Type>text/xml</Type>
+    </Asset>
+  </AssetList>
+</PackingList>
diff --git a/test/ref/DCP/ASSETMAP.xml b/test/ref/DCP/ASSETMAP.xml
new file mode 100644 (file)
index 0000000..dff8685
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AssetMap xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
+  <Id>urn:uuid:7193f3d3-4083-4e4d-9a35-b108dad4e305</Id>
+  <Creator>OpenDCP 0.0.25</Creator>
+  <VolumeCount>1</VolumeCount>
+  <IssueDate>2012-07-16T06:28:27+00:00</IssueDate>
+  <Issuer>OpenDCP 0.0.25</Issuer>
+  <AssetList>
+    <Asset>
+      <Id>urn:uuid:caaf9bfe-2a00-4b95-b6d3-d6c0b181e17b</Id>
+      <PackingList>true</PackingList>
+      <ChunkList>
+        <Chunk>
+          <Path>caaf9bfe-2a00-4b95-b6d3-d6c0b181e17b_pkl.xml</Path>
+          <VolumeIndex>1</VolumeIndex>
+          <Offset>0</Offset>
+          <Length>1049</Length>
+        </Chunk>
+      </ChunkList>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:488d58ab-474e-4b01-a2cb-a6ce1e5e70b3</Id>
+      <ChunkList>
+        <Chunk>
+          <Path>488d58ab-474e-4b01-a2cb-a6ce1e5e70b3_cpl.xml</Path>
+          <VolumeIndex>1</VolumeIndex>
+          <Offset>0</Offset>
+          <Length>1526</Length>
+        </Chunk>
+      </ChunkList>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:0a2335fe-09a3-4a19-b5ea-2e0308e727b3</Id>
+      <ChunkList>
+        <Chunk>
+          <Path>video.mxf</Path>
+          <VolumeIndex>1</VolumeIndex>
+          <Offset>0</Offset>
+          <Length>26080</Length>
+        </Chunk>
+      </ChunkList>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:ac884d5a-1d72-425b-a45b-d0c0bce4f6f4</Id>
+      <ChunkList>
+        <Chunk>
+          <Path>audio.mxf</Path>
+          <VolumeIndex>1</VolumeIndex>
+          <Offset>0</Offset>
+          <Length>305326</Length>
+        </Chunk>
+      </ChunkList>
+    </Asset>
+  </AssetList>
+</AssetMap>
diff --git a/test/ref/DCP/VOLINDEX.xml b/test/ref/DCP/VOLINDEX.xml
new file mode 100644 (file)
index 0000000..f66c004
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VolumeIndex xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
+  <Index>1</Index>
+</VolumeIndex>
diff --git a/test/ref/DCP/audio.mxf b/test/ref/DCP/audio.mxf
new file mode 100644 (file)
index 0000000..06e9438
Binary files /dev/null and b/test/ref/DCP/audio.mxf differ
diff --git a/test/ref/DCP/video.dump b/test/ref/DCP/video.dump
new file mode 100644 (file)
index 0000000..c01dfd7
--- /dev/null
@@ -0,0 +1,302 @@
+Dump an MXF file using MXFLib
+- using dictionary "dict.xml"
+
+Partition at 0x00000000 is for BodySID 0x0000
+ClosedCompleteHeader
+  MajorVersion = 1
+  MinorVersion = 2
+  KAGSize = 1
+  ThisPartition = 0
+  PreviousPartition = 0
+  FooterPartition = 25476
+  HeaderByteCount = 16244
+  IndexByteCount = 0
+  IndexSID = 0
+  BodyOffset = 0
+  BodySID = 0
+  OperationalPattern = MXF Specialized OP Atom
+  EssenceContainers
+    EssenceContainer = MXF-GC Generic Essence Multiple Mappings
+    EssenceContainer = MXF-GC JPEG-2000 Picture Mappings
+
+Header Metadata:
+  Preface
+    InstanceUID = {772726eb-422b-478c-869c-679e550ee103}
+    LastModifiedDate = 2012-07-16 17:28:27.000
+    Version = 258
+    ObjectModelVersion = 0
+    PrimaryPackage -> Weak Reference to SourcePackage
+    Identifications
+      Identification = {7079b446-6e8c-4bfb-91d6-8e2053a0b4c2}
+      Identification -> Strong Reference to Identification
+        Identification
+          InstanceUID = {7079b446-6e8c-4bfb-91d6-8e2053a0b4c2}
+          ThisGenerationUID = {4f2bd67b-f257-4ed9-ac9d-6956bbe61c36}
+          CompanyName = OpenDCP
+          ProductName = OpenDCP
+          ProductVersion = Major="0", Minor="0", Patch="0", Build="0", Release="VersionUnknown"
+          VersionString = 0.0.25
+          ProductUID = {43059a1d-0432-4101-b83f-736815acf31d}
+          ModificationDate = 2012-07-16 17:28:27.000
+          ToolkitVersion = Major="1", Minor="8", Patch="44", Build="27240", Release="VersionReleased"
+          Platform = unix
+    ContentStorage = {f11189d2-31a5-4c7b-8608-59ff5d340245}
+    ContentStorage -> Strong Reference to ContentStorage
+      ContentStorage
+        InstanceUID = {f11189d2-31a5-4c7b-8608-59ff5d340245}
+        Packages
+          Package = {80a78644-dda6-43d7-a55b-77c4fec29654}
+          Package -> Strong Reference to MaterialPackage
+            MaterialPackage
+              InstanceUID = {80a78644-dda6-43d7-a55b-77c4fec29654}
+              PackageUID = [060a2b34.0101.0105.01010f20],13,00,00,00,{2542c57c-5a87-4834-918b-9f09153e10ca}
+              Name = AS-DCP Material Package
+              PackageCreationDate = 2012-07-16 17:28:27.000
+              PackageModifiedDate = 2012-07-16 17:28:27.000
+              Tracks
+                Tracks_Item = {79f6d86f-3f08-40b3-943b-e7e3b1819209}
+                Tracks_Item -> Strong Reference to Track
+                  Track
+                    InstanceUID = {79f6d86f-3f08-40b3-943b-e7e3b1819209}
+                    TrackID = 1
+                    TrackNumber = 0
+                    TrackName = Timecode Track
+                    Sequence = {6964beaf-d7fc-4f74-8d58-6a095850df00}
+                    Sequence -> Strong Reference to Sequence
+                      Sequence
+                        InstanceUID = {6964beaf-d7fc-4f74-8d58-6a095850df00}
+                        DataDefinition = SMPTE 12M Timecode Track
+                        Duration = 24
+                        StructuralComponents
+                          StructuralComponent = {9c28304b-6293-4651-8e20-ba11db057222}
+                          StructuralComponent -> Strong Reference to TimecodeComponent
+                            TimecodeComponent
+                              InstanceUID = {9c28304b-6293-4651-8e20-ba11db057222}
+                              DataDefinition = SMPTE 12M Timecode Track
+                              Duration = 24
+                              RoundedTimecodeBase = 24
+                              StartTimecode = 0
+                              DropFrame = 0
+                    EditRate = 24/1
+                    Origin = 0
+                Tracks_Item = {4cc1735a-c2e5-40c5-a3d8-4699d9d8f28a}
+                Tracks_Item -> Strong Reference to Track
+                  Track
+                    InstanceUID = {4cc1735a-c2e5-40c5-a3d8-4699d9d8f28a}
+                    TrackID = 2
+                    TrackNumber = 0
+                    TrackName = Picture Track
+                    Sequence = {85182d60-83d9-490d-9a6e-9939ea88593b}
+                    Sequence -> Strong Reference to Sequence
+                      Sequence
+                        InstanceUID = {85182d60-83d9-490d-9a6e-9939ea88593b}
+                        DataDefinition = Picture Essence Track
+                        Duration = 24
+                        StructuralComponents
+                          StructuralComponent = {8d1a4bab-3854-4110-a6c6-a8658947859e}
+                          StructuralComponent -> Strong Reference to SourceClip
+                            SourceClip
+                              InstanceUID = {8d1a4bab-3854-4110-a6c6-a8658947859e}
+                              DataDefinition = Picture Essence Track
+                              Duration = 24
+                              StartPosition = 0
+                              SourcePackageID = [060a2b34.0101.0105.01010f20],13,00,00,00,{0a2335fe-09a3-4a19-b5ea-2e0308e727b3}
+                              SourceTrackID = 2
+                    EditRate = 24/1
+                    Origin = 0
+          Package = {24569e0a-10e9-42b5-bbb6-c81b76ec6c7e}
+          Package -> Strong Reference to SourcePackage
+            SourcePackage
+              InstanceUID = {24569e0a-10e9-42b5-bbb6-c81b76ec6c7e}
+              PackageUID = [060a2b34.0101.0105.01010f20],13,00,00,00,{0a2335fe-09a3-4a19-b5ea-2e0308e727b3}
+              Name = File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams
+              PackageCreationDate = 2012-07-16 17:28:27.000
+              PackageModifiedDate = 2012-07-16 17:28:27.000
+              Tracks
+                Tracks_Item = {072c2857-9116-4802-98bb-1c585580baae}
+                Tracks_Item -> Strong Reference to Track
+                  Track
+                    InstanceUID = {072c2857-9116-4802-98bb-1c585580baae}
+                    TrackID = 1
+                    TrackNumber = 0
+                    TrackName = Timecode Track
+                    Sequence = {82f075be-eb53-47c2-b6d6-5aa053756248}
+                    Sequence -> Strong Reference to Sequence
+                      Sequence
+                        InstanceUID = {82f075be-eb53-47c2-b6d6-5aa053756248}
+                        DataDefinition = SMPTE 12M Timecode Track
+                        Duration = 24
+                        StructuralComponents
+                          StructuralComponent = {29dc1968-3487-4ef2-a156-949afe99fdab}
+                          StructuralComponent -> Strong Reference to TimecodeComponent
+                            TimecodeComponent
+                              InstanceUID = {29dc1968-3487-4ef2-a156-949afe99fdab}
+                              DataDefinition = SMPTE 12M Timecode Track
+                              Duration = 24
+                              RoundedTimecodeBase = 24
+                              StartTimecode = 86400
+                              DropFrame = 0
+                    EditRate = 24/1
+                    Origin = 0
+                Tracks_Item = {f2f685f0-25f5-4d65-9592-7f511c730706}
+                Tracks_Item -> Strong Reference to Track
+                  Track
+                    InstanceUID = {f2f685f0-25f5-4d65-9592-7f511c730706}
+                    TrackID = 2
+                    TrackNumber = 352389121
+                    TrackName = Picture Track
+                    Sequence = {90bbbbca-9042-4244-9db2-939c83cd1a84}
+                    Sequence -> Strong Reference to Sequence
+                      Sequence
+                        InstanceUID = {90bbbbca-9042-4244-9db2-939c83cd1a84}
+                        DataDefinition = Picture Essence Track
+                        Duration = 24
+                        StructuralComponents
+                          StructuralComponent = {f1f17679-2c07-458c-af0d-cfdadde6a705}
+                          StructuralComponent -> Strong Reference to SourceClip
+                            SourceClip
+                              InstanceUID = {f1f17679-2c07-458c-af0d-cfdadde6a705}
+                              DataDefinition = Picture Essence Track
+                              Duration = 24
+                              StartPosition = 0
+                              SourcePackageID = [00000000.0000.0000.00000000],00,00,00,00,[00000000.0000.0000.00000000.00000000]
+                              SourceTrackID = 0
+                    EditRate = 24/1
+                    Origin = 0
+              Descriptor = {d33fd7d1-a6ce-4f9f-ade5-db60bf89e34b}
+              Descriptor -> Strong Reference to RGBAEssenceDescriptor
+                RGBAEssenceDescriptor
+                  InstanceUID = {d33fd7d1-a6ce-4f9f-ade5-db60bf89e34b}
+                  SubDescriptors
+                    SubDescriptor = {d4700ab9-4c69-44d1-a849-8920b60b017e}
+                    SubDescriptor -> Strong Reference to JPEG2000PictureSubDescriptor
+                      JPEG2000PictureSubDescriptor
+                        InstanceUID = {d4700ab9-4c69-44d1-a849-8920b60b017e}
+                        Rsiz = 3
+                        Xsiz = 32
+                        Ysiz = 32
+                        XOsiz = 0
+                        YOsiz = 0
+                        XTsiz = 32
+                        YTsiz = 32
+                        XTOsiz = 0
+                        YTOsiz = 0
+                        Csiz = 3
+                        PictureComponentSizing
+                          PictureComponentSize = Ssiz="7", XRsiz="1", YRsiz="1"
+                          PictureComponentSize = Ssiz="7", XRsiz="1", YRsiz="1"
+                          PictureComponentSize = Ssiz="7", XRsiz="1", YRsiz="1"
+                        CodingStyleDefault = Scod="1", SGcod="ProgressionOrder="4", NumberOfLayers="1", MultipleComponentTransformation="1"", SPcod="DecompositionLevels="5", CodeblockWidth="3", CodeblockHeight="3", CodeblockStyle="0", Transformation="0"", PrecinctSize="119, 136, 136, 136, 136, 136"
+                        QuantizationDefault = Sqcd="66", SPqcd="119, 32, 118, 240, 118, 240, 118, 192, 111, 0, 111, 0, 110, 224, 103, 80, 103, 80, 103, 104, 80, 5, 80, 5, 80, 71, 87, 211, 87, 211, 87, 98"
+                  LinkedTrackID = 2
+                  SampleRate = 24/1
+                  ContainerDuration = 24
+                  EssenceContainer = MXF-GC JPEG-2000 Picture Mappings
+                  FrameLayout = 0
+                  StoredWidth = 32
+                  StoredHeight = 32
+                  AspectRatio = 32/32
+                  PictureEssenceCoding = [060e2b34.0401.0109.04010202.03010103]
+                  ComponentMaxRef = 4095
+                  ComponentMinRef = 0
+        EssenceContainerData
+          EssenceContainer = {7d384edf-2ff0-4b50-ab06-9165947b289b}
+          EssenceContainer -> Strong Reference to EssenceContainerData
+            EssenceContainerData
+              InstanceUID = {7d384edf-2ff0-4b50-ab06-9165947b289b}
+              LinkedPackageUID = [060a2b34.0101.0105.01010f20],13,00,00,00,{0a2335fe-09a3-4a19-b5ea-2e0308e727b3}
+              IndexSID = 129
+              BodySID = 1
+    OperationalPattern = MXF Specialized OP Atom
+    EssenceContainers
+      EssenceContainer = MXF-GC Generic Essence Multiple Mappings
+      EssenceContainer = MXF-GC JPEG-2000 Picture Mappings
+    DMSchemes
+
+No index table in this partition
+
+Partition at 0x00004000 is for BodySID 0x0001
+
+Partition at 0x00006384 is for BodySID 0x0000
+CompleteFooter
+  MajorVersion = 1
+  MinorVersion = 2
+  KAGSize = 1
+  ThisPartition = 25476
+  PreviousPartition = 16384
+  FooterPartition = 25476
+  HeaderByteCount = 0
+  IndexByteCount = 404
+  IndexSID = 129
+  BodyOffset = 0
+  BodySID = 0
+  OperationalPattern = MXF Specialized OP Atom
+  EssenceContainers
+    EssenceContainer = MXF-GC Generic Essence Multiple Mappings
+    EssenceContainer = MXF-GC JPEG-2000 Picture Mappings
+No header metadata in this partition
+
+Index Table Segment (first edit unit = 0, duration = 24) :
+  Indexing BodySID 0x0001 from IndexSID 0x0081
+
+ Bytestream Order:
+  EditUnit   0 for stream 0 is at 0x00000000, Flags=00  *Exact*
+  EditUnit   1 for stream 0 is at 0x00000175, Flags=00  *Exact*
+  EditUnit   2 for stream 0 is at 0x000002ea, Flags=00  *Exact*
+  EditUnit   3 for stream 0 is at 0x0000045f, Flags=00  *Exact*
+  EditUnit   4 for stream 0 is at 0x000005d4, Flags=00  *Exact*
+  EditUnit   5 for stream 0 is at 0x00000749, Flags=00  *Exact*
+  EditUnit   6 for stream 0 is at 0x000008be, Flags=00  *Exact*
+  EditUnit   7 for stream 0 is at 0x00000a33, Flags=00  *Exact*
+  EditUnit   8 for stream 0 is at 0x00000ba8, Flags=00  *Exact*
+  EditUnit   9 for stream 0 is at 0x00000d1d, Flags=00  *Exact*
+  EditUnit  10 for stream 0 is at 0x00000e92, Flags=00  *Exact*
+  EditUnit  11 for stream 0 is at 0x00001007, Flags=00  *Exact*
+  EditUnit  12 for stream 0 is at 0x0000117c, Flags=00  *Exact*
+  EditUnit  13 for stream 0 is at 0x000012f1, Flags=00  *Exact*
+  EditUnit  14 for stream 0 is at 0x00001466, Flags=00  *Exact*
+  EditUnit  15 for stream 0 is at 0x000015db, Flags=00  *Exact*
+  EditUnit  16 for stream 0 is at 0x00001750, Flags=00  *Exact*
+  EditUnit  17 for stream 0 is at 0x000018c5, Flags=00  *Exact*
+  EditUnit  18 for stream 0 is at 0x00001a3a, Flags=00  *Exact*
+  EditUnit  19 for stream 0 is at 0x00001baf, Flags=00  *Exact*
+  EditUnit  20 for stream 0 is at 0x00001d24, Flags=00  *Exact*
+  EditUnit  21 for stream 0 is at 0x00001e99, Flags=00  *Exact*
+  EditUnit  22 for stream 0 is at 0x0000200e, Flags=00  *Exact*
+  EditUnit  23 for stream 0 is at 0x00002183, Flags=00  *Exact*
+
+ Presentation Order:
+  EditUnit   0 for stream 0 is at 0x00000000, Flags=00  *Exact*
+  EditUnit   1 for stream 0 is at 0x00000175, Flags=00  *Exact*
+  EditUnit   2 for stream 0 is at 0x000002ea, Flags=00  *Exact*
+  EditUnit   3 for stream 0 is at 0x0000045f, Flags=00  *Exact*
+  EditUnit   4 for stream 0 is at 0x000005d4, Flags=00  *Exact*
+  EditUnit   5 for stream 0 is at 0x00000749, Flags=00  *Exact*
+  EditUnit   6 for stream 0 is at 0x000008be, Flags=00  *Exact*
+  EditUnit   7 for stream 0 is at 0x00000a33, Flags=00  *Exact*
+  EditUnit   8 for stream 0 is at 0x00000ba8, Flags=00  *Exact*
+  EditUnit   9 for stream 0 is at 0x00000d1d, Flags=00  *Exact*
+  EditUnit  10 for stream 0 is at 0x00000e92, Flags=00  *Exact*
+  EditUnit  11 for stream 0 is at 0x00001007, Flags=00  *Exact*
+  EditUnit  12 for stream 0 is at 0x0000117c, Flags=00  *Exact*
+  EditUnit  13 for stream 0 is at 0x000012f1, Flags=00  *Exact*
+  EditUnit  14 for stream 0 is at 0x00001466, Flags=00  *Exact*
+  EditUnit  15 for stream 0 is at 0x000015db, Flags=00  *Exact*
+  EditUnit  16 for stream 0 is at 0x00001750, Flags=00  *Exact*
+  EditUnit  17 for stream 0 is at 0x000018c5, Flags=00  *Exact*
+  EditUnit  18 for stream 0 is at 0x00001a3a, Flags=00  *Exact*
+  EditUnit  19 for stream 0 is at 0x00001baf, Flags=00  *Exact*
+  EditUnit  20 for stream 0 is at 0x00001d24, Flags=00  *Exact*
+  EditUnit  21 for stream 0 is at 0x00001e99, Flags=00  *Exact*
+  EditUnit  22 for stream 0 is at 0x0000200e, Flags=00  *Exact*
+  EditUnit  23 for stream 0 is at 0x00002183, Flags=00  *Exact*
+
+Read RIP
+  BodySID 0x0000 is at 0x00000000 and is not loaded
+  BodySID 0x0001 is at 0x00004000 and is not loaded
+  BodySID 0x0000 is at 0x00006384 and is not loaded
+
+Scanned RIP
+  BodySID 0x0000 is at 0x00000000 type ClosedCompleteHeader
+  BodySID 0x0001 is at 0x00004000 type ClosedCompleteBodyPartition
+  BodySID 0x0000 is at 0x00006384 type CompleteFooter
diff --git a/test/ref/DCP/video.mxf b/test/ref/DCP/video.mxf
new file mode 100644 (file)
index 0000000..9b11f99
Binary files /dev/null and b/test/ref/DCP/video.mxf differ
diff --git a/test/ref/j2c/1.j2c b/test/ref/j2c/1.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/10.j2c b/test/ref/j2c/10.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/11.j2c b/test/ref/j2c/11.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/12.j2c b/test/ref/j2c/12.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/13.j2c b/test/ref/j2c/13.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/14.j2c b/test/ref/j2c/14.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/15.j2c b/test/ref/j2c/15.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/16.j2c b/test/ref/j2c/16.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/17.j2c b/test/ref/j2c/17.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/18.j2c b/test/ref/j2c/18.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/19.j2c b/test/ref/j2c/19.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/2.j2c b/test/ref/j2c/2.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/20.j2c b/test/ref/j2c/20.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/21.j2c b/test/ref/j2c/21.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/22.j2c b/test/ref/j2c/22.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/23.j2c b/test/ref/j2c/23.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/24.j2c b/test/ref/j2c/24.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/3.j2c b/test/ref/j2c/3.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/4.j2c b/test/ref/j2c/4.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/5.j2c b/test/ref/j2c/5.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/6.j2c b/test/ref/j2c/6.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/7.j2c b/test/ref/j2c/7.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/8.j2c b/test/ref/j2c/8.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/j2c/9.j2c b/test/ref/j2c/9.j2c
new file mode 120000 (symlink)
index 0000000..7e4f07e
--- /dev/null
@@ -0,0 +1 @@
+../../data/32x32_red_square.j2c
\ No newline at end of file
diff --git a/test/ref/make.sh b/test/ref/make.sh
new file mode 100644 (file)
index 0000000..1d04e24
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+rm -rf DCP
+mkdir DCP
+opendcp_mxf -i j2c -o DCP/video.mxf -r 24
+opendcp_mxf -i wav -o DCP/audio.mxf -r 24
+opendcp_xml --reel DCP/video.mxf DCP/audio.mxf -k feature -t "A Test DCP" -a "A Test DCP"
+mv *.xml DCP
+mv DCP/*_pkl.xml DCP/04040404-0404-0404-0404-040404040404_pkl.xml
+mv DCP/*_cpl.xml DCP/02020202-0202-0202-0202-020202020202_cpl.xml
diff --git a/test/ref/wav/1.wav b/test/ref/wav/1.wav
new file mode 120000 (symlink)
index 0000000..6163f16
--- /dev/null
@@ -0,0 +1 @@
+../../data/1s_24-bit_48k_silence.wav
\ No newline at end of file
diff --git a/test/ref/wav/2.wav b/test/ref/wav/2.wav
new file mode 120000 (symlink)
index 0000000..6163f16
--- /dev/null
@@ -0,0 +1 @@
+../../data/1s_24-bit_48k_silence.wav
\ No newline at end of file
diff --git a/test/tests.cc b/test/tests.cc
new file mode 100644 (file)
index 0000000..dd9ed07
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+    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 <boost/filesystem.hpp>
+#include "dcp.h"
+#include "util.h"
+#include "tags.h"
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE libdcp_test
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_CASE (dcp_test)
+{
+       libdcp::libdcp_test = true;
+
+       libdcp::Tags* t = libdcp::Tags::instance ();
+       t->issuer = "OpenDCP 0.0.25";
+       t->creator = "OpenDCP 0.0.25";
+       t->company_name = "OpenDCP";
+       t->product_name = "OpenDCP";
+       t->product_version = "0.0.25";
+       
+       filesystem::remove_all ("build/test/foo");
+       filesystem::create_directories ("build/test/foo");
+       libdcp::DCP d ("build/test/foo", "A Test DCP", libdcp::DCP::FEATURE, 24, 24);
+
+       list<string> j2cs;
+       for (int i = 0; i < 24; ++i) {
+               j2cs.push_back ("test/data/32x32_red_square.j2c");
+       }
+       d.add_picture_asset (j2cs, 32, 32);
+       
+       list<string> wavs;
+       for (int i = 0; i < 2; ++i) {
+               wavs.push_back ("test/data/1s_24-bit_48k_silence.wav");
+       }
+       d.add_sound_asset (wavs);
+
+       d.write_xml ();
+}
diff --git a/test/wscript b/test/wscript
new file mode 100644 (file)
index 0000000..cd10983
--- /dev/null
@@ -0,0 +1,15 @@
+def configure(conf):
+    conf.check_cxx(fragment = """
+                              #define BOOST_TEST_MODULE Config test\n
+                             #include <boost/test/unit_test.hpp>\n
+                              int main() {}
+                              """, msg = 'Checking for boost unit testing library', lib = 'boost_unit_test_framework', uselib_store = 'BOOST_TEST')
+
+def build(bld):
+    obj = bld(features = 'cxx cxxprogram')
+    obj.name   = 'tests'
+    obj.uselib = 'BOOST_TEST'
+    obj.use    = 'libdcp'
+    obj.source = 'tests.cc'
+    obj.target = 'tests'
+    obj.install_path = ''
diff --git a/waf b/waf
new file mode 100755 (executable)
index 0000000..178461f
Binary files /dev/null and b/waf differ
diff --git a/wscript b/wscript
new file mode 100644 (file)
index 0000000..b28c366
--- /dev/null
+++ b/wscript
@@ -0,0 +1,43 @@
+APPNAME = 'libdcp'
+VERSION = '0.01pre'
+
+def options(opt):
+    opt.load('compiler_cxx')
+
+def configure(conf):
+    conf.load('compiler_cxx')
+    conf.env.append_value('CXXFLAGS', ['-Wall', '-Werror', '-Wextra', '-O2', '-D_FILE_OFFSET_BITS=64'])
+    conf.env.append_value('CXXFLAGS', ['-DLIBDCP_VERSION="%s"' % VERSION])
+
+    conf.check_cc(msg = 'Checking for libkumu',
+                  function_name = 'Kumu::Version',
+                  header_name = 'KM_util.h',
+                  lib = 'kumu',
+                  uselib_store = 'KUMU',
+                  mandatory = True)
+
+    conf.check_cc(msg = 'Checking for asdcplib',
+                  function_name = 'ASDCP::Version',
+                  header_name = 'AS_DCP.h',
+                  lib = 'asdcp',
+                  uselib_store = 'ASDCP',
+                  mandatory = True)
+
+    conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True)
+    conf.check_cfg(package = 'sigc++-2.0', args = '--cflags --libs', uselib_store = 'SIGC++', mandatory = True)
+    
+    conf.check_cxx(fragment = """
+                             #include <boost/filesystem.hpp>\n
+                             int main() { boost::filesystem::copy_file ("a", "b"); }\n
+                             """,
+                   msg = 'Checking for boost filesystem library',
+                   libpath = '/usr/local/lib',
+                   lib = ['boost_filesystem', 'boost_system'],
+                   uselib_store = 'BOOST_FILESYSTEM')
+
+    conf.recurse('test')
+
+def build(bld):
+    bld.recurse('src')
+    bld.recurse('test')
+