diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cpl.cc | 3 | ||||
| -rw-r--r-- | src/mono_picture_asset.cc | 169 | ||||
| -rw-r--r-- | src/mono_picture_asset.h | 52 | ||||
| -rw-r--r-- | src/mono_picture_asset_writer.cc | 105 | ||||
| -rw-r--r-- | src/mono_picture_asset_writer.h | 60 | ||||
| -rw-r--r-- | src/mono_picture_frame.cc | 89 | ||||
| -rw-r--r-- | src/mono_picture_frame.h | 51 | ||||
| -rw-r--r-- | src/picture_asset.cc | 246 | ||||
| -rw-r--r-- | src/picture_asset.h | 44 | ||||
| -rw-r--r-- | src/picture_asset_writer.cc | 195 | ||||
| -rw-r--r-- | src/picture_asset_writer.h | 64 | ||||
| -rw-r--r-- | src/picture_asset_writer_common.cc | 59 | ||||
| -rw-r--r-- | src/stereo_picture_asset.cc | 124 | ||||
| -rw-r--r-- | src/stereo_picture_asset.h | 44 | ||||
| -rw-r--r-- | src/stereo_picture_asset_writer.cc | 116 | ||||
| -rw-r--r-- | src/stereo_picture_asset_writer.h | 62 | ||||
| -rw-r--r-- | src/stereo_picture_frame.cc (renamed from src/picture_frame.cc) | 56 | ||||
| -rw-r--r-- | src/stereo_picture_frame.h (renamed from src/picture_frame.h) | 18 | ||||
| -rw-r--r-- | src/wscript | 10 |
19 files changed, 957 insertions, 610 deletions
@@ -22,7 +22,8 @@ #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" diff --git a/src/mono_picture_asset.cc b/src/mono_picture_asset.cc new file mode 100644 index 00000000..7830d829 --- /dev/null +++ b/src/mono_picture_asset.cc @@ -0,0 +1,169 @@ +/* + 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; +} diff --git a/src/mono_picture_asset.h b/src/mono_picture_asset.h new file mode 100644 index 00000000..6ade93bd --- /dev/null +++ b/src/mono_picture_asset.h @@ -0,0 +1,52 @@ +/* + 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 diff --git a/src/mono_picture_asset_writer.cc b/src/mono_picture_asset_writer.cc new file mode 100644 index 00000000..1f384c28 --- /dev/null +++ b/src/mono_picture_asset_writer.cc @@ -0,0 +1,105 @@ +/* + 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); +} + diff --git a/src/mono_picture_asset_writer.h b/src/mono_picture_asset_writer.h new file mode 100644 index 00000000..e3922623 --- /dev/null +++ b/src/mono_picture_asset_writer.h @@ -0,0 +1,60 @@ +/* + 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; +}; + +} diff --git a/src/mono_picture_frame.cc b/src/mono_picture_frame.cc new file mode 100644 index 00000000..474b0715 --- /dev/null +++ b/src/mono_picture_frame.cc @@ -0,0 +1,89 @@ +/* + 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) + ); +} diff --git a/src/mono_picture_frame.h b/src/mono_picture_frame.h new file mode 100644 index 00000000..83b80c5c --- /dev/null +++ b/src/mono_picture_frame.h @@ -0,0 +1,51 @@ +/* + 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; +}; + +} diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 97fce2ab..12032328 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -35,7 +35,6 @@ #include "picture_asset.h" #include "util.h" #include "exceptions.h" -#include "picture_frame.h" #include "xyz_frame.h" #include "picture_asset_writer.h" @@ -144,158 +143,6 @@ PictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost: 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, @@ -350,100 +197,35 @@ PictureAsset::frame_buffer_equals ( 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; -} diff --git a/src/picture_asset.h b/src/picture_asset.h index d1b097fa..53231418 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -41,7 +41,6 @@ class PictureAsset : public MXFAsset { 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. @@ -84,49 +83,6 @@ private: 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; -}; } diff --git a/src/picture_asset_writer.cc b/src/picture_asset_writer.cc index ca5a3e96..67883e31 100644 --- a/src/picture_asset_writer.cc +++ b/src/picture_asset_writer.cc @@ -61,198 +61,3 @@ PictureAssetWriter::PictureAssetWriter (PictureAsset* asset, bool overwrite) { } - -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); -} diff --git a/src/picture_asset_writer.h b/src/picture_asset_writer.h index fd4f81ee..bc2f65e5 100644 --- a/src/picture_asset_writer.h +++ b/src/picture_asset_writer.h @@ -73,68 +73,4 @@ protected: 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; -}; - } diff --git a/src/picture_asset_writer_common.cc b/src/picture_asset_writer_common.cc new file mode 100644 index 00000000..94999131 --- /dev/null +++ b/src/picture_asset_writer_common.cc @@ -0,0 +1,59 @@ +/* + 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; +} diff --git a/src/stereo_picture_asset.cc b/src/stereo_picture_asset.cc new file mode 100644 index 00000000..433659f4 --- /dev/null +++ b/src/stereo_picture_asset.cc @@ -0,0 +1,124 @@ +/* + 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; +} diff --git a/src/stereo_picture_asset.h b/src/stereo_picture_asset.h new file mode 100644 index 00000000..c9019610 --- /dev/null +++ b/src/stereo_picture_asset.h @@ -0,0 +1,44 @@ +/* + 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; +}; + +} diff --git a/src/stereo_picture_asset_writer.cc b/src/stereo_picture_asset_writer.cc new file mode 100644 index 00000000..fc7290a8 --- /dev/null +++ b/src/stereo_picture_asset_writer.cc @@ -0,0 +1,116 @@ +/* + 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); +} diff --git a/src/stereo_picture_asset_writer.h b/src/stereo_picture_asset_writer.h new file mode 100644 index 00000000..771524c4 --- /dev/null +++ b/src/stereo_picture_asset_writer.h @@ -0,0 +1,62 @@ +/* + 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; +}; + +} diff --git a/src/picture_frame.cc b/src/stereo_picture_frame.cc index 07a2b074..279fe7a0 100644 --- a/src/picture_frame.cc +++ b/src/stereo_picture_frame.cc @@ -20,7 +20,7 @@ #include <openjpeg.h> #include "AS_DCP.h" #include "KM_fileio.h" -#include "picture_frame.h" +#include "stereo_picture_frame.h" #include "exceptions.h" #include "argb_frame.h" #include "lut.h" @@ -34,60 +34,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. diff --git a/src/picture_frame.h b/src/stereo_picture_frame.h index 1c17e50b..b72eabc9 100644 --- a/src/picture_frame.h +++ b/src/stereo_picture_frame.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + 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 @@ -24,7 +24,6 @@ namespace ASDCP { namespace JP2K { - class FrameBuffer; class SFrameBuffer; } class AESDecContext; @@ -34,21 +33,6 @@ 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 { diff --git a/src/wscript b/src/wscript index 030cde3b..d7e118c7 100644 --- a/src/wscript +++ b/src/wscript @@ -24,10 +24,12 @@ def build(bld): 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 @@ -36,6 +38,9 @@ def build(bld): 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 @@ -62,10 +67,10 @@ def build(bld): 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 @@ -75,6 +80,7 @@ def build(bld): sound_asset.h sound_frame.h srgb_linearised_gamma_lut.h + stereo_picture_frame.h subtitle_asset.h types.h util.h |
