From a68b877d96a9e9f366f27752e071bc0e895e9dc7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 1 Jun 2016 23:53:06 +0100 Subject: [PATCH] Add Reader classes to permit much more efficient DCP reading. --- examples/read_dcp.cc | 6 +++- src/asset_reader.cc | 42 +++++++++++++++++++++++++ src/asset_reader.h | 44 +++++++++++++++++++++++++++ src/mono_picture_asset.cc | 22 ++++++++------ src/mono_picture_asset.h | 4 +-- src/mono_picture_asset_reader.cc | 49 ++++++++++++++++++++++++++++++ src/mono_picture_asset_reader.h | 48 +++++++++++++++++++++++++++++ src/mono_picture_frame.cc | 14 +++------ src/mono_picture_frame.h | 6 +++- src/mxf.cc | 16 ---------- src/mxf.h | 4 +-- src/sound_asset.cc | 21 +++++++------ src/sound_asset.h | 4 +-- src/sound_asset_reader.cc | 49 ++++++++++++++++++++++++++++++ src/sound_asset_reader.h | 48 +++++++++++++++++++++++++++++ src/sound_frame.cc | 12 ++------ src/sound_frame.h | 6 +++- src/stereo_picture_asset.cc | 22 ++++++++------ src/stereo_picture_asset.h | 5 +-- src/stereo_picture_asset_reader.cc | 49 ++++++++++++++++++++++++++++++ src/stereo_picture_asset_reader.h | 48 +++++++++++++++++++++++++++++ src/stereo_picture_asset_writer.cc | 2 +- src/stereo_picture_asset_writer.h | 10 +++--- src/stereo_picture_frame.cc | 14 +++------ src/stereo_picture_frame.h | 9 ++++-- src/wscript | 13 ++++++-- test/decryption_test.cc | 4 ++- test/round_trip_test.cc | 5 +-- test/sound_frame_test.cc | 29 ++++++++++-------- 29 files changed, 496 insertions(+), 109 deletions(-) create mode 100644 src/asset_reader.cc create mode 100644 src/asset_reader.h create mode 100644 src/mono_picture_asset_reader.cc create mode 100644 src/mono_picture_asset_reader.h create mode 100644 src/sound_asset_reader.cc create mode 100644 src/sound_asset_reader.h create mode 100644 src/stereo_picture_asset_reader.cc create mode 100644 src/stereo_picture_asset_reader.h diff --git a/examples/read_dcp.cc b/examples/read_dcp.cc index 4e3f4836..6cc9b676 100644 --- a/examples/read_dcp.cc +++ b/examples/read_dcp.cc @@ -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 picture_asset_reader = picture_asset->start_read(); + /* Get the 1000th frame of it */ - boost::shared_ptr picture_frame_j2k = picture_asset->get_frame(999); + boost::shared_ptr picture_frame_j2k = picture_asset_reader->get_frame(999); /* Get the frame as an XYZ image */ boost::shared_ptr picture_image_xyz = picture_frame_j2k->xyz_image (); diff --git a/src/asset_reader.cc b/src/asset_reader.cc new file mode 100644 index 00000000..a78af4d3 --- /dev/null +++ b/src/asset_reader.cc @@ -0,0 +1,42 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 . + +*/ + +#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 index 00000000..688b1a3d --- /dev/null +++ b/src/asset_reader.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 . + +*/ + +#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 diff --git a/src/mono_picture_asset.cc b/src/mono_picture_asset.cc index 9d0d1497..1a3656cc 100644 --- a/src/mono_picture_asset.cc +++ b/src/mono_picture_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington 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 -MonoPictureAsset::get_frame (int n) const -{ - return shared_ptr (new MonoPictureFrame (_file, n, _decryption_context)); -} - static void storing_note_handler (list >& notes, NoteType t, string s) { @@ -118,6 +113,9 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, No #pragma omp parallel for #endif + shared_ptr reader = start_read (); + shared_ptr 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 other, EqualityOptions opt, No if (result || opt.keep_going) { - shared_ptr frame_A = get_frame (i); - shared_ptr frame_B = other_picture->get_frame (i); + shared_ptr frame_A = reader->get_frame (i); + shared_ptr frame_B = other_reader->get_frame (i); list > notes; @@ -160,6 +158,12 @@ MonoPictureAsset::start_write (boost::filesystem::path file, Standard standard, return shared_ptr (new MonoPictureAssetWriter (this, file, standard, overwrite)); } +shared_ptr +MonoPictureAsset::start_read () const +{ + return shared_ptr (new MonoPictureAssetReader (this)); +} + string MonoPictureAsset::cpl_node_name () const { diff --git a/src/mono_picture_asset.h b/src/mono_picture_asset.h index a10eada0..5b36bc33 100644 --- a/src/mono_picture_asset.h +++ b/src/mono_picture_asset.h @@ -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 start_write (boost::filesystem::path, Standard standard, bool); + boost::shared_ptr start_read () const; bool equals ( boost::shared_ptr other, @@ -51,8 +53,6 @@ public: NoteHandler note ) const; - boost::shared_ptr 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 index 00000000..68606f03 --- /dev/null +++ b/src/mono_picture_asset_reader.cc @@ -0,0 +1,49 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 +MonoPictureAssetReader::get_frame (int n) const +{ + return shared_ptr (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 index 00000000..4d7d83a9 --- /dev/null +++ b/src/mono_picture_asset_reader.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 + +namespace ASDCP { + namespace JP2K { + class MXFReader; + } +} + +namespace dcp { + +class MonoPictureFrame; +class MonoPictureAsset; + +class MonoPictureAssetReader : public AssetReader +{ +public: + ~MonoPictureAssetReader (); + boost::shared_ptr get_frame (int n) const; + +private: + friend class MonoPictureAsset; + + MonoPictureAssetReader (MonoPictureAsset const *); + + ASDCP::JP2K::MXFReader* _reader; +}; + +} diff --git a/src/mono_picture_frame.cc b/src/mono_picture_frame.cc index a422e7c4..e870ff0f 100644 --- a/src/mono_picture_frame.cc +++ b/src/mono_picture_frame.cc @@ -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))); } } diff --git a/src/mono_picture_frame.h b/src/mono_picture_frame.h index 9e7a9926..6c004969 100644 --- a/src/mono_picture_frame.h +++ b/src/mono_picture_frame.h @@ -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; }; diff --git a/src/mxf.cc b/src/mxf.cc index f902212e..67e63283 100644 --- a/src/mxf.cc +++ b/src/mxf.cc @@ -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 diff --git a/src/mxf.h b/src/mxf.h index a3ba4b10..d490e9e4 100644 --- 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 _key_id; /** Key used for encryption/decryption, if there is one */ diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 590472a5..ffafe46c 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -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 other, EqualityOptions opt, NoteHand shared_ptr other_sound = dynamic_pointer_cast (other); + shared_ptr reader = start_read (); + shared_ptr other_reader = other_sound->start_read (); + for (int i = 0; i < _intrinsic_duration; ++i) { - shared_ptr frame_A = get_frame (i); - shared_ptr frame_B = other_sound->get_frame (i); + shared_ptr frame_A = reader->get_frame (i); + shared_ptr 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 other, EqualityOptions opt, NoteHand return true; } -shared_ptr -SoundAsset::get_frame (int n) const -{ - /* XXX: should add on entry point here? */ - return shared_ptr (new SoundFrame (file(), n, _decryption_context)); -} - shared_ptr 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 (new SoundAssetWriter (this, file, standard)); } +shared_ptr +SoundAsset::start_read () const +{ + return shared_ptr (new SoundAssetReader (this)); +} + string SoundAsset::pkl_type (Standard standard) const { diff --git a/src/sound_asset.h b/src/sound_asset.h index 73734f9f..78b80bc8 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -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 start_write (boost::filesystem::path file, Standard standard); + boost::shared_ptr start_read () const; bool equals ( boost::shared_ptr other, @@ -51,8 +53,6 @@ public: NoteHandler note ) const; - boost::shared_ptr 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 index 00000000..816f5add --- /dev/null +++ b/src/sound_asset_reader.cc @@ -0,0 +1,49 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 +SoundAssetReader::get_frame (int n) const +{ + return shared_ptr (new SoundFrame (_reader, n, _decryption_context)); +} diff --git a/src/sound_asset_reader.h b/src/sound_asset_reader.h new file mode 100644 index 00000000..50121686 --- /dev/null +++ b/src/sound_asset_reader.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 + +namespace ASDCP { + namespace PCM { + class MXFReader; + } +} + +namespace dcp { + +class SoundFrame; +class SoundAsset; + +class SoundAssetReader : public AssetReader +{ +public: + ~SoundAssetReader (); + boost::shared_ptr get_frame (int n) const; + +private: + friend class SoundAsset; + + SoundAssetReader (SoundAsset const * asset); + + ASDCP::PCM::MXFReader* _reader; +}; + +} diff --git a/src/sound_frame.cc b/src/sound_frame.cc index 2d31291b..540c3dfd 100644 --- a/src/sound_frame.cc +++ b/src/sound_frame.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington This file is part of libdcp. @@ -30,18 +30,12 @@ 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")); } } diff --git a/src/sound_frame.h b/src/sound_frame.h index 4fdc39e5..742864a8 100644 --- a/src/sound_frame.h +++ b/src/sound_frame.h @@ -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; }; diff --git a/src/stereo_picture_asset.cc b/src/stereo_picture_asset.cc index d8cb7c9a..c7e0575c 100644 --- a/src/stereo_picture_asset.cc +++ b/src/stereo_picture_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington 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 -StereoPictureAsset::get_frame (int n) const -{ - return shared_ptr (new StereoPictureFrame (file().string(), n)); -} - shared_ptr StereoPictureAsset::start_write (boost::filesystem::path file, Standard standard, bool overwrite) { return shared_ptr (new StereoPictureAssetWriter (this, file, standard, overwrite)); } +shared_ptr +StereoPictureAsset::start_read () const +{ + return shared_ptr (new StereoPictureAssetReader (this)); +} + bool StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, NoteHandler note) const { @@ -106,14 +107,17 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, shared_ptr other_picture = dynamic_pointer_cast (other); DCP_ASSERT (other_picture); + shared_ptr reader = start_read (); + shared_ptr other_reader = other_picture->start_read (); + bool result = true; for (int i = 0; i < _intrinsic_duration; ++i) { shared_ptr frame_A; shared_ptr 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. diff --git a/src/stereo_picture_asset.h b/src/stereo_picture_asset.h index 533be758..9799c49f 100644 --- a/src/stereo_picture_asset.h +++ b/src/stereo_picture_asset.h @@ -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 start_write (boost::filesystem::path file, Standard, bool); + boost::shared_ptr start_read () const; bool equals ( boost::shared_ptr other, EqualityOptions opt, NoteHandler note ) const; - - boost::shared_ptr 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 index 00000000..95db4c2b --- /dev/null +++ b/src/stereo_picture_asset_reader.cc @@ -0,0 +1,49 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 +StereoPictureAssetReader::get_frame (int n) const +{ + return shared_ptr (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 index 00000000..15d7f2e0 --- /dev/null +++ b/src/stereo_picture_asset_reader.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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 + +namespace ASDCP { + namespace JP2K { + class MXFSReader; + } +} + +namespace dcp { + +class StereoPictureFrame; +class StereoPictureAsset; + +class StereoPictureAssetReader : public AssetReader +{ +public: + ~StereoPictureAssetReader (); + boost::shared_ptr get_frame (int n) const; + +private: + friend class StereoPictureAsset; + + StereoPictureAssetReader (StereoPictureAsset const *); + + ASDCP::JP2K::MXFSReader* _reader; +}; + +} diff --git a/src/stereo_picture_asset_writer.cc b/src/stereo_picture_asset_writer.cc index de4e0f61..8f7e1b7e 100644 --- a/src/stereo_picture_asset_writer.cc +++ b/src/stereo_picture_asset_writer.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington This file is part of libdcp. diff --git a/src/stereo_picture_asset_writer.h b/src/stereo_picture_asset_writer.h index 24f35ef4..b68b2ce9 100644 --- a/src/stereo_picture_asset_writer.h +++ b/src/stereo_picture_asset_writer.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington 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,14 +27,14 @@ 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 diff --git a/src/stereo_picture_frame.cc b/src/stereo_picture_frame.cc index 8573084f..c5b199ab 100644 --- a/src/stereo_picture_frame.cc +++ b/src/stereo_picture_frame.cc @@ -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))); } } diff --git a/src/stereo_picture_frame.h b/src/stereo_picture_frame.h index 5be764fe..79d59dc6 100644 --- a/src/stereo_picture_frame.h +++ b/src/stereo_picture_frame.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington 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; }; diff --git a/src/wscript b/src/wscript index 86f99b33..f15b2384 100644 --- a/src/wscript +++ b/src/wscript @@ -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 diff --git a/test/decryption_test.cc b/test/decryption_test.cc index 2f0bb420..1496a0d5 100644 --- a/test/decryption_test.cc +++ b/test/decryption_test.cc @@ -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 mono_picture = dynamic_pointer_cast (picture); - shared_ptr j2k_frame = mono_picture->get_frame (0); + shared_ptr reader = mono_picture->start_read (); + shared_ptr j2k_frame = reader->get_frame (0); shared_ptr xyz = j2k_frame->xyz_image(); uint8_t* argb = new uint8_t[xyz->size().width * xyz->size().height * 4]; diff --git a/test/round_trip_test.cc b/test/round_trip_test.cc index 45b2cbad..e735a276 100644 --- a/test/round_trip_test.cc +++ b/test/round_trip_test.cc @@ -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 xyz_A = asset_A->get_frame(0)->xyz_image (); - shared_ptr xyz_B = asset_B->get_frame(0)->xyz_image (); + shared_ptr xyz_A = asset_A->start_read()->get_frame(0)->xyz_image (); + shared_ptr xyz_B = asset_B->start_read()->get_frame(0)->xyz_image (); scoped_array 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()); diff --git a/test/sound_frame_test.cc b/test/sound_frame_test.cc index fa7e2103..837cfe32 100644 --- a/test/sound_frame_test.cc +++ b/test/sound_frame_test.cc @@ -20,21 +20,25 @@ #include #include "test.h" #include "sound_frame.h" +#include "sound_asset.h" +#include "sound_asset_reader.h" #include "exceptions.h" #include +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 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); } -- 2.30.2