Add Atmos read/write and untested MXF decryption tool. 1.0-templates
authorCarl Hetherington <cth@carlh.net>
Tue, 27 Sep 2016 11:30:04 +0000 (12:30 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 27 Sep 2016 11:30:04 +0000 (12:30 +0100)
15 files changed:
run/tools/dcpdecryptmxf [new file with mode: 0755]
src/atmos_asset.cc
src/atmos_asset.h
src/atmos_asset_reader.h [new file with mode: 0644]
src/atmos_asset_writer.cc [new file with mode: 0644]
src/atmos_asset_writer.h [new file with mode: 0644]
src/atmos_frame.h [new file with mode: 0644]
src/decryption_context.h
src/frame.h
src/mono_picture_asset.cc
src/sound_asset.cc
src/stereo_picture_asset.cc
src/wscript
tools/dcpdecryptmxf.cc [new file with mode: 0644]
tools/wscript

diff --git a/run/tools/dcpdecryptmxf b/run/tools/dcpdecryptmxf
new file mode 100755 (executable)
index 0000000..9caf546
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src:build/asdcplib/src:$LD_LIBRARY_PATH
+if [ "$1" == "--debug" ]; then
+    shift
+    gdb --args build/tools/dcpdecryptmxf "$@"
+elif [ "$1" == "--valgrind" ]; then
+    shift
+    valgrind --tool="memcheck" --leak-check=full --show-reachable=yes build/tools/dcpdecryptmxf "$@"
+else
+    build/tools/dcpdecryptmxf "$@"
+fi
index a8a595c3465c228cc2ea125a0a72e454aea994d0..eac01dcf3525378a35b1b6dd824bad28486674f1 100644 (file)
 */
 
 #include "atmos_asset.h"
+#include "atmos_asset_reader.h"
+#include "atmos_asset_writer.h"
 #include "exceptions.h"
 #include <asdcp/AS_DCP.h>
 
 using std::string;
+using boost::shared_ptr;
 using namespace dcp;
 
+AtmosAsset::AtmosAsset (Fraction edit_rate, int first_frame, int max_channel_count, int max_object_count, string atmos_id, int atmos_version)
+       : _edit_rate (edit_rate)
+       , _intrinsic_duration (0)
+       , _first_frame (first_frame)
+       , _max_channel_count (max_channel_count)
+       , _max_object_count (max_object_count)
+       , _atmos_id (atmos_id)
+       , _atmos_version (atmos_version)
+{
+
+}
+
 AtmosAsset::AtmosAsset (boost::filesystem::path file)
        : Asset (file)
 {
@@ -57,6 +72,12 @@ AtmosAsset::AtmosAsset (boost::filesystem::path file)
        _first_frame = desc.FirstFrame;
        _max_channel_count = desc.MaxChannelCount;
        _max_object_count = desc.MaxObjectCount;
+
+       char id[64];
+       Kumu::bin2UUIDhex (desc.AtmosID, ASDCP::UUIDlen, id, sizeof (id));
+       _atmos_id = id;
+
+       _atmos_version = desc.AtmosVersion;
 }
 
 string
@@ -64,3 +85,15 @@ AtmosAsset::pkl_type (Standard) const
 {
        return "application/mxf";
 }
+
+shared_ptr<AtmosAssetReader>
+AtmosAsset::start_read () const
+{
+       return shared_ptr<AtmosAssetReader> (new AtmosAssetReader (this, key ()));
+}
+
+shared_ptr<AtmosAssetWriter>
+AtmosAsset::start_write (boost::filesystem::path file)
+{
+       return shared_ptr<AtmosAssetWriter> (new AtmosAssetWriter (this, file));
+}
index 2e99e18b3f8ec33eefc79248938096ec6d957794..8e9190c88cef37572c21c659de9d286b74faa043 100644 (file)
 
 #include "asset.h"
 #include "mxf.h"
+#include "atmos_asset_reader.h"
 
 namespace dcp {
 
+class AtmosAssetWriter;
+
 class AtmosAsset : public Asset, public MXF
 {
 public:
+       AtmosAsset (Fraction edit_rate, int first_frame, int max_channel_count, int max_object_count, std::string atmos_id, int atmos_version);
        explicit AtmosAsset (boost::filesystem::path file);
 
+       boost::shared_ptr<AtmosAssetWriter> start_write (boost::filesystem::path file);
+       boost::shared_ptr<AtmosAssetReader> start_read () const;
+
        std::string pkl_type (Standard) const;
 
        Fraction edit_rate () const {
@@ -69,12 +76,24 @@ public:
                return _max_object_count;
        }
 
+       std::string atmos_id () const {
+               return _atmos_id;
+       }
+
+       int atmos_version () const {
+               return _atmos_version;
+       }
+
 private:
+       friend class AtmosAssetWriter;
+
        Fraction _edit_rate;
        int64_t _intrinsic_duration;
        int _first_frame;
        int _max_channel_count;
        int _max_object_count;
+       std::string _atmos_id;
+       int _atmos_version;
 };
 
 }
diff --git a/src/atmos_asset_reader.h b/src/atmos_asset_reader.h
new file mode 100644 (file)
index 0000000..1480626
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp 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.
+
+    libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+#include "asset_reader.h"
+#include "atmos_frame.h"
+
+namespace dcp {
+
+typedef AssetReader<ASDCP::ATMOS::MXFReader, AtmosFrame> AtmosAssetReader;
+
+}
diff --git a/src/atmos_asset_writer.cc b/src/atmos_asset_writer.cc
new file mode 100644 (file)
index 0000000..eb0d608
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp 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.
+
+    libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+#include "atmos_asset_writer.h"
+#include "atmos_asset.h"
+#include "exceptions.h"
+#include "dcp_assert.h"
+#include "compose.hpp"
+#include "encryption_context.h"
+#include <asdcp/AS_DCP.h>
+
+using std::min;
+using std::max;
+using namespace dcp;
+
+struct AtmosAssetWriter::ASDCPState
+{
+       ASDCP::ATMOS::MXFWriter mxf_writer;
+       ASDCP::DCData::FrameBuffer frame_buffer;
+       ASDCP::WriterInfo writer_info;
+       ASDCP::ATMOS::AtmosDescriptor desc;
+};
+
+AtmosAssetWriter::AtmosAssetWriter (AtmosAsset* asset, boost::filesystem::path file)
+       : AssetWriter (asset, file, SMPTE)
+       , _state (new AtmosAssetWriter::ASDCPState)
+       , _asset (asset)
+{
+       _state->desc.EditRate = ASDCP::Rational (_asset->edit_rate().numerator, _asset->edit_rate().denominator);
+       _state->desc.FirstFrame = _asset->first_frame ();
+       _state->desc.MaxChannelCount = _asset->max_channel_count ();
+       _state->desc.MaxObjectCount = _asset->max_object_count ();
+
+       unsigned int c;
+       Kumu::hex2bin (_asset->atmos_id().c_str(), _state->desc.AtmosID, ASDCP::UUIDlen, &c);
+       DCP_ASSERT (c == ASDCP::UUIDlen);
+
+       _state->desc.AtmosVersion = 0;
+
+       _asset->fill_writer_info (&_state->writer_info, _asset->id(), SMPTE);
+}
+
+void
+AtmosAssetWriter::write (uint8_t const * data, int size)
+{
+       DCP_ASSERT (!_finalized);
+
+       if (!_started) {
+               Kumu::Result_t r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc);
+               if (ASDCP_FAILURE (r)) {
+                       boost::throw_exception (FileError ("could not open atmos MXF for writing", _file.string(), r));
+               }
+
+               _asset->set_file (_file);
+               _started = true;
+       }
+
+       _state->frame_buffer.Capacity (size);
+       _state->frame_buffer.Size (size);
+       memcpy (_state->frame_buffer.Data(), data, size);
+
+       ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _encryption_context->encryption(), _encryption_context->hmac());
+       if (ASDCP_FAILURE (r)) {
+               boost::throw_exception (MiscError (String::compose ("could not write atmos MXF frame (%1)", int (r))));
+       }
+
+       ++_frames_written;
+}
+
+bool
+AtmosAssetWriter::finalize ()
+{
+       if (_started && ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
+               boost::throw_exception (MiscError ("could not finalise atmos MXF"));
+       }
+
+       _asset->_intrinsic_duration = _frames_written;
+       return AssetWriter::finalize ();
+}
diff --git a/src/atmos_asset_writer.h b/src/atmos_asset_writer.h
new file mode 100644 (file)
index 0000000..e494b77
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp 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.
+
+    libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+/** @file  src/atmos_asset_writer.h
+ *  @brief AtmosAssetWriter class.
+ */
+
+#include "asset_writer.h"
+#include "types.h"
+#include "atmos_frame.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class AtmosAsset;
+
+/** @class AtmosAssetWriter
+ *  @brief A helper class for writing to AtmosAssets.
+ *
+ *  Objects of this class can only be created with AtmosAsset::start_write().
+ */
+class AtmosAssetWriter : public AssetWriter
+{
+public:
+       void write (uint8_t const * data, int size);
+       bool finalize ();
+
+private:
+       friend class AtmosAsset;
+
+       AtmosAssetWriter (AtmosAsset *, boost::filesystem::path);
+
+       /* do this with an opaque pointer so we don't have to include
+          ASDCP headers
+       */
+       struct ASDCPState;
+       boost::shared_ptr<ASDCPState> _state;
+
+       AtmosAsset* _asset;
+};
+
+}
diff --git a/src/atmos_frame.h b/src/atmos_frame.h
new file mode 100644 (file)
index 0000000..763875b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp 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.
+
+    libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+/** @file  src/atmos_frame.h
+ *  @brief AtmosFrame class.
+ */
+
+#ifndef LIBDCP_ATMOS_FRAME_H
+#define LIBDCP_ATMOS_FRAME_H
+
+#include "frame.h"
+
+namespace dcp {
+
+typedef Frame<ASDCP::ATMOS::MXFReader, ASDCP::DCData::FrameBuffer> AtmosFrame;
+
+}
+
+#endif
index e3d3ce1e4cbe8199187930be2459b9985dacda3a..fb8342cf4e968b9f1388887b4cae6835f484504d 100644 (file)
@@ -31,6 +31,9 @@
     files in the program, then also delete it here.
 */
 
+#ifndef LIBDCP_DECRYPTION_CONTEXT_H
+#define LIBDCP_DECRYPTION_CONTEXT_H
+
 #include "key.h"
 #include <boost/optional.hpp>
 
@@ -55,3 +58,5 @@ private:
 };
 
 }
+
+#endif
index 54b74e552ee4ea8f2693558715908403c9d4b412..f20a1bb36f8d662aac41058d81a54bc8a781afb0 100644 (file)
@@ -31,6 +31,9 @@
     files in the program, then also delete it here.
 */
 
+#ifndef LIBDCP_FRAME_H
+#define LIBDCP_FRAME_H
+
 #include "decryption_context.h"
 #include "exceptions.h"
 #include <asdcp/KM_fileio.h>
@@ -73,3 +76,5 @@ private:
 };
 
 }
+
+#endif
index a6643bc053a1095e3158cf3b9f3fbf8b0912e584..407a3614de88231a2df313bb59296422e4c6648c 100644 (file)
@@ -176,7 +176,7 @@ MonoPictureAsset::start_write (boost::filesystem::path file, Standard standard,
 shared_ptr<MonoPictureAssetReader>
 MonoPictureAsset::start_read () const
 {
-       return shared_ptr<MonoPictureAssetReader> (new MonoPictureAssetReader (this));
+       return shared_ptr<MonoPictureAssetReader> (new MonoPictureAssetReader (this, key ()));
 }
 
 string
index 11fd4b2fae685ec081f0221fe6ea35c98abcd134..74d412123803435de48e19d364ef5570f684cdb0 100644 (file)
@@ -201,7 +201,7 @@ SoundAsset::start_write (boost::filesystem::path file, Standard standard)
 shared_ptr<SoundAssetReader>
 SoundAsset::start_read () const
 {
-       return shared_ptr<SoundAssetReader> (new SoundAssetReader (this));
+       return shared_ptr<SoundAssetReader> (new SoundAssetReader (this, key ()));
 }
 
 string
index 9a21b72b152c947a6a767763dc375d9f09083a8c..4bbf7268568d0c7366fc5fecc0f6427b4703743a 100644 (file)
@@ -86,7 +86,7 @@ StereoPictureAsset::start_write (boost::filesystem::path file, Standard standard
 shared_ptr<StereoPictureAssetReader>
 StereoPictureAsset::start_read () const
 {
-       return shared_ptr<StereoPictureAssetReader> (new StereoPictureAssetReader (this));
+       return shared_ptr<StereoPictureAssetReader> (new StereoPictureAssetReader (this, key ()));
 }
 
 bool
index 63c65905cb5ce4f57bc04320b6e539f537f34959..f24064be21215638eac91bd5666724bb68f61b01 100644 (file)
@@ -37,6 +37,7 @@ def build(bld):
              asset.cc
              asset_writer.cc
              atmos_asset.cc
+             atmos_asset_writer.cc
              certificate_chain.cc
              certificate.cc
              colour_conversion.cc
@@ -103,6 +104,8 @@ def build(bld):
               asset_reader.h
               asset_writer.h
               atmos_asset.h
+              atmos_asset_reader.h
+              atmos_asset_writer.h
               certificate_chain.h
               certificate.h
               chromaticity.h
diff --git a/tools/dcpdecryptmxf.cc b/tools/dcpdecryptmxf.cc
new file mode 100644 (file)
index 0000000..e640620
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp 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.
+
+    libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+#include "encrypted_kdm.h"
+#include "decrypted_kdm.h"
+#include "decryption_context.h"
+#include "key.h"
+#include "util.h"
+#include "atmos_asset.h"
+#include "atmos_frame.h"
+#include "atmos_asset_reader.h"
+#include "atmos_asset_writer.h"
+#include "exceptions.h"
+#include <asdcp/AS_DCP.h>
+#include <boost/foreach.hpp>
+#include <getopt.h>
+#include <string>
+
+using std::string;
+using std::cerr;
+using std::cout;
+using boost::optional;
+using boost::shared_ptr;
+
+static void
+help (string n)
+{
+       cerr << "Syntax: " << n << " [OPTION] <MXF>]\n"
+            << "  -v, --version      show DCP-o-matic version\n"
+            << "  -h, --help         show this help\n"
+            << "  -o, --output       output filename\n"
+            << "  -k, --kdm          KDM file\n"
+            << "  -p, --private-key  private key file\n";
+}
+
+int
+atmos (
+       ASDCP::ATMOS::MXFReader& reader,
+       boost::filesystem::path output_file,
+       dcp::DecryptedKDM kdm
+       )
+{
+       ASDCP::WriterInfo info;
+       if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+               cerr << "Could not read ATMOS MXF information\n";
+               exit (EXIT_FAILURE);
+       }
+
+       if (!info.EncryptedEssence) {
+               cerr << "MXF is not encrypted!\n";
+               exit (EXIT_FAILURE);
+       }
+
+       char key_buffer[64];
+       Kumu::bin2UUIDhex (info.CryptographicKeyID, ASDCP::UUIDlen, key_buffer, sizeof (key_buffer));
+       string const key_id = key_buffer;
+
+       optional<dcp::Key> key;
+       BOOST_FOREACH (dcp::DecryptedKDMKey const & i, kdm.keys()) {
+               if (i.id() == key_id) {
+                       key = i.key();
+               }
+       }
+
+       if (!key) {
+               cerr << "Could not find key in KDM.\n";
+               exit (EXIT_FAILURE);
+       }
+
+       dcp::DecryptionContext dc (key.get());
+
+       ASDCP::ATMOS::AtmosDescriptor desc;
+       if (ASDCP_FAILURE (reader.FillAtmosDescriptor (desc))) {
+               cerr << "could not read ATMOS descriptor.\n";
+               exit (EXIT_FAILURE);
+       }
+
+       ASDCP::DCData::FrameBuffer buffer (Kumu::Megabyte);
+
+       for (size_t i = 0; i < desc.ContainerDuration; ++i) {
+               reader.ReadFrame (i, buffer, dc.decryption(), 0);
+       }
+
+       return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+       optional<boost::filesystem::path> output_file;
+       optional<boost::filesystem::path> kdm_file;
+       optional<boost::filesystem::path> private_key_file;
+
+       int option_index = 0;
+       while (true) {
+               struct option long_options[] = {
+                       { "version", no_argument, 0, 'v' },
+                       { "help", no_argument, 0, 'h' },
+                       { "output", required_argument, 0, 'o'},
+                       { "kdm", required_argument, 0, 'k'},
+                       { "private-key", required_argument, 0, 'p'},
+                       { 0, 0, 0, 0 }
+               };
+
+               int c = getopt_long (argc, argv, "vho:k:p:", long_options, &option_index);
+
+               if (c == -1) {
+                       break;
+               }
+
+               switch (c) {
+               case 'v':
+                       cout << "libdcp version " << LIBDCP_VERSION << "\n";
+                       exit (EXIT_SUCCESS);
+               case 'h':
+                       help (argv[0]);
+                       exit (EXIT_SUCCESS);
+               case 'o':
+                       output_file = optarg;
+                       break;
+               case 'k':
+                       kdm_file = optarg;
+                       break;
+               case 'p':
+                       private_key_file = optarg;
+                       break;
+               }
+       }
+
+       if (optind >= argc) {
+               help (argv[0]);
+               exit (EXIT_FAILURE);
+       }
+
+       boost::filesystem::path input_file = argv[optind];
+
+       if (!output_file) {
+               cerr << "You must specify -o or --output\n";
+               exit (EXIT_FAILURE);
+       }
+
+       if (!kdm_file) {
+               cerr << "You must specify -k or --kdm\n";
+               exit (EXIT_FAILURE);
+       }
+
+       if (!private_key_file) {
+               cerr << "You must specify -p or --private-key\n";
+               exit (EXIT_FAILURE);
+       }
+
+       dcp::EncryptedKDM encrypted_kdm (dcp::file_to_string (kdm_file.get ()));
+       dcp::DecryptedKDM decrypted_kdm (encrypted_kdm, dcp::file_to_string (private_key_file.get()));
+
+       try {
+               dcp::AtmosAsset in (input_file);
+               shared_ptr<dcp::AtmosAssetReader> reader = in.start_read ();
+               dcp::AtmosAsset out (
+                       in.edit_rate(),
+                       in.first_frame(),
+                       in.max_channel_count(),
+                       in.max_object_count(),
+                       in.atmos_id(),
+                       in.atmos_version()
+                       );
+               shared_ptr<dcp::AtmosAssetWriter> writer = out.start_write (output_file.get());
+               for (int64_t i = 0; i < in.intrinsic_duration(); ++i) {
+                       shared_ptr<const dcp::AtmosFrame> f = reader->get_frame (i);
+                       writer->write (f->data(), f->size());
+               }
+       } catch (dcp::DCPReadError& e) {
+               cerr << "Unknown MXF format.\n";
+               return EXIT_FAILURE;
+       }
+
+       return 0;
+}
index 1f04cd184a5e82c4cf642848cd2a80e746d1dc34..b3bb3a1fdf4b4ad01e365a92123c54ee1751b899 100644 (file)
@@ -49,3 +49,9 @@ def build(bld):
     obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM LIBXML++ XMLSEC1 OPENSSL'
     obj.source = 'dcpdumpsub.cc'
     obj.target = 'dcpdumpsub'
+
+    obj = bld(features='cxx cxxprogram')
+    obj.use = ['libdcp%s' % bld.env.API_VERSION]
+    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM LIBXML++ XMLSEC1 OPENSSL'
+    obj.source = 'dcpdecryptmxf.cc'
+    obj.target = 'dcpdecryptmxf'