Add Reader classes to permit much more efficient DCP reading.
authorCarl Hetherington <cth@carlh.net>
Wed, 1 Jun 2016 22:53:06 +0000 (23:53 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 1 Jun 2016 22:53:06 +0000 (23:53 +0100)
29 files changed:
examples/read_dcp.cc
src/asset_reader.cc [new file with mode: 0644]
src/asset_reader.h [new file with mode: 0644]
src/mono_picture_asset.cc
src/mono_picture_asset.h
src/mono_picture_asset_reader.cc [new file with mode: 0644]
src/mono_picture_asset_reader.h [new file with mode: 0644]
src/mono_picture_frame.cc
src/mono_picture_frame.h
src/mxf.cc
src/mxf.h
src/sound_asset.cc
src/sound_asset.h
src/sound_asset_reader.cc [new file with mode: 0644]
src/sound_asset_reader.h [new file with mode: 0644]
src/sound_frame.cc
src/sound_frame.h
src/stereo_picture_asset.cc
src/stereo_picture_asset.h
src/stereo_picture_asset_reader.cc [new file with mode: 0644]
src/stereo_picture_asset_reader.h [new file with mode: 0644]
src/stereo_picture_asset_writer.cc
src/stereo_picture_asset_writer.h
src/stereo_picture_frame.cc
src/stereo_picture_frame.h
src/wscript
test/decryption_test.cc
test/round_trip_test.cc
test/sound_frame_test.cc

index 4e3f48365f2fb73d405347b58c9d2b8dd7f6111b..6cc9b67673718af73bba9c6f8bc16eab0ca7efd0 100644 (file)
@@ -29,6 +29,7 @@
 #include "reel_picture_asset.h"
 #include "mono_picture_frame.h"
 #include "mono_picture_asset.h"
+#include "mono_picture_asset_reader.h"
 #include "stereo_picture_asset.h"
 #include "sound_asset.h"
 #include "subtitle_asset.h"
@@ -82,8 +83,11 @@ main ()
                cpl->reels().front()->main_picture()->asset()
                );
 
+       /* Get a reader for it */
+       boost::shared_ptr<dcp::MonoPictureAssetReader> picture_asset_reader = picture_asset->start_read();
+
        /* Get the 1000th frame of it */
-       boost::shared_ptr<const dcp::MonoPictureFrame> picture_frame_j2k = picture_asset->get_frame(999);
+       boost::shared_ptr<const dcp::MonoPictureFrame> picture_frame_j2k = picture_asset_reader->get_frame(999);
 
        /* Get the frame as an XYZ image */
        boost::shared_ptr<const dcp::OpenJPEGImage> picture_image_xyz = picture_frame_j2k->xyz_image ();
diff --git a/src/asset_reader.cc b/src/asset_reader.cc
new file mode 100644 (file)
index 0000000..a78af4d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+    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/>.
+
+*/
+
+#include "asset_reader.h"
+#include "mxf.h"
+#include "exceptions.h"
+#include "AS_DCP.h"
+
+using namespace dcp;
+
+AssetReader::AssetReader (MXF const * mxf)
+       : _decryption_context (0)
+{
+       if (mxf->key()) {
+               _decryption_context = new ASDCP::AESDecContext;
+               if (ASDCP_FAILURE (_decryption_context->InitKey (mxf->key()->value ()))) {
+                       throw MiscError ("could not set up decryption context");
+               }
+       }
+}
+
+AssetReader::~AssetReader ()
+{
+       delete _decryption_context;
+}
diff --git a/src/asset_reader.h b/src/asset_reader.h
new file mode 100644 (file)
index 0000000..688b1a3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    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/>.
+
+*/
+
+#ifndef LIBDCP_ASSET_READER_H
+#define LIBDCP_ASSET_READER_H
+
+namespace ASDCP {
+       class AESDecContext;
+}
+
+namespace dcp {
+
+class MXF;
+
+class AssetReader
+{
+public:
+       AssetReader (MXF const * mxf);
+       virtual ~AssetReader ();
+
+protected:
+       ASDCP::AESDecContext* _decryption_context;
+};
+
+}
+
+#endif
index 9d0d14975d3176cc9612d754b8c85961e5c97156..1a3656cc18d45d0fe32c797241c69316b5808f2f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -20,6 +20,7 @@
 
 #include "mono_picture_asset.h"
 #include "mono_picture_asset_writer.h"
+#include "mono_picture_asset_reader.h"
 #include "AS_DCP.h"
 #include "KM_fileio.h"
 #include "exceptions.h"
@@ -65,12 +66,6 @@ MonoPictureAsset::MonoPictureAsset (Fraction edit_rate)
 
 }
 
-shared_ptr<const MonoPictureFrame>
-MonoPictureAsset::get_frame (int n) const
-{
-       return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (_file, n, _decryption_context));
-}
-
 static void
 storing_note_handler (list<pair<NoteType, string> >& notes, NoteType t, string s)
 {
@@ -118,6 +113,9 @@ MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, No
 #pragma omp parallel for
 #endif
 
+       shared_ptr<MonoPictureAssetReader> reader = start_read ();
+       shared_ptr<MonoPictureAssetReader> other_reader = other_picture->start_read ();
+
        for (int i = 0; i < _intrinsic_duration; ++i) {
                if (i >= other_picture->intrinsic_duration()) {
                        result = false;
@@ -125,8 +123,8 @@ MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, No
 
                if (result || opt.keep_going) {
 
-                       shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
-                       shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
+                       shared_ptr<const MonoPictureFrame> frame_A = reader->get_frame (i);
+                       shared_ptr<const MonoPictureFrame> frame_B = other_reader->get_frame (i);
 
                        list<pair<NoteType, string> > notes;
 
@@ -160,6 +158,12 @@ MonoPictureAsset::start_write (boost::filesystem::path file, Standard standard,
        return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, file, standard, overwrite));
 }
 
+shared_ptr<MonoPictureAssetReader>
+MonoPictureAsset::start_read () const
+{
+       return shared_ptr<MonoPictureAssetReader> (new MonoPictureAssetReader (this));
+}
+
 string
 MonoPictureAsset::cpl_node_name () const
 {
index a10eada00f1261548ce83e6d4e92c8ea21f9a789..5b36bc33b5b0f463b12d8464374ec569a256184b 100644 (file)
@@ -25,6 +25,7 @@
 namespace dcp {
 
 class MonoPictureAssetWriter;
+class MonoPictureAssetReader;
 
 /** @class MonoPictureAsset
  *  @brief A 2D (monoscopic) picture asset.
@@ -44,6 +45,7 @@ public:
 
        /** Start a progressive write to a MonoPictureAsset */
        boost::shared_ptr<PictureAssetWriter> start_write (boost::filesystem::path, Standard standard, bool);
+       boost::shared_ptr<MonoPictureAssetReader> start_read () const;
 
        bool equals (
                boost::shared_ptr<const Asset> other,
@@ -51,8 +53,6 @@ public:
                NoteHandler note
                ) const;
 
-       boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
-
 private:
        std::string cpl_node_name () const;
 };
diff --git a/src/mono_picture_asset_reader.cc b/src/mono_picture_asset_reader.cc
new file mode 100644 (file)
index 0000000..68606f0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2016 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 "mono_picture_asset_reader.h"
+#include "mono_picture_asset.h"
+#include "mono_picture_frame.h"
+#include "exceptions.h"
+#include "AS_DCP.h"
+
+using namespace dcp;
+using boost::shared_ptr;
+
+MonoPictureAssetReader::MonoPictureAssetReader (MonoPictureAsset const * asset)
+       : AssetReader (asset)
+{
+       _reader = new ASDCP::JP2K::MXFReader ();
+       Kumu::Result_t const r = _reader->OpenRead (asset->file().string().c_str());
+       if (ASDCP_FAILURE (r)) {
+               delete _reader;
+               boost::throw_exception (FileError ("could not open MXF file for reading", asset->file(), r));
+       }
+}
+
+MonoPictureAssetReader::~MonoPictureAssetReader ()
+{
+       delete _reader;
+}
+
+shared_ptr<const MonoPictureFrame>
+MonoPictureAssetReader::get_frame (int n) const
+{
+       return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (_reader, n, _decryption_context));
+}
diff --git a/src/mono_picture_asset_reader.h b/src/mono_picture_asset_reader.h
new file mode 100644 (file)
index 0000000..4d7d83a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2016 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_reader.h"
+#include <boost/shared_ptr.hpp>
+
+namespace ASDCP {
+       namespace JP2K {
+               class MXFReader;
+       }
+}
+
+namespace dcp {
+
+class MonoPictureFrame;
+class MonoPictureAsset;
+
+class MonoPictureAssetReader : public AssetReader
+{
+public:
+       ~MonoPictureAssetReader ();
+       boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
+
+private:
+       friend class MonoPictureAsset;
+
+       MonoPictureAssetReader (MonoPictureAsset const *);
+
+       ASDCP::JP2K::MXFReader* _reader;
+};
+
+}
index a422e7c4053043482c76aa5634dfdcd31c086d82..e870ff0fd7559fc454ce54876dd1dd09beb0ee52 100644 (file)
@@ -56,23 +56,17 @@ MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path)
 }
 
 /** Make a picture frame from a 2D (monoscopic) asset.
- *  @param path Path to the asset's MXF file.
+ *  @param reader Reader for the asset's MXF file.
  *  @param n Frame within the asset, not taking EntryPoint into account.
  *  @param c Context for decryption, or 0.
  */
-MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path, int n, ASDCP::AESDecContext* c)
+MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, ASDCP::AESDecContext* c)
 {
-       ASDCP::JP2K::MXFReader reader;
-       Kumu::Result_t r = reader.OpenRead (path.string().c_str());
-       if (ASDCP_FAILURE (r)) {
-               boost::throw_exception (FileError ("could not open MXF file for reading", path, r));
-       }
-
        /* XXX: unfortunate guesswork on this buffer size */
        _buffer = new ASDCP::JP2K::FrameBuffer (4 * Kumu::Megabyte);
 
-       if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer, c))) {
-               boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1 of %2", n, path.string())));
+       if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
+               boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1", n)));
        }
 }
 
index 9e7a992670fbf88bd3d51afcd8ab8d7fa27325f4..6c004969afb1fb2d0af412152b0f02a74376aa79 100644 (file)
@@ -32,6 +32,7 @@
 namespace ASDCP {
        namespace JP2K {
                class FrameBuffer;
+               class MXFReader;
        }
        class AESDecContext;
 }
@@ -46,7 +47,6 @@ class OpenJPEGImage;
 class MonoPictureFrame : public boost::noncopyable
 {
 public:
-       MonoPictureFrame (boost::filesystem::path path, int n, ASDCP::AESDecContext *);
        MonoPictureFrame (boost::filesystem::path path);
        MonoPictureFrame (uint8_t const * data, int size);
        ~MonoPictureFrame ();
@@ -58,6 +58,10 @@ public:
        int j2k_size () const;
 
 private:
+       friend class MonoPictureAssetReader;
+
+       MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, ASDCP::AESDecContext *);
+
        ASDCP::JP2K::FrameBuffer* _buffer;
 };
 
index f902212ee4a1e10cc5b8bb833b38182d7420a099..67e63283d93903323fa138cfb7520ed92055210f 100644 (file)
@@ -44,17 +44,6 @@ using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 using namespace dcp;
 
-MXF::MXF ()
-       : _decryption_context (0)
-{
-
-}
-
-MXF::~MXF ()
-{
-       delete _decryption_context;
-}
-
 void
 MXF::fill_writer_info (ASDCP::WriterInfo* writer_info, string id, Standard standard) const
 {
@@ -97,11 +86,6 @@ MXF::set_key (Key key)
                /* No key ID so far; we now need one */
                _key_id = make_uuid ();
        }
-
-       _decryption_context = new ASDCP::AESDecContext;
-       if (ASDCP_FAILURE (_decryption_context->InitKey (_key->value ()))) {
-               throw MiscError ("could not set up decryption context");
-       }
 }
 
 string
index a3ba4b102d0dad9b6803a4d955aa01629c8c2214..d490e9e4a8a2e66a80a3d8b868448923bce63813 100644 (file)
--- a/src/mxf.h
+++ b/src/mxf.h
@@ -47,8 +47,7 @@ class PictureAssetWriter;
 class MXF
 {
 public:
-       MXF ();
-       virtual ~MXF ();
+       virtual ~MXF () {}
 
        /** @return true if the data is encrypted */
        bool encrypted () const {
@@ -97,7 +96,6 @@ protected:
         */
        void fill_writer_info (ASDCP::WriterInfo* w, std::string id, Standard standard) const;
 
-       ASDCP::AESDecContext* _decryption_context;
        /** ID of the key used for encryption/decryption, if there is one */
        boost::optional<std::string> _key_id;
        /** Key used for encryption/decryption, if there is one */
index 590472a5ebea2a8d4c66123ebfd7f24a275cfde4..ffafe46c316945bd5ffbca88b62f9ed9641b6627 100644 (file)
@@ -27,6 +27,7 @@
 #include "exceptions.h"
 #include "sound_frame.h"
 #include "sound_asset_writer.h"
+#include "sound_asset_reader.h"
 #include "compose.hpp"
 #include "KM_fileio.h"
 #include "AS_DCP.h"
@@ -125,10 +126,13 @@ SoundAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, NoteHand
 
        shared_ptr<const SoundAsset> other_sound = dynamic_pointer_cast<const SoundAsset> (other);
 
+       shared_ptr<const SoundAssetReader> reader = start_read ();
+       shared_ptr<const SoundAssetReader> other_reader = other_sound->start_read ();
+
        for (int i = 0; i < _intrinsic_duration; ++i) {
 
-               shared_ptr<const SoundFrame> frame_A = get_frame (i);
-               shared_ptr<const SoundFrame> frame_B = other_sound->get_frame (i);
+               shared_ptr<const SoundFrame> frame_A = reader->get_frame (i);
+               shared_ptr<const SoundFrame> frame_B = other_reader->get_frame (i);
 
                if (frame_A->size() != frame_B->size()) {
                        note (DCP_ERROR, String::compose ("sizes of audio data for frame %1 differ", i));
@@ -149,13 +153,6 @@ SoundAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, NoteHand
        return true;
 }
 
-shared_ptr<const SoundFrame>
-SoundAsset::get_frame (int n) const
-{
-       /* XXX: should add on entry point here? */
-       return shared_ptr<const SoundFrame> (new SoundFrame (file(), n, _decryption_context));
-}
-
 shared_ptr<SoundAssetWriter>
 SoundAsset::start_write (boost::filesystem::path file, Standard standard)
 {
@@ -163,6 +160,12 @@ SoundAsset::start_write (boost::filesystem::path file, Standard standard)
        return shared_ptr<SoundAssetWriter> (new SoundAssetWriter (this, file, standard));
 }
 
+shared_ptr<SoundAssetReader>
+SoundAsset::start_read () const
+{
+       return shared_ptr<SoundAssetReader> (new SoundAssetReader (this));
+}
+
 string
 SoundAsset::pkl_type (Standard standard) const
 {
index 73734f9fa67ce5a0ac4209ce19a8836343d2c34a..78b80bc821d32539d7bc190a00e24ec8a349cab8 100644 (file)
@@ -33,6 +33,7 @@ namespace dcp
 
 class SoundFrame;
 class SoundAssetWriter;
+class SoundAssetReader;
 
 /** @class SoundAsset
  *  @brief Representation of a sound asset
@@ -44,6 +45,7 @@ public:
        SoundAsset (Fraction edit_rate, int sampling_rate, int channels);
 
        boost::shared_ptr<SoundAssetWriter> start_write (boost::filesystem::path file, Standard standard);
+       boost::shared_ptr<SoundAssetReader> start_read () const;
 
        bool equals (
                boost::shared_ptr<const Asset> other,
@@ -51,8 +53,6 @@ public:
                NoteHandler note
                ) const;
 
-       boost::shared_ptr<const SoundFrame> get_frame (int n) const;
-
        /** @return number of channels */
        int channels () const {
                return _channels;
diff --git a/src/sound_asset_reader.cc b/src/sound_asset_reader.cc
new file mode 100644 (file)
index 0000000..816f5ad
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "sound_asset_reader.h"
+#include "sound_asset.h"
+#include "sound_frame.h"
+#include "exceptions.h"
+#include "AS_DCP.h"
+
+using boost::shared_ptr;
+using namespace dcp;
+
+SoundAssetReader::SoundAssetReader (SoundAsset const * asset)
+       : AssetReader (asset)
+{
+       _reader = new ASDCP::PCM::MXFReader ();
+       Kumu::Result_t const r = _reader->OpenRead (asset->file().string().c_str());
+       if (ASDCP_FAILURE (r)) {
+               delete _reader;
+               boost::throw_exception (FileError ("could not open MXF file for reading", asset->file(), r));
+       }
+}
+
+SoundAssetReader::~SoundAssetReader ()
+{
+       delete _reader;
+}
+
+shared_ptr<const SoundFrame>
+SoundAssetReader::get_frame (int n) const
+{
+       return shared_ptr<const SoundFrame> (new SoundFrame (_reader, n, _decryption_context));
+}
diff --git a/src/sound_asset_reader.h b/src/sound_asset_reader.h
new file mode 100644 (file)
index 0000000..5012168
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2016 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_reader.h"
+#include <boost/shared_ptr.hpp>
+
+namespace ASDCP {
+       namespace PCM {
+               class MXFReader;
+       }
+}
+
+namespace dcp {
+
+class SoundFrame;
+class SoundAsset;
+
+class SoundAssetReader : public AssetReader
+{
+public:
+       ~SoundAssetReader ();
+       boost::shared_ptr<const SoundFrame> get_frame (int n) const;
+
+private:
+       friend class SoundAsset;
+
+       SoundAssetReader (SoundAsset const * asset);
+
+       ASDCP::PCM::MXFReader* _reader;
+};
+
+}
index 2d31291b63840c1e69185c2ac1ac58ba4a06ac1a..540c3dfde039ea238cd76404c669e50978cd10a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
 using namespace std;
 using namespace dcp;
 
-SoundFrame::SoundFrame (boost::filesystem::path path, int n, ASDCP::AESDecContext* c)
+SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, ASDCP::AESDecContext* c)
 {
-       ASDCP::PCM::MXFReader reader;
-       Kumu::Result_t r = reader.OpenRead (path.string().c_str());
-       if (ASDCP_FAILURE (r)) {
-               boost::throw_exception (FileError ("could not open MXF file for reading", path, r));
-       }
-
        /* XXX: unfortunate guesswork on this buffer size */
        _buffer = new ASDCP::PCM::FrameBuffer (1 * Kumu::Megabyte);
 
-       if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer, c))) {
+       if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
                boost::throw_exception (DCPReadError ("could not read audio frame"));
        }
 }
index 4fdc39e512eea8fe54ed175f3b48d964767fb0dc..742864a81c538426d3a1b7647ef326a07e4ccb2b 100644 (file)
@@ -32,6 +32,7 @@
 namespace ASDCP {
        namespace PCM {
                class FrameBuffer;
+               class MXFReader;
        }
        class AESDecContext;
 }
@@ -44,13 +45,16 @@ namespace dcp {
 class SoundFrame : public boost::noncopyable
 {
 public:
-       SoundFrame (boost::filesystem::path path, int n, ASDCP::AESDecContext *);
        ~SoundFrame ();
 
        uint8_t const * data () const;
        int size () const;
 
 private:
+       friend class SoundAssetReader;
+
+       SoundFrame (ASDCP::PCM::MXFReader* reader, int n, ASDCP::AESDecContext *);
+
        /** a buffer to hold the frame */
        ASDCP::PCM::FrameBuffer* _buffer;
 };
index d8cb7c9a2fa2acb7dead57397172ea06aca55e6d..c7e0575c2af6f7ab345c725b6283860abe34e3e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -23,6 +23,7 @@
 #include "stereo_picture_frame.h"
 #include "exceptions.h"
 #include "stereo_picture_asset_writer.h"
+#include "stereo_picture_asset_reader.h"
 #include "dcp_assert.h"
 
 using std::string;
@@ -63,18 +64,18 @@ StereoPictureAsset::StereoPictureAsset (Fraction edit_rate)
 
 }
 
-shared_ptr<const StereoPictureFrame>
-StereoPictureAsset::get_frame (int n) const
-{
-       return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (file().string(), n));
-}
-
 shared_ptr<PictureAssetWriter>
 StereoPictureAsset::start_write (boost::filesystem::path file, Standard standard, bool overwrite)
 {
        return shared_ptr<StereoPictureAssetWriter> (new StereoPictureAssetWriter (this, file, standard, overwrite));
 }
 
+shared_ptr<StereoPictureAssetReader>
+StereoPictureAsset::start_read () const
+{
+       return shared_ptr<StereoPictureAssetReader> (new StereoPictureAssetReader (this));
+}
+
 bool
 StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, NoteHandler note) const
 {
@@ -106,14 +107,17 @@ StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt,
        shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
        DCP_ASSERT (other_picture);
 
+       shared_ptr<const StereoPictureAssetReader> reader = start_read ();
+       shared_ptr<const StereoPictureAssetReader> other_reader = other_picture->start_read ();
+
        bool result = true;
 
        for (int i = 0; i < _intrinsic_duration; ++i) {
                shared_ptr<const StereoPictureFrame> frame_A;
                shared_ptr<const StereoPictureFrame> frame_B;
                try {
-                       frame_A = get_frame (i);
-                       frame_B = other_picture->get_frame (i);
+                       frame_A = reader->get_frame (i);
+                       frame_B = other_reader->get_frame (i);
                } catch (DCPReadError& e) {
                        /* If there was a problem reading the frame data we'll just assume
                           the two frames are not equal.
index 533be75844472d4862c3ea3c9f758112c7af50f7..9799c49f01f3809fabffa0c584fc53fe70bbd878 100644 (file)
@@ -24,6 +24,8 @@
 
 namespace dcp {
 
+class StereoPictureAssetReader;
+
 /** A 3D (stereoscopic) picture asset */
 class StereoPictureAsset : public PictureAsset
 {
@@ -33,14 +35,13 @@ public:
 
        /** Start a progressive write to a StereoPictureAsset */
        boost::shared_ptr<PictureAssetWriter> start_write (boost::filesystem::path file, Standard, bool);
+       boost::shared_ptr<StereoPictureAssetReader> start_read () const;
 
        bool equals (
                boost::shared_ptr<const Asset> other,
                EqualityOptions opt,
                NoteHandler note
                ) const;
-
-       boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
 };
 
 }
diff --git a/src/stereo_picture_asset_reader.cc b/src/stereo_picture_asset_reader.cc
new file mode 100644 (file)
index 0000000..95db4c2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2016 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 "stereo_picture_asset_reader.h"
+#include "stereo_picture_asset.h"
+#include "stereo_picture_frame.h"
+#include "exceptions.h"
+#include "AS_DCP.h"
+
+using namespace dcp;
+using boost::shared_ptr;
+
+StereoPictureAssetReader::StereoPictureAssetReader (StereoPictureAsset const * asset)
+       : AssetReader (asset)
+{
+       _reader = new ASDCP::JP2K::MXFSReader ();
+       Kumu::Result_t const r = _reader->OpenRead (asset->file().string().c_str());
+       if (ASDCP_FAILURE (r)) {
+               delete _reader;
+               boost::throw_exception (FileError ("could not open MXF file for reading", asset->file(), r));
+       }
+}
+
+StereoPictureAssetReader::~StereoPictureAssetReader ()
+{
+       delete _reader;
+}
+
+shared_ptr<const StereoPictureFrame>
+StereoPictureAssetReader::get_frame (int n) const
+{
+       return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (_reader, n, _decryption_context));
+}
diff --git a/src/stereo_picture_asset_reader.h b/src/stereo_picture_asset_reader.h
new file mode 100644 (file)
index 0000000..15d7f2e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2016 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_reader.h"
+#include <boost/shared_ptr.hpp>
+
+namespace ASDCP {
+       namespace JP2K {
+               class MXFSReader;
+       }
+}
+
+namespace dcp {
+
+class StereoPictureFrame;
+class StereoPictureAsset;
+
+class StereoPictureAssetReader : public AssetReader
+{
+public:
+       ~StereoPictureAssetReader ();
+       boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
+
+private:
+       friend class StereoPictureAsset;
+
+       StereoPictureAssetReader (StereoPictureAsset const *);
+
+       ASDCP::JP2K::MXFSReader* _reader;
+};
+
+}
index de4e0f61baeebf4454b08a8df723c4ebc0e06401..8f7e1b7e3d445283abe1ab30b6ef2ac68312c304 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
index 24f35ef4fef1481970c4659d322ad411fa44cf9b..b68b2ce9789d3713829b3e07c1a73d503f819e36 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 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
 
 namespace dcp {
 
-/** A helper class for writing to StereoPictureAssets progressively (i.e. writing frame-by-frame,
- *  rather than giving libdcp all the frames in one go).
+/** @class StereoPictureAssetWriter
+ *  @brief A helper class for writing to StereoPictureAssets.
  *
  *  Objects of this class can only be created with StereoPictureAsset::start_write().
  *
- *  Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ *  Frames can be written to the StereoPictureAsset by calling write() with a JPEG2000 image
  *  (a verbatim .j2c file).  finalize() must be called after the last frame has been written.
- *  The action of finalize() can't be done in MonoPictureAssetWriter's destructor as it may
+ *  The action of finalize() can't be done in StereoPictureAssetWriter's destructor as it may
  *  throw an exception.
  */
 class StereoPictureAssetWriter : public PictureAssetWriter
index 8573084fdd8872973aa3d7dcff25d64a449da588..c5b199abc06c4f0d4ed385b46d1880f99ee1cdf6 100644 (file)
@@ -33,22 +33,16 @@ using boost::shared_ptr;
 using namespace dcp;
 
 /** Make a picture frame from a 3D (stereoscopic) asset.
- *  @param mxf_path Path to the asset's MXF file.
+ *  @param reader Reader for the MXF file.
  *  @param n Frame within the asset, not taking EntryPoint into account.
  */
-StereoPictureFrame::StereoPictureFrame (boost::filesystem::path path, int n)
+StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, ASDCP::AESDecContext* c)
 {
-       ASDCP::JP2K::MXFSReader reader;
-       Kumu::Result_t r = reader.OpenRead (path.string().c_str());
-       if (ASDCP_FAILURE (r)) {
-               boost::throw_exception (FileError ("could not open MXF file for reading", path, r));
-       }
-
        /* XXX: unfortunate guesswork on this buffer size */
        _buffer = new ASDCP::JP2K::SFrameBuffer (4 * Kumu::Megabyte);
 
-       if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) {
-               boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1 of %2", n, path.string())));
+       if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
+               boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1 of %2", n)));
        }
 }
 
index 5be764fe6ccc0b9f6d7f2f5e1a97f6f30468d297..79d59dc630c1be8a686ea10becda869b92e03b4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 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
@@ -27,7 +27,9 @@
 namespace ASDCP {
        namespace JP2K {
                struct SFrameBuffer;
+               class MXFSReader;
        }
+       class AESDecContext;
 }
 
 namespace dcp {
@@ -38,7 +40,6 @@ class OpenJPEGImage;
 class StereoPictureFrame : public boost::noncopyable
 {
 public:
-       StereoPictureFrame (boost::filesystem::path path, int n);
        StereoPictureFrame ();
        ~StereoPictureFrame ();
 
@@ -53,6 +54,10 @@ public:
        int right_j2k_size () const;
 
 private:
+       friend class StereoPictureAssetReader;
+
+       StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, ASDCP::AESDecContext *);
+
        ASDCP::JP2K::SFrameBuffer* _buffer;
 };
 
index 86f99b33246a0dc78ab0f76044b18932f844e75d..f15b2384c2d1e695ae77c50f8eb2c4d3e03fa607 100644 (file)
@@ -21,6 +21,8 @@ from waflib import TaskGen
 def build(bld):
     source = """
              asset.cc
+             asset_reader.cc
+             asset_writer.cc
              atmos_asset.cc
              certificate_chain.cc
              certificate.cc
@@ -46,10 +48,10 @@ def build(bld):
              metadata.cc
              modified_gamma_transfer_function.cc
              mono_picture_asset.cc
+             mono_picture_asset_reader.cc
              mono_picture_asset_writer.cc
              mono_picture_frame.cc
              mxf.cc
-             asset_writer.cc
              object.cc
              openjpeg_image.cc
              picture_asset.cc
@@ -68,9 +70,11 @@ def build(bld):
              smpte_load_font_node.cc
              smpte_subtitle_asset.cc
              sound_asset.cc
+             sound_asset_reader.cc
              sound_asset_writer.cc
              sound_frame.cc
              stereo_picture_asset.cc
+             stereo_picture_asset_reader.cc
              stereo_picture_asset_writer.cc
              stereo_picture_frame.cc
              subtitle_node.cc
@@ -85,6 +89,8 @@ def build(bld):
 
     headers = """
               asset.h
+              asset_reader.h
+              asset_writer.h
               atmos_asset.h
               certificate_chain.h
               certificate.h
@@ -109,10 +115,10 @@ def build(bld):
               local_time.h
               metadata.h
               mono_picture_asset.h
+              mono_picture_asset_reader.h
               mono_picture_frame.h
               modified_gamma_transfer_function.h
               mxf.h
-              asset_writer.h
               object.h
               openjpeg_image.h
               picture_asset.h
@@ -133,8 +139,11 @@ def build(bld):
               smpte_subtitle_asset.h
               sound_frame.h
               sound_asset.h
+              sound_asset_reader.h
               sound_asset_writer.h
               stereo_picture_asset.h
+              stereo_picture_asset_reader.h
+              stereo_picture_asset_writer.h
               stereo_picture_frame.h
               subtitle_node.h
               subtitle_asset.h
index 2f0bb420610ff4d8170d85d7f6dbf2d930a6dbf1..1496a0d5ebae80454b1d182e9c8dc779296bb3b0 100644 (file)
@@ -23,6 +23,7 @@
 #include "decrypted_kdm.h"
 #include "encrypted_kdm.h"
 #include "mono_picture_asset.h"
+#include "mono_picture_asset_reader.h"
 #include "reel_picture_asset.h"
 #include "reel.h"
 #include "test.h"
@@ -46,7 +47,8 @@ get_frame (dcp::DCP const & dcp)
        BOOST_CHECK (picture);
 
        shared_ptr<const dcp::MonoPictureAsset> mono_picture = dynamic_pointer_cast<const dcp::MonoPictureAsset> (picture);
-       shared_ptr<const dcp::MonoPictureFrame> j2k_frame = mono_picture->get_frame (0);
+       shared_ptr<const dcp::MonoPictureAssetReader> reader = mono_picture->start_read ();
+       shared_ptr<const dcp::MonoPictureFrame> j2k_frame = reader->get_frame (0);
        shared_ptr<dcp::OpenJPEGImage> xyz = j2k_frame->xyz_image();
 
        uint8_t* argb = new uint8_t[xyz->size().width * xyz->size().height * 4];
index 45b2cbadd361a8425a75cc9a5fee3b8c9b12e678..e735a2764c765c4b9fc7cd2080ce51985539964a 100644 (file)
@@ -29,6 +29,7 @@
 #include "mono_picture_frame.h"
 #include "certificate_chain.h"
 #include "mono_picture_asset_writer.h"
+#include "mono_picture_asset_reader.h"
 #include "reel_picture_asset.h"
 #include "reel_mono_picture_asset.h"
 #include "file.h"
@@ -107,8 +108,8 @@ BOOST_AUTO_TEST_CASE (round_trip_test)
        BOOST_CHECK (!kdm_B.keys().empty ());
        asset_B->set_key (kdm_B.keys().front().key());
 
-       shared_ptr<dcp::OpenJPEGImage> xyz_A = asset_A->get_frame(0)->xyz_image ();
-       shared_ptr<dcp::OpenJPEGImage> xyz_B = asset_B->get_frame(0)->xyz_image ();
+       shared_ptr<dcp::OpenJPEGImage> xyz_A = asset_A->start_read()->get_frame(0)->xyz_image ();
+       shared_ptr<dcp::OpenJPEGImage> xyz_B = asset_B->start_read()->get_frame(0)->xyz_image ();
 
        scoped_array<uint8_t> frame_A (new uint8_t[xyz_A->size().width * xyz_A->size().height * 4]);
        dcp::xyz_to_rgba (xyz_A, dcp::ColourConversion::srgb_to_xyz(), frame_A.get());
index fa7e210368d7fcb26aedd31234a0633cd9a60e7f..837cfe32f5f2cdda3d36f00711b9b979d1218d5d 100644 (file)
 #include <boost/test/unit_test.hpp>
 #include "test.h"
 #include "sound_frame.h"
+#include "sound_asset.h"
+#include "sound_asset_reader.h"
 #include "exceptions.h"
 #include <sndfile.h>
 
+using boost::shared_ptr;
+
 BOOST_AUTO_TEST_CASE (sound_frame_test)
 {
        int const frame_length = 2000;
        int const channels = 6;
 
-       dcp::SoundFrame frame (
-               private_test / "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV/pcm_95734608-5d47-4d3f-bf5f-9e9186b66afa_.mxf",
-               42,
-               0
+       dcp::SoundAsset asset (
+               private_test / "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV/pcm_95734608-5d47-4d3f-bf5f-9e9186b66afa_.mxf"
                );
 
-       BOOST_REQUIRE_EQUAL (frame.size(), channels * frame_length * 3);
+       shared_ptr<const dcp::SoundFrame> frame = asset.start_read()->get_frame(42);
+
+       BOOST_REQUIRE_EQUAL (frame->size(), channels * frame_length * 3);
 
        boost::filesystem::path ref_file = private_test / "data" / "frame.wav";
        SF_INFO info;
@@ -46,7 +50,7 @@ BOOST_AUTO_TEST_CASE (sound_frame_test)
        int const read = sf_readf_int (sndfile, ref_data, frame_length);
        BOOST_REQUIRE_EQUAL (read, frame_length);
 
-       uint8_t const * p = frame.data ();
+       uint8_t const * p = frame->data ();
        for (int i = 0; i < (frame_length * channels); ++i) {
                int x = ref_data[i] >> 8;
                if (x < 0) {
@@ -60,11 +64,12 @@ BOOST_AUTO_TEST_CASE (sound_frame_test)
 
 BOOST_AUTO_TEST_CASE (sound_frame_test2)
 {
-       BOOST_CHECK_THROW (dcp::SoundFrame ("frobozz", 42, 0), dcp::FileError);
-       BOOST_CHECK_THROW (dcp::SoundFrame (
-                                  private_test /
-                                  "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV/pcm_95734608-5d47-4d3f-bf5f-9e9186b66afa_.mxf",
-                                  999999999, 0
-                                  ), dcp::DCPReadError
+       BOOST_CHECK_THROW (dcp::SoundAsset("frobozz"), dcp::FileError);
+
+       dcp::SoundAsset asset (
+               private_test /
+               "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV/pcm_95734608-5d47-4d3f-bf5f-9e9186b66afa_.mxf"
                );
+
+       BOOST_CHECK_THROW (asset.start_read()->get_frame (99999999), dcp::DCPReadError);
 }