/* If you are using an installed libdcp, these #includes would need to be changed to
#include <libdcp/dcp.h>
#include <libdcp/cpl.h>
-#include <libdcp/picture_asset.h>
+#include <libdcp/mono_picture_asset.h>
... etc. ...
*/
#include "dcp.h"
#include "cpl.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "sound_asset.h"
#include "reel.h"
#include "cpl.h"
#include "parse/cpl.h"
#include "util.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
+#include "stereo_picture_asset.h"
#include "sound_asset.h"
#include "subtitle_asset.h"
#include "parse/asset_map.h"
--- /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 "mono_picture_asset.h"
+#include "mono_picture_asset_writer.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "exceptions.h"
+#include "mono_picture_frame.h"
+
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using boost::lexical_cast;
+using namespace libdcp;
+
+MonoPictureAsset::MonoPictureAsset (boost::filesystem::path directory, string mxf_name)
+ : PictureAsset (directory, mxf_name)
+{
+
+}
+
+void
+MonoPictureAsset::create (vector<boost::filesystem::path> const & files)
+{
+ create (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
+}
+
+void
+MonoPictureAsset::create (boost::function<boost::filesystem::path (int)> get_path)
+{
+ ASDCP::JP2K::CodestreamParser j2k_parser;
+ ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
+ if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (get_path(0).c_str(), frame_buffer))) {
+ boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path (0)));
+ }
+
+ ASDCP::JP2K::PictureDescriptor picture_desc;
+ j2k_parser.FillPictureDescriptor (picture_desc);
+ picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
+
+ ASDCP::WriterInfo writer_info;
+ fill_writer_info (&writer_info, _uuid, _interop, _metadata);
+
+ ASDCP::JP2K::MXFWriter mxf_writer;
+ if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for writing", path().string()));
+ }
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+
+ boost::filesystem::path const path = get_path (i);
+
+ if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (path.c_str(), frame_buffer))) {
+ boost::throw_exception (FileError ("could not open JPEG2000 file for reading", path));
+ }
+
+ if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0))) {
+ boost::throw_exception (MXFFileError ("error in writing video MXF", this->path().string()));
+ }
+
+ if (_progress) {
+ (*_progress) (0.5 * float (i) / _intrinsic_duration);
+ }
+ }
+
+ if (ASDCP_FAILURE (mxf_writer.Finalize())) {
+ boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string()));
+ }
+}
+
+void
+MonoPictureAsset::read ()
+{
+ ASDCP::JP2K::MXFReader reader;
+ if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string()));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ _size.width = desc.StoredWidth;
+ _size.height = desc.StoredHeight;
+ _edit_rate = desc.EditRate.Numerator;
+ assert (desc.EditRate.Denominator == 1);
+ _intrinsic_duration = desc.ContainerDuration;
+}
+
+boost::filesystem::path
+MonoPictureAsset::path_from_list (int f, vector<boost::filesystem::path> const & files) const
+{
+ return files[f];
+}
+
+shared_ptr<const MonoPictureFrame>
+MonoPictureAsset::get_frame (int n) const
+{
+ return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (path().string(), n, _decryption_context));
+}
+
+bool
+MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!PictureAsset::equals (other, opt, note)) {
+ return false;
+ }
+
+ shared_ptr<const MonoPictureAsset> other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
+ assert (other_picture);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ if (i >= other_picture->intrinsic_duration()) {
+ return false;
+ }
+
+ note (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_intrinsic_duration));
+ shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
+ shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->j2k_data(), frame_A->j2k_size(),
+ frame_B->j2k_data(), frame_B->j2k_size()
+ )) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+shared_ptr<PictureAssetWriter>
+MonoPictureAsset::start_write (bool overwrite)
+{
+ /* XXX: can't we use shared_ptr here? */
+ return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite));
+}
+
+string
+MonoPictureAsset::cpl_node_name () const
+{
+ return "MainPicture";
+}
+
+int
+MonoPictureAsset::edit_rate_factor () const
+{
+ return 1;
+}
--- /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.
+
+*/
+
+#ifndef LIBDCP_MONO_PICTURE_ASSET_H
+#define LIBDCP_MONO_PICTURE_ASSET_H
+
+#include "picture_asset.h"
+
+namespace libdcp {
+
+/** A 2D (monoscopic) picture asset */
+class MonoPictureAsset : public PictureAsset
+{
+public:
+ MonoPictureAsset (boost::filesystem::path directory, std::string mxf_name);
+
+ void read ();
+ void create (std::vector<boost::filesystem::path> const & files);
+ void create (boost::function<boost::filesystem::path (int)> get_path);
+
+ /** Start a progressive write to a MonoPictureAsset */
+ boost::shared_ptr<PictureAssetWriter> start_write (bool);
+
+ boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
+ bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
+
+private:
+ boost::filesystem::path path_from_list (int f, std::vector<boost::filesystem::path> const & files) const;
+ void construct (boost::function<boost::filesystem::path (int)>, bool, MXFMetadata const &);
+ std::string cpl_node_name () const;
+ int edit_rate_factor () const;
+};
+
+}
+
+#endif
--- /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 "mono_picture_asset_writer.h"
+#include "exceptions.h"
+#include "picture_asset.h"
+
+#include "picture_asset_writer_common.cc"
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace libdcp;
+
+struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+{
+ ASDCP::JP2K::MXFWriter mxf_writer;
+};
+
+/** @param a Asset to write to. `a' must not be deleted while
+ * this writer class still exists, or bad things will happen.
+ */
+MonoPictureAssetWriter::MonoPictureAssetWriter (PictureAsset* asset, bool overwrite)
+ : PictureAssetWriter (asset, overwrite)
+ , _state (new MonoPictureAssetWriter::ASDCPState)
+{
+ _state->encryption_context = asset->encryption_context ();
+}
+
+void
+MonoPictureAssetWriter::start (uint8_t* data, int size)
+{
+ libdcp::start (this, _state, _asset, data, size);
+}
+
+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, _state->encryption_context, 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)
+{
+ 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);
+}
+
--- /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 "picture_asset_writer.h"
+
+namespace libdcp {
+
+/** 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 .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
+ * throw an exception.
+ */
+class MonoPictureAssetWriter : public PictureAssetWriter
+{
+public:
+ FrameInfo write (uint8_t *, int);
+ void fake_write (int size);
+ void finalize ();
+
+private:
+ friend class MonoPictureAsset;
+
+ MonoPictureAssetWriter (PictureAsset *, bool);
+ 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;
+};
+
+}
--- /dev/null
+/*
+ Copyright (C) 2012 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 <openjpeg.h>
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "mono_picture_frame.h"
+#include "exceptions.h"
+#include "argb_frame.h"
+#include "lut.h"
+#include "util.h"
+#include "gamma_lut.h"
+#include "rgb_xyz.h"
+
+#define DCI_GAMMA 2.6
+
+using std::string;
+using boost::shared_ptr;
+using namespace libdcp;
+
+/** Make a picture frame from a 2D (monoscopic) asset.
+ * @param mxf_path Path to the asset's MXF file.
+ * @param n Frame within the asset, not taking EntryPoint into account.
+ */
+MonoPictureFrame::MonoPictureFrame (string mxf_path, int n, ASDCP::AESDecContext* c)
+{
+ ASDCP::JP2K::MXFReader reader;
+ if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) {
+ boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path));
+ }
+
+ /* 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 ("could not read video frame"));
+ }
+}
+
+MonoPictureFrame::~MonoPictureFrame ()
+{
+ delete _buffer;
+}
+
+uint8_t const *
+MonoPictureFrame::j2k_data () const
+{
+ return _buffer->RoData ();
+}
+
+int
+MonoPictureFrame::j2k_size () const
+{
+ return _buffer->Size ();
+}
+
+/** @param reduce a factor by which to reduce the resolution
+ * of the image, expressed as a power of two (pass 0 for no
+ * reduction).
+ *
+ * @return An ARGB representation of this frame. This is ARGB in the
+ * Cairo sense, so that each pixel takes up 4 bytes; the first byte
+ * is blue, second green, third red and fourth alpha (always 255).
+ *
+ */
+shared_ptr<ARGBFrame>
+MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const
+{
+ return xyz_to_rgb (
+ decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce),
+ GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)
+ );
+}
--- /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 <string>
+#include <stdint.h>
+#include <boost/shared_ptr.hpp>
+#include "types.h"
+
+namespace ASDCP {
+ namespace JP2K {
+ class FrameBuffer;
+ }
+ class AESDecContext;
+}
+
+namespace libdcp {
+
+class ARGBFrame;
+
+/** A single frame of a 2D (monoscopic) picture asset */
+class MonoPictureFrame
+{
+public:
+ MonoPictureFrame (std::string mxf_path, int n, ASDCP::AESDecContext *);
+ ~MonoPictureFrame ();
+
+ boost::shared_ptr<ARGBFrame> argb_frame (int reduce = 0, float srgb_gamma = 2.4) const;
+ uint8_t const * j2k_data () const;
+ int j2k_size () const;
+
+private:
+ ASDCP::JP2K::FrameBuffer* _buffer;
+};
+
+}
#include "picture_asset.h"
#include "util.h"
#include "exceptions.h"
-#include "picture_frame.h"
#include "xyz_frame.h"
#include "picture_asset_writer.h"
return true;
}
-MonoPictureAsset::MonoPictureAsset (boost::filesystem::path directory, string mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-MonoPictureAsset::create (vector<boost::filesystem::path> const & files)
-{
- create (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
-}
-
-void
-MonoPictureAsset::create (boost::function<boost::filesystem::path (int)> get_path)
-{
- ASDCP::JP2K::CodestreamParser j2k_parser;
- ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
- if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (get_path(0).c_str(), frame_buffer))) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path (0)));
- }
-
- ASDCP::JP2K::PictureDescriptor picture_desc;
- j2k_parser.FillPictureDescriptor (picture_desc);
- picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
-
- ASDCP::WriterInfo writer_info;
- fill_writer_info (&writer_info, _uuid, _interop, _metadata);
-
- ASDCP::JP2K::MXFWriter mxf_writer;
- if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) {
- boost::throw_exception (MXFFileError ("could not open MXF file for writing", path().string()));
- }
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
-
- boost::filesystem::path const path = get_path (i);
-
- if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (path.c_str(), frame_buffer))) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", path));
- }
-
- if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0))) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", this->path().string()));
- }
-
- if (_progress) {
- (*_progress) (0.5 * float (i) / _intrinsic_duration);
- }
- }
-
- if (ASDCP_FAILURE (mxf_writer.Finalize())) {
- boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string()));
- }
-}
-
-void
-MonoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFReader reader;
- if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string()));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
- _intrinsic_duration = desc.ContainerDuration;
-}
-
-boost::filesystem::path
-MonoPictureAsset::path_from_list (int f, vector<boost::filesystem::path> const & files) const
-{
- return files[f];
-}
-
-shared_ptr<const MonoPictureFrame>
-MonoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (path().string(), n, _decryption_context));
-}
-
-bool
-MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!PictureAsset::equals (other, opt, note)) {
- return false;
- }
-
- shared_ptr<const MonoPictureAsset> other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
- assert (other_picture);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- if (i >= other_picture->intrinsic_duration()) {
- return false;
- }
-
- note (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_intrinsic_duration));
- shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
- shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->j2k_data(), frame_A->j2k_size(),
- frame_B->j2k_data(), frame_B->j2k_size()
- )) {
- return false;
- }
- }
-
- return true;
-}
-
-bool
-StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!PictureAsset::equals (other, opt, note)) {
- return false;
- }
-
- shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
- assert (other_picture);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- shared_ptr<const StereoPictureFrame> frame_A = get_frame (i);
- shared_ptr<const StereoPictureFrame> frame_B = other_picture->get_frame (i);
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->left_j2k_data(), frame_A->left_j2k_size(),
- frame_B->left_j2k_data(), frame_B->left_j2k_size()
- )) {
- return false;
- }
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->right_j2k_data(), frame_A->right_j2k_size(),
- frame_B->right_j2k_data(), frame_B->right_j2k_size()
- )) {
- return false;
- }
- }
-
- return true;
-}
-
bool
PictureAsset::frame_buffer_equals (
int frame, EqualityOptions opt, boost::function<void (NoteType, string)> note,
note (NOTE, "mean difference " + lexical_cast<string> (mean) + ", deviation " + lexical_cast<string> (std_dev));
if (mean > opt.max_mean_pixel_error) {
- note (ERROR, "mean " + lexical_cast<string>(mean) + " out of range " + lexical_cast<string>(opt.max_mean_pixel_error) + " in frame " + lexical_cast<string>(frame));
+ note (
+ ERROR,
+ "mean " + lexical_cast<string>(mean) +
+ " out of range " + lexical_cast<string>(opt.max_mean_pixel_error) +
+ " in frame " + lexical_cast<string>(frame)
+ );
+
return false;
}
if (std_dev > opt.max_std_dev_pixel_error) {
- note (ERROR, "standard deviation " + lexical_cast<string>(std_dev) + " out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) + " in frame " + lexical_cast<string>(frame));
+ note (
+ ERROR,
+ "standard deviation " + lexical_cast<string>(std_dev) +
+ " out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) +
+ " in frame " + lexical_cast<string>(frame)
+ );
+
return false;
}
return true;
}
-
-StereoPictureAsset::StereoPictureAsset (boost::filesystem::path directory, string mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-StereoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFSReader reader;
- if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string()));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
-}
-
-shared_ptr<const StereoPictureFrame>
-StereoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n));
-}
-
-shared_ptr<PictureAssetWriter>
-MonoPictureAsset::start_write (bool overwrite)
-{
- /* XXX: can't we use shared_ptr here? */
- return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite));
-}
-
string
PictureAsset::key_type () const
{
return "MDIK";
}
-shared_ptr<PictureAssetWriter>
-StereoPictureAsset::start_write (bool overwrite)
-{
- return shared_ptr<StereoPictureAssetWriter> (new StereoPictureAssetWriter (this, overwrite));
-}
-
-string
-MonoPictureAsset::cpl_node_name () const
-{
- return "MainPicture";
-}
-
-int
-MonoPictureAsset::edit_rate_factor () const
-{
- return 1;
-}
-
-string
-StereoPictureAsset::cpl_node_name () const
-{
- return "msp-cpl:MainStereoscopicPicture";
-}
-pair<string, string>
-StereoPictureAsset::cpl_node_attribute (bool interop) const
-{
- if (interop) {
- return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
- } else {
- return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
- }
-
- return make_pair ("", "");
-}
-
-int
-StereoPictureAsset::edit_rate_factor () const
-{
- return 2;
-}
{
public:
/** Construct a PictureAsset.
- * This class will not write anything to disk in this constructor, but subclasses may.
*
* @param directory Directory where MXF file is.
* @param mxf_name Name of MXF file.
std::string key_type () const;
virtual int edit_rate_factor () const = 0;
};
-
-/** A 2D (monoscopic) picture asset */
-class MonoPictureAsset : public PictureAsset
-{
-public:
- MonoPictureAsset (boost::filesystem::path directory, std::string mxf_name);
-
- void read ();
- void create (std::vector<boost::filesystem::path> const & files);
- void create (boost::function<boost::filesystem::path (int)> get_path);
-
- /** Start a progressive write to a MonoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
-
- boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
-private:
- boost::filesystem::path path_from_list (int f, std::vector<boost::filesystem::path> const & files) const;
- void construct (boost::function<boost::filesystem::path (int)>, bool, MXFMetadata const &);
- std::string cpl_node_name () const;
- int edit_rate_factor () const;
-};
-
-/** A 3D (stereoscopic) picture asset */
-class StereoPictureAsset : public PictureAsset
-{
-public:
- StereoPictureAsset (boost::filesystem::path directory, std::string mxf_name);
-
- void read ();
-
- /** Start a progressive write to a StereoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
-
- 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;
-
-private:
- std::string cpl_node_name () const;
- std::pair<std::string, std::string> cpl_node_attribute (bool) const;
- int edit_rate_factor () const;
-};
}
{
}
-
-struct ASDCPStateBase
-{
- ASDCPStateBase ()
- : frame_buffer (4 * Kumu::Megabyte)
- {}
-
- ASDCP::JP2K::CodestreamParser j2k_parser;
- ASDCP::JP2K::FrameBuffer frame_buffer;
- ASDCP::WriterInfo writer_info;
- ASDCP::JP2K::PictureDescriptor picture_descriptor;
- ASDCP::AESEncContext* encryption_context;
-};
-
-struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
-{
- ASDCP::JP2K::MXFWriter mxf_writer;
-};
-
-struct StereoPictureAssetWriter::ASDCPState : public ASDCPStateBase
-{
- ASDCP::JP2K::MXFSWriter mxf_writer;
-};
-
-/** @param a Asset to write to. `a' must not be deleted while
- * this writer class still exists, or bad things will happen.
- */
-MonoPictureAssetWriter::MonoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new MonoPictureAssetWriter::ASDCPState)
-{
- _state->encryption_context = asset->encryption_context ();
-}
-
-StereoPictureAssetWriter::StereoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new StereoPictureAssetWriter::ASDCPState)
- , _next_eye (EYE_LEFT)
-{
- _state->encryption_context = asset->encryption_context ();
-}
-
-template <class P, class Q>
-void libdcp::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->_asset->interop(), writer->_asset->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)
-{
- libdcp::start (this, _state, _asset, data, size);
-}
-
-void
-StereoPictureAssetWriter::start (uint8_t* data, int size)
-{
- libdcp::start (this, _state, _asset, data, size);
-}
-
-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, _state->encryption_context, 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);
-}
-
-/** Write a frame for one eye. Frames must be written left, then right, then left etc.
- * @param data JPEG2000 data.
- * @param size Size of data.
- */
-FrameInfo
-StereoPictureAssetWriter::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,
- _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT,
- _state->encryption_context,
- 0,
- &hash)
- )) {
-
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
- }
-
- _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
-
- return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
-}
-
-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()));
- }
-
- _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
- ++_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 / 2);
- _asset->set_duration (_frames_written / 2);
-}
bool _overwrite;
};
-/** 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 .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
- * throw an exception.
- */
-class MonoPictureAssetWriter : public PictureAssetWriter
-{
-public:
- FrameInfo write (uint8_t *, int);
- void fake_write (int size);
- void finalize ();
-
-private:
- friend class MonoPictureAsset;
-
- MonoPictureAssetWriter (PictureAsset *, bool);
- 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;
-};
-
-/** A helper class for writing to StereoPictureAssets 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 StereoPictureAsset::start_write().
- *
- * Frames can be written to the MonoPictureAsset 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
- * throw an exception.
- */
-class StereoPictureAssetWriter : public PictureAssetWriter
-{
-public:
- FrameInfo write (uint8_t *, int);
- void fake_write (int size);
- void finalize ();
-
-private:
- friend class StereoPictureAsset;
-
- StereoPictureAssetWriter (PictureAsset *, bool);
- 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;
-
- libdcp::Eye _next_eye;
-};
-
}
--- /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.
+
+*/
+
+using boost::shared_ptr;
+
+struct ASDCPStateBase
+{
+ ASDCPStateBase ()
+ : frame_buffer (4 * Kumu::Megabyte)
+ {}
+
+ ASDCP::JP2K::CodestreamParser j2k_parser;
+ ASDCP::JP2K::FrameBuffer frame_buffer;
+ ASDCP::WriterInfo writer_info;
+ ASDCP::JP2K::PictureDescriptor picture_descriptor;
+ ASDCP::AESEncContext* encryption_context;
+};
+
+template <class P, class Q>
+void libdcp::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->_asset->interop(), writer->_asset->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;
+}
+++ /dev/null
-/*
- Copyright (C) 2012 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 <openjpeg.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "picture_frame.h"
-#include "exceptions.h"
-#include "argb_frame.h"
-#include "lut.h"
-#include "util.h"
-#include "gamma_lut.h"
-#include "rgb_xyz.h"
-
-#define DCI_GAMMA 2.6
-
-using std::string;
-using boost::shared_ptr;
-using namespace libdcp;
-
-/** Make a picture frame from a 2D (monoscopic) asset.
- * @param mxf_path Path to the asset's MXF file.
- * @param n Frame within the asset, not taking EntryPoint into account.
- */
-MonoPictureFrame::MonoPictureFrame (string mxf_path, int n, ASDCP::AESDecContext* c)
-{
- ASDCP::JP2K::MXFReader reader;
- if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) {
- boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path));
- }
-
- /* 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 ("could not read video frame"));
- }
-}
-
-MonoPictureFrame::~MonoPictureFrame ()
-{
- delete _buffer;
-}
-
-uint8_t const *
-MonoPictureFrame::j2k_data () const
-{
- return _buffer->RoData ();
-}
-
-int
-MonoPictureFrame::j2k_size () const
-{
- return _buffer->Size ();
-}
-
-/** @param reduce a factor by which to reduce the resolution
- * of the image, expressed as a power of two (pass 0 for no
- * reduction).
- *
- * @return An ARGB representation of this frame. This is ARGB in the
- * Cairo sense, so that each pixel takes up 4 bytes; the first byte
- * is blue, second green, third red and fourth alpha (always 255).
- *
- */
-shared_ptr<ARGBFrame>
-MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const
-{
- return xyz_to_rgb (
- decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce),
- GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)
- );
-}
-
-/** Make a picture frame from a 3D (stereoscopic) asset.
- * @param mxf_path Path to the asset's MXF file.
- * @param n Frame within the asset, not taking EntryPoint into account.
- */
-StereoPictureFrame::StereoPictureFrame (string mxf_path, int n)
-{
- ASDCP::JP2K::MXFSReader reader;
- if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) {
- boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path));
- }
-
- /* 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 ("could not read video frame"));
- }
-}
-
-StereoPictureFrame::~StereoPictureFrame ()
-{
- delete _buffer;
-}
-
-/** @param reduce a factor by which to reduce the resolution
- * of the image, expressed as a power of two (pass 0 for no
- * reduction).
- *
- * @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
- *
- * @return An ARGB representation of one of the eyes (left or right)
- * of this frame. This is ARGB in the Cairo sense, so that each
- * pixel takes up 4 bytes; the first byte is blue, second green,
- * third red and fourth alpha (always 255).
- *
- */
-shared_ptr<ARGBFrame>
-StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const
-{
- shared_ptr<XYZFrame> xyz_frame;
- switch (eye) {
- case LEFT:
- xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Left.RoData()), _buffer->Left.Size(), reduce);
- break;
- case RIGHT:
- xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Right.RoData()), _buffer->Right.Size(), reduce);
- break;
- }
-
- return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma));
-}
-
-uint8_t const *
-StereoPictureFrame::left_j2k_data () const
-{
- return _buffer->Left.RoData ();
-}
-
-int
-StereoPictureFrame::left_j2k_size () const
-{
- return _buffer->Left.Size ();
-}
-
-uint8_t const *
-StereoPictureFrame::right_j2k_data () const
-{
- return _buffer->Right.RoData ();
-}
-
-int
-StereoPictureFrame::right_j2k_size () const
-{
- return _buffer->Right.Size ();
-}
+++ /dev/null
-/*
- Copyright (C) 2012 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 <string>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include "types.h"
-
-namespace ASDCP {
- namespace JP2K {
- class FrameBuffer;
- class SFrameBuffer;
- }
- class AESDecContext;
-}
-
-namespace libdcp {
-
-class ARGBFrame;
-
-/** A single frame of a 2D (monoscopic) picture asset */
-class MonoPictureFrame
-{
-public:
- MonoPictureFrame (std::string mxf_path, int n, ASDCP::AESDecContext *);
- ~MonoPictureFrame ();
-
- boost::shared_ptr<ARGBFrame> argb_frame (int reduce = 0, float srgb_gamma = 2.4) const;
- uint8_t const * j2k_data () const;
- int j2k_size () const;
-
-private:
- ASDCP::JP2K::FrameBuffer* _buffer;
-};
-
-/** A single frame of a 3D (stereoscopic) picture asset */
-class StereoPictureFrame
-{
-public:
- StereoPictureFrame (std::string mxf_path, int n);
- ~StereoPictureFrame ();
-
- boost::shared_ptr<ARGBFrame> argb_frame (Eye eye, int reduce = 0, float srgb_gamma = 2.4) const;
- uint8_t const * left_j2k_data () const;
- int left_j2k_size () const;
- uint8_t const * right_j2k_data () const;
- int right_j2k_size () const;
-
-private:
- ASDCP::JP2K::SFrameBuffer* _buffer;
-};
-
-}
--- /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 "stereo_picture_asset.h"
+#include "stereo_picture_frame.h"
+#include "exceptions.h"
+#include "stereo_picture_asset_writer.h"
+
+using std::string;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using namespace libdcp;
+
+bool
+StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!PictureAsset::equals (other, opt, note)) {
+ return false;
+ }
+
+ shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
+ assert (other_picture);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ shared_ptr<const StereoPictureFrame> frame_A = get_frame (i);
+ shared_ptr<const StereoPictureFrame> frame_B = other_picture->get_frame (i);
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->left_j2k_data(), frame_A->left_j2k_size(),
+ frame_B->left_j2k_data(), frame_B->left_j2k_size()
+ )) {
+ return false;
+ }
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->right_j2k_data(), frame_A->right_j2k_size(),
+ frame_B->right_j2k_data(), frame_B->right_j2k_size()
+ )) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+StereoPictureAsset::StereoPictureAsset (boost::filesystem::path directory, string mxf_name)
+ : PictureAsset (directory, mxf_name)
+{
+
+}
+
+void
+StereoPictureAsset::read ()
+{
+ ASDCP::JP2K::MXFSReader reader;
+ if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string()));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ _size.width = desc.StoredWidth;
+ _size.height = desc.StoredHeight;
+}
+
+shared_ptr<const StereoPictureFrame>
+StereoPictureAsset::get_frame (int n) const
+{
+ return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n));
+}
+
+shared_ptr<PictureAssetWriter>
+StereoPictureAsset::start_write (bool overwrite)
+{
+ return shared_ptr<StereoPictureAssetWriter> (new StereoPictureAssetWriter (this, overwrite));
+}
+
+string
+StereoPictureAsset::cpl_node_name () const
+{
+ return "msp-cpl:MainStereoscopicPicture";
+}
+
+pair<string, string>
+StereoPictureAsset::cpl_node_attribute (bool interop) const
+{
+ if (interop) {
+ return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
+ } else {
+ return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
+ }
+
+ return make_pair ("", "");
+}
+
+int
+StereoPictureAsset::edit_rate_factor () const
+{
+ return 2;
+}
--- /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 "picture_asset.h"
+
+namespace libdcp {
+
+/** A 3D (stereoscopic) picture asset */
+class StereoPictureAsset : public PictureAsset
+{
+public:
+ StereoPictureAsset (boost::filesystem::path directory, std::string mxf_name);
+
+ void read ();
+
+ /** Start a progressive write to a StereoPictureAsset */
+ boost::shared_ptr<PictureAssetWriter> start_write (bool);
+
+ 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;
+
+private:
+ std::string cpl_node_name () const;
+ std::pair<std::string, std::string> cpl_node_attribute (bool) const;
+ int edit_rate_factor () 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 "stereo_picture_asset_writer.h"
+#include "exceptions.h"
+#include "picture_asset.h"
+
+#include "picture_asset_writer_common.cc"
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace libdcp;
+
+struct StereoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+{
+ ASDCP::JP2K::MXFSWriter mxf_writer;
+};
+
+StereoPictureAssetWriter::StereoPictureAssetWriter (PictureAsset* asset, bool overwrite)
+ : PictureAssetWriter (asset, overwrite)
+ , _state (new StereoPictureAssetWriter::ASDCPState)
+ , _next_eye (EYE_LEFT)
+{
+ _state->encryption_context = asset->encryption_context ();
+}
+
+void
+StereoPictureAssetWriter::start (uint8_t* data, int size)
+{
+ libdcp::start (this, _state, _asset, data, size);
+}
+
+/** Write a frame for one eye. Frames must be written left, then right, then left etc.
+ * @param data JPEG2000 data.
+ * @param size Size of data.
+ */
+FrameInfo
+StereoPictureAssetWriter::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,
+ _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT,
+ _state->encryption_context,
+ 0,
+ &hash)
+ )) {
+
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string()));
+ }
+
+ _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
+
+ return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
+}
+
+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()));
+ }
+
+ _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
+ ++_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 / 2);
+ _asset->set_duration (_frames_written / 2);
+}
--- /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 "picture_asset_writer.h"
+
+namespace libdcp {
+
+/** A helper class for writing to StereoPictureAssets 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 StereoPictureAsset::start_write().
+ *
+ * Frames can be written to the MonoPictureAsset 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
+ * throw an exception.
+ */
+class StereoPictureAssetWriter : public PictureAssetWriter
+{
+public:
+ FrameInfo write (uint8_t *, int);
+ void fake_write (int size);
+ void finalize ();
+
+private:
+ friend class StereoPictureAsset;
+
+ StereoPictureAssetWriter (PictureAsset *, bool);
+ 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;
+
+ libdcp::Eye _next_eye;
+};
+
+}
--- /dev/null
+/*
+ Copyright (C) 2012 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 <openjpeg.h>
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "stereo_picture_frame.h"
+#include "exceptions.h"
+#include "argb_frame.h"
+#include "lut.h"
+#include "util.h"
+#include "gamma_lut.h"
+#include "rgb_xyz.h"
+
+#define DCI_GAMMA 2.6
+
+using std::string;
+using boost::shared_ptr;
+using namespace libdcp;
+
+/** Make a picture frame from a 3D (stereoscopic) asset.
+ * @param mxf_path Path to the asset's MXF file.
+ * @param n Frame within the asset, not taking EntryPoint into account.
+ */
+StereoPictureFrame::StereoPictureFrame (string mxf_path, int n)
+{
+ ASDCP::JP2K::MXFSReader reader;
+ if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) {
+ boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path));
+ }
+
+ /* 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 ("could not read video frame"));
+ }
+}
+
+StereoPictureFrame::~StereoPictureFrame ()
+{
+ delete _buffer;
+}
+
+/** @param reduce a factor by which to reduce the resolution
+ * of the image, expressed as a power of two (pass 0 for no
+ * reduction).
+ *
+ * @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
+ *
+ * @return An ARGB representation of one of the eyes (left or right)
+ * of this frame. This is ARGB in the Cairo sense, so that each
+ * pixel takes up 4 bytes; the first byte is blue, second green,
+ * third red and fourth alpha (always 255).
+ *
+ */
+shared_ptr<ARGBFrame>
+StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const
+{
+ shared_ptr<XYZFrame> xyz_frame;
+ switch (eye) {
+ case LEFT:
+ xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Left.RoData()), _buffer->Left.Size(), reduce);
+ break;
+ case RIGHT:
+ xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Right.RoData()), _buffer->Right.Size(), reduce);
+ break;
+ }
+
+ return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma));
+}
+
+uint8_t const *
+StereoPictureFrame::left_j2k_data () const
+{
+ return _buffer->Left.RoData ();
+}
+
+int
+StereoPictureFrame::left_j2k_size () const
+{
+ return _buffer->Left.Size ();
+}
+
+uint8_t const *
+StereoPictureFrame::right_j2k_data () const
+{
+ return _buffer->Right.RoData ();
+}
+
+int
+StereoPictureFrame::right_j2k_size () const
+{
+ return _buffer->Right.Size ();
+}
--- /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 <string>
+#include <stdint.h>
+#include <boost/shared_ptr.hpp>
+#include "types.h"
+
+namespace ASDCP {
+ namespace JP2K {
+ class SFrameBuffer;
+ }
+ class AESDecContext;
+}
+
+namespace libdcp {
+
+class ARGBFrame;
+
+/** A single frame of a 3D (stereoscopic) picture asset */
+class StereoPictureFrame
+{
+public:
+ StereoPictureFrame (std::string mxf_path, int n);
+ ~StereoPictureFrame ();
+
+ boost::shared_ptr<ARGBFrame> argb_frame (Eye eye, int reduce = 0, float srgb_gamma = 2.4) const;
+ uint8_t const * left_j2k_data () const;
+ int left_j2k_size () const;
+ uint8_t const * right_j2k_data () const;
+ int right_j2k_size () const;
+
+private:
+ ASDCP::JP2K::SFrameBuffer* _buffer;
+};
+
+}
kdm.cc
key.cc
metadata.cc
+ mono_picture_asset.cc
+ mono_picture_asset_writer.cc
+ mono_picture_frame.cc
mxf_asset.cc
picture_asset.cc
picture_asset_writer.cc
- picture_frame.cc
rec709_linearised_gamma_lut.cc
reel.cc
rgb_xyz.cc
sound_asset.cc
sound_frame.cc
srgb_linearised_gamma_lut.cc
+ stereo_picture_asset.cc
+ stereo_picture_asset_writer.cc
+ stereo_picture_frame.cc
subtitle_asset.cc
types.cc
util.cc
lut.h
lut_cache.h
metadata.h
+ mono_picture_frame.h
mxf_asset.h
picture_asset.h
picture_asset_writer.h
- picture_frame.h
rgb_xyz.h
rec709_linearised_gamma_lut.h
reel.h
sound_asset.h
sound_frame.h
srgb_linearised_gamma_lut.h
+ stereo_picture_frame.h
subtitle_asset.h
types.h
util.h
#include "dcp.h"
#include "metadata.h"
#include "cpl.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "sound_asset.h"
#include "reel.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include "kdm.h"
#include "dcp.h"
-#include "picture_frame.h"
+#include "mono_picture_frame.h"
#include "cpl.h"
#include "argb_frame.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "reel.h"
#include "test.h"
#include "dcp.h"
#include "signer.h"
#include "cpl.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "sound_asset.h"
#include "reel.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include "dcp.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "sound_asset.h"
#include "util.h"
#include "exceptions.h"
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
-#include "picture_asset_writer.h"
-#include "picture_asset.h"
+#include "mono_picture_asset_writer.h"
+#include "mono_picture_asset.h"
#include "KM_util.h"
using std::string;
#include "certificates.h"
#include "kdm.h"
#include "signer.h"
-#include "picture_asset.h"
+#include "mono_picture_asset.h"
#include "sound_asset.h"
#include "reel.h"
#include "test.h"
#include "cpl.h"
-#include "picture_frame.h"
+#include "mono_picture_frame.h"
#include "argb_frame.h"
#include "signer_chain.h"