Some hacks.
authorCarl Hetherington <cth@carlh.net>
Mon, 22 Jul 2013 07:22:52 +0000 (08:22 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 22 Jul 2013 07:22:52 +0000 (08:22 +0100)
src/picture_asset.cc
src/picture_asset.h
src/picture_asset_writer.cc [new file with mode: 0644]
src/picture_asset_writer.h [new file with mode: 0644]
src/wscript
test/recovery_test.cc

index 824ebf805e56026a4dcc27e3e69b5ccffdd8095f..2ecfa2290896e3ec325f40cde39f1014816e6622 100644 (file)
@@ -37,6 +37,7 @@
 #include "exceptions.h"
 #include "picture_frame.h"
 #include "xyz_frame.h"
+#include "picture_asset_writer.h"
 
 using std::string;
 using std::ostream;
@@ -429,126 +430,14 @@ MonoPictureAsset::start_write (bool overwrite, MXFMetadata const & metadata)
        return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite, metadata));
 }
 
-FrameInfo::FrameInfo (istream& s)
-{
-       s >> offset >> size >> hash;
-}
-
-void
-FrameInfo::write (ostream& s)
-{
-       s << offset << " " << size << " " << hash;
-}
-
-struct MonoPictureAssetWriter::ASDCPState
-{
-       ASDCPState()
-               : frame_buffer (4 * Kumu::Megabyte)
-       {}
-       
-       ASDCP::JP2K::CodestreamParser j2k_parser;
-       ASDCP::JP2K::FrameBuffer frame_buffer;
-       ASDCP::JP2K::MXFWriter mxf_writer;
-       ASDCP::WriterInfo writer_info;
-       ASDCP::JP2K::PictureDescriptor picture_descriptor;
-};
-
-
-/** @param a Asset to write to.  `a' must not be deleted while
- *  this writer class still exists, or bad things will happen.
- */
-MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite, MXFMetadata const & m)
-       : _state (new MonoPictureAssetWriter::ASDCPState)
-       , _asset (a)
-       , _frames_written (0)
-       , _started (false)
-       , _finalized (false)
-       , _overwrite (overwrite)
-       , _metadata (m)
-{
-
-}
-
-
-void
-MonoPictureAssetWriter::start (uint8_t* data, int size)
-{
-       if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) {
-               boost::throw_exception (MiscError ("could not parse J2K frame"));
-       }
-
-       _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor);
-       _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
-       
-       _asset->fill_writer_info (&_state->writer_info, _asset->uuid(), _metadata);
-       
-       if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (
-                                  _asset->path().string().c_str(),
-                                  _state->writer_info,
-                                  _state->picture_descriptor,
-                                  16384,
-                                  _overwrite)
-                   )) {
-               
-               boost::throw_exception (MXFFileError ("could not open MXF file for writing", _asset->path().string()));
-       }
-
-       _started = true;
-}
-
-FrameInfo
-MonoPictureAssetWriter::write (uint8_t* data, int size)
-{
-       assert (!_finalized);
-
-       if (!_started) {
-               start (data, size);
-       }
-
-       if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) {
-               boost::throw_exception (MiscError ("could not parse J2K frame"));
-       }
-
-       uint64_t const before_offset = _state->mxf_writer.Tell ();
-
-       string hash;
-       if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0, &hash))) {
-               boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
-       }
-
-       ++_frames_written;
-       return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
-}
-
-void
-MonoPictureAssetWriter::fake_write (int size)
+string
+PictureAsset::key_type () const
 {
-       assert (_started);
-       assert (!_finalized);
-
-       if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) {
-               boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
-       }
-
-       ++_frames_written;
+       return "MDIK";
 }
 
-void
-MonoPictureAssetWriter::finalize ()
+StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, Size size)
+       : PictureAsset (directory, mxf_name, 0, fps, 0, false, size)
 {
-       assert (!_finalized);
-       
-       if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
-               boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string()));
-       }
-
-       _finalized = true;
-       _asset->set_intrinsic_duration (_frames_written);
-       _asset->set_duration (_frames_written);
-}
 
-string
-PictureAsset::key_type () const
-{
-       return "MDIK";
 }
index cc99ddbcbe0ea592d89000fee51a7958c44114c5..2031a9ed5bd052b72074e07a6bc52be3e5eb7226 100644 (file)
@@ -33,7 +33,9 @@ namespace libdcp
 {
 
 class MonoPictureFrame;        
-class StereoPictureFrame;      
+class StereoPictureFrame;
+class MonoPictureAssetWriter;
+class StereoPictureAssetWriter;
 
 /** @brief An asset made up of JPEG2000 files */
 class PictureAsset : public MXFAsset
@@ -84,66 +86,6 @@ private:
 
 class MonoPictureAsset;
 
-struct FrameInfo
-{
-       FrameInfo (uint64_t o, uint64_t s, std::string h)
-               : offset (o)
-               , size (s)
-               , hash (h)
-       {}
-
-       FrameInfo (std::istream& s);
-
-       void write (std::ostream& s);
-       
-       uint64_t offset;
-       uint64_t size;
-       std::string hash;
-};
-
-/** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame,
- *  rather than giving libdcp all the frames in one go).
- *
- *  Objects of this class can only be created with MonoPictureAsset::start_write().
- *
- *  Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
- *  (a verbatim .j2 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
- *  throw an exception.
- */
-class MonoPictureAssetWriter
-{
-public:
-       FrameInfo write (uint8_t* data, int size);
-       void fake_write (int size);
-       void finalize ();
-
-private:
-       friend class MonoPictureAsset;
-
-       MonoPictureAssetWriter (MonoPictureAsset *, bool, MXFMetadata const &);
-       void start (uint8_t *, int);
-
-       /* no copy construction */
-       MonoPictureAssetWriter (MonoPictureAssetWriter const &);
-       MonoPictureAssetWriter& operator= (MonoPictureAssetWriter const &);
-
-       /* do this with an opaque pointer so we don't have to include
-          ASDCP headers
-       */
-          
-       struct ASDCPState;
-       boost::shared_ptr<ASDCPState> _state;
-
-       MonoPictureAsset* _asset;
-       /** Number of picture frames written to the asset so far */
-       int _frames_written;
-       bool _started;
-       /** true if finalize() has been called */
-       bool _finalized;
-       bool _overwrite;
-       MXFMetadata _metadata;
-};
 
 /** A 2D (monoscopic) picture asset */
 class MonoPictureAsset : public PictureAsset
@@ -229,7 +171,20 @@ class StereoPictureAsset : public PictureAsset
 {
 public:
        StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration);
-       
+
+       /** Construct a StereoPictureAsset for progressive writing using
+        *  start_write() and a StereoPictureAssetWriter.
+        *
+        *  @param directory Directory to put the MXF in.
+        *  @param mxf_name Filename of the MXF within this directory.
+        *  @param fps Video frames per second.
+        *  @param size Size in pixels that the picture frames will be.
+        */
+       StereoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size);
+
+       /** Start a progressive write to a StereoPictureAsset */
+       boost::shared_ptr<StereoPictureAssetWriter> start_write (bool, MXFMetadata const & metadata = MXFMetadata ());
+
        boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
        bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
 };
diff --git a/src/picture_asset_writer.cc b/src/picture_asset_writer.cc
new file mode 100644 (file)
index 0000000..748de2d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+    Copyright (C) 2012-2013 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 "AS_DCP.h"
+#include "KM_fileio.h"
+#include "picture_asset_writer.h"
+#include "exceptions.h"
+#include "picture_asset.h"
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace libdcp;
+
+FrameInfo::FrameInfo (istream& s)
+{
+       s >> offset >> size >> hash;
+}
+
+void
+FrameInfo::write (ostream& s)
+{
+       s << offset << " " << size << " " << hash;
+}
+
+
+PictureAssetWriter::PictureAssetWriter (bool overwrite, MXFMetadata const & metadata)
+       : _frames_written (0)
+       , _started (false)
+       , _finalized (false)
+       , _overwrite (overwrite)
+       , _metadata (metadata)
+{
+       
+}
+
+struct MonoPictureAssetWriter::ASDCPState
+{
+       ASDCPState()
+               : frame_buffer (4 * Kumu::Megabyte)
+       {}
+       
+       ASDCP::JP2K::CodestreamParser j2k_parser;
+       ASDCP::JP2K::FrameBuffer frame_buffer;
+       ASDCP::JP2K::MXFWriter mxf_writer;
+       ASDCP::WriterInfo writer_info;
+       ASDCP::JP2K::PictureDescriptor picture_descriptor;
+};
+
+struct StereoPictureAssetWriter::ASDCPState
+{
+       ASDCPState()
+               : frame_buffer (4 * Kumu::Megabyte)
+       {}
+       
+       ASDCP::JP2K::CodestreamParser j2k_parser;
+       ASDCP::JP2K::SFrameBuffer frame_buffer;
+       ASDCP::JP2K::MXFSWriter mxf_writer;
+       ASDCP::WriterInfo writer_info;
+       ASDCP::JP2K::PictureDescriptor picture_descriptor;
+};
+
+/** @param a Asset to write to.  `a' must not be deleted while
+ *  this writer class still exists, or bad things will happen.
+ */
+MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* asset, bool overwrite, MXFMetadata const & metadata)
+       : PictureAssetWriter (overwrite, metadata)
+       , _state (new MonoPictureAssetWriter::ASDCPState)
+       , _asset (asset)
+{
+
+}
+
+StereoPictureAssetWriter::StereoPictureAssetWriter (StereoPictureAsset* asset, bool overwrite, MXFMetadata const & metadata)
+       : PictureAssetWriter (overwrite, metadata)
+       , _state (new StereoPictureAssetWriter::ASDCPState)
+       , _asset (asset)
+{
+
+}
+
+template <class P, class Q>
+void start (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t* data, int size)
+{
+       if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
+               boost::throw_exception (MiscError ("could not parse J2K frame"));
+       }
+
+       state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
+       state->picture_descriptor.EditRate = ASDCP::Rational (asset->edit_rate(), 1);
+       
+       asset->fill_writer_info (&state->writer_info, asset->uuid(), writer->_metadata);
+       
+       if (ASDCP_FAILURE (state->mxf_writer.OpenWrite (
+                                  asset->path().string().c_str(),
+                                  state->writer_info,
+                                  state->picture_descriptor,
+                                  16384,
+                                  writer->_overwrite)
+                   )) {
+               
+               boost::throw_exception (MXFFileError ("could not open MXF file for writing", asset->path().string()));
+       }
+
+       writer->_started = true;
+}
+
+void
+MonoPictureAssetWriter::start (uint8_t* data, int size)
+{
+       ::start (this, _state, _asset, data, size);
+}
+
+void
+StereoPictureAssetWriter::start (uint8_t* data, int size)
+{
+       ::start (this, _state, _asset, data, size);
+}
+
+template <class P, class Q>
+FrameInfo write (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t* data, int size)
+{
+       assert (!writer->_finalized);
+
+       if (!writer->_started) {
+               writer->start (data, size);
+       }
+
+       if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
+               boost::throw_exception (MiscError ("could not parse J2K frame"));
+       }
+
+       uint64_t const before_offset = state->mxf_writer.Tell ();
+
+       string hash;
+       if (ASDCP_FAILURE (state->mxf_writer.WriteFrame (state->frame_buffer, 0, 0, &hash))) {
+               boost::throw_exception (MXFFileError ("error in writing video MXF", asset->path().string()));
+       }
+
+       ++asset->_frames_written;
+       return FrameInfo (before_offset, state->mxf_writer.Tell() - before_offset, hash);
+}
+
+FrameInfo
+MonoPictureAssetWriter::write (uint8_t* data, int size)
+{
+       return ::write (this, _state, _asset, data, size);
+}
+
+FrameInfo
+StereoPictureAssetWriter::write (uint8_t* data, int size)
+{
+       return ::write (this, _state, _asset, data, size);
+}
+
+void
+MonoPictureAssetWriter::fake_write (int size)
+{
+       assert (_started);
+       assert (!_finalized);
+
+       if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) {
+               boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
+       }
+
+       ++_frames_written;
+}
+
+void
+StereoPictureAssetWriter::fake_write (int size)
+{
+       assert (_started);
+       assert (!_finalized);
+
+       if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) {
+               boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
+       }
+
+       ++_frames_written;
+}
+
+void
+MonoPictureAssetWriter::finalize ()
+{
+       assert (!_finalized);
+       
+       if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
+               boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string()));
+       }
+
+       _finalized = true;
+       _asset->set_intrinsic_duration (_frames_written);
+       _asset->set_duration (_frames_written);
+}
+
+void
+StereoPictureAssetWriter::finalize ()
+{
+       assert (!_finalized);
+       
+       if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
+               boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string()));
+       }
+
+       _finalized = true;
+       _asset->set_intrinsic_duration (_frames_written);
+       _asset->set_duration (_frames_written);
+}
diff --git a/src/picture_asset_writer.h b/src/picture_asset_writer.h
new file mode 100644 (file)
index 0000000..5c2b0fe
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+    Copyright (C) 2012-2013 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 <stdint.h>
+#include <string>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include "metadata.h"
+
+namespace libdcp {
+
+class MonoPictureAsset;        
+class StereoPictureAsset;      
+
+struct FrameInfo
+{
+       FrameInfo (uint64_t o, uint64_t s, std::string h)
+               : offset (o)
+               , size (s)
+               , hash (h)
+       {}
+
+       FrameInfo (std::istream& s);
+
+       void write (std::ostream& s);
+       
+       uint64_t offset;
+       uint64_t size;
+       std::string hash;
+};
+
+class PictureAssetWriter : public boost::noncopyable
+{
+public:
+       virtual FrameInfo write (uint8_t *, int) = 0;
+       virtual void fake_write (int) = 0;
+       virtual void finalize () = 0;
+       
+protected:
+
+       PictureAssetWriter (bool, MXFMetadata const &);
+       virtual void start (uint8_t *, int) = 0;
+       
+       /** Number of picture frames written to the asset so far */
+       int _frames_written;
+       bool _started;
+       /** true if finalize() has been called */
+       bool _finalized;
+       bool _overwrite;
+       MXFMetadata _metadata;
+};
+
+/** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame,
+ *  rather than giving libdcp all the frames in one go).
+ *
+ *  Objects of this class can only be created with MonoPictureAsset::start_write().
+ *
+ *  Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ *  (a verbatim .j2 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
+ *  throw an exception.
+ */
+class MonoPictureAssetWriter : public PictureAssetWriter
+{
+public:
+       FrameInfo write (uint8_t* data, int size);
+       void fake_write (int size);
+       void finalize ();
+
+private:
+       friend class MonoPictureAsset;
+
+       MonoPictureAssetWriter (MonoPictureAsset *, bool, MXFMetadata const &);
+       void start (uint8_t *, int);
+
+       /* do this with an opaque pointer so we don't have to include
+          ASDCP headers
+       */
+          
+       struct ASDCPState;
+       boost::shared_ptr<ASDCPState> _state;
+
+       MonoPictureAsset* _asset;
+};
+
+class StereoPictureAssetWriter : public PictureAssetWriter
+{
+public:
+       FrameInfo write (uint8_t* data, int size);
+       void fake_write (int size);
+       void finalize ();
+
+private:
+       friend class StereoPictureAsset;
+
+       StereoPictureAssetWriter (StereoPictureAsset *, bool, MXFMetadata const &);
+       void start (uint8_t *, int);
+
+       /* do this with an opaque pointer so we don't have to include
+          ASDCP headers
+       */
+          
+       struct ASDCPState;
+       boost::shared_ptr<ASDCPState> _state;
+
+       StereoPictureAsset* _asset;
+};
+
+}
index 16b92447bea8ed4dfe727897a565ad04cd545222..2f20721cbe21c468a7754ce3c7d2b610fdea110b 100644 (file)
@@ -24,6 +24,7 @@ def build(bld):
                  metadata.cc
                  mxf_asset.cc
                  picture_asset.cc
+                 picture_asset_writer.cc
                  picture_frame.cc
                  rec709_linearised_gamma_lut.cc
                  reel.cc
index 751bf357efaf582c96db7886413b2ebebf9f2a72..f397b96b4a0c2d7735f474e27f9a4e00fc7b4ebf 100644 (file)
@@ -17,6 +17,8 @@
 
 */
 
+#include "picture_asset_writer.h"
+
 /* Check that recovery from a partially-written MXF works */
 BOOST_AUTO_TEST_CASE (recovery)
 {