#include "exceptions.h"
#include "picture_frame.h"
#include "xyz_frame.h"
+#include "picture_asset_writer.h"
using std::string;
using std::ostream;
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";
}
{
class MonoPictureFrame;
-class StereoPictureFrame;
+class StereoPictureFrame;
+class MonoPictureAssetWriter;
+class StereoPictureAssetWriter;
/** @brief An asset made up of JPEG2000 files */
class PictureAsset : public MXFAsset
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
{
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;
};
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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;
+};
+
+}
metadata.cc
mxf_asset.cc
picture_asset.cc
+ picture_asset_writer.cc
picture_frame.cc
rec709_linearised_gamma_lut.cc
reel.cc
*/
+#include "picture_asset_writer.h"
+
/* Check that recovery from a partially-written MXF works */
BOOST_AUTO_TEST_CASE (recovery)
{