From 2ea3a0d0e4066a166c0700bd1d53daa7f1c50dff Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 1 Nov 2020 23:51:19 +0100 Subject: Pass around JPEG2000 data as a shared_ptr and hence avoid a copy of 4MB of data for every JPEG2000 frame we decode. --- src/lib/j2k_encoder.cc | 10 +++++----- src/lib/j2k_image_proxy.cc | 47 +++++++++++++++++++--------------------------- src/lib/j2k_image_proxy.h | 8 ++++---- src/lib/player_video.cc | 2 +- src/lib/player_video.h | 2 +- src/lib/reel_writer.cc | 7 ++++--- src/lib/reel_writer.h | 4 ++-- src/lib/writer.cc | 5 +++-- src/lib/writer.h | 4 ++-- 9 files changed, 41 insertions(+), 48 deletions(-) (limited to 'src/lib') diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index 64cd38147..18bb27645 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -127,7 +127,7 @@ J2KEncoder::end () LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ()); try { _writer->write ( - (*i)->encode_locally(), + shared_ptr(new dcp::ArrayData((*i)->encode_locally())), (*i)->index(), (*i)->eyes() ); @@ -296,12 +296,12 @@ try lock.unlock (); - optional encoded; + shared_ptr encoded; /* We need to encode this input */ if (server) { try { - encoded = vf->encode_remotely (server.get ()); + encoded.reset(new dcp::ArrayData(vf->encode_remotely(server.get()))); if (remote_backoff > 0) { LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", server->host_name ()); @@ -324,7 +324,7 @@ try } else { try { LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf->index()); - encoded = vf->encode_locally (); + encoded.reset(new dcp::ArrayData(vf->encode_locally())); LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), vf->index()); } catch (std::exception& e) { /* This is very bad, so don't cope with it, just pass it on */ @@ -334,7 +334,7 @@ try } if (encoded) { - _writer->write (encoded.get(), vf->index (), vf->eyes ()); + _writer->write (encoded, vf->index(), vf->eyes()); frame_done (); } else { lock.lock (); diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 08ebc343c..064bbec7b 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -46,12 +46,12 @@ using std::make_pair; using boost::shared_ptr; using boost::optional; using boost::dynamic_pointer_cast; -using dcp::Data; +using dcp::ArrayData; using dcp::raw_convert; /** Construct a J2KImageProxy from a JPEG2000 file */ J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format) - : _data (path) + : _data (new dcp::ArrayData(path)) , _size (size) , _pixel_format (pixel_format) , _error (false) @@ -60,13 +60,14 @@ J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPi DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE); } + J2KImageProxy::J2KImageProxy ( shared_ptr frame, dcp::Size size, AVPixelFormat pixel_format, optional forced_reduction ) - : _data (frame->j2k_size ()) + : _data (frame) , _size (size) , _pixel_format (pixel_format) , _forced_reduction (forced_reduction) @@ -74,9 +75,9 @@ J2KImageProxy::J2KImageProxy ( { /* ::image assumes 16bpp */ DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE); - memcpy (_data.data().get(), frame->j2k_data(), _data.size ()); } + J2KImageProxy::J2KImageProxy ( shared_ptr frame, dcp::Size size, @@ -84,7 +85,8 @@ J2KImageProxy::J2KImageProxy ( AVPixelFormat pixel_format, optional forced_reduction ) - : _size (size) + : _data (eye ? frame->left() : frame->right()) + , _size (size) , _eye (eye) , _pixel_format (pixel_format) , _forced_reduction (forced_reduction) @@ -92,18 +94,9 @@ J2KImageProxy::J2KImageProxy ( { /* ::image assumes 16bpp */ DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE); - switch (eye) { - case dcp::EYE_LEFT: - _data = Data (frame->left_j2k_size ()); - memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ()); - break; - case dcp::EYE_RIGHT: - _data = Data (frame->right_j2k_size ()); - memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ()); - break; - } } + J2KImageProxy::J2KImageProxy (shared_ptr xml, shared_ptr socket) : _error (false) { @@ -111,13 +104,14 @@ J2KImageProxy::J2KImageProxy (shared_ptr xml, shared_ptr soc if (xml->optional_number_child ("Eye")) { _eye = static_cast (xml->number_child ("Eye")); } - _data = Data (xml->number_child ("Size")); + shared_ptr data(new ArrayData(xml->number_child("Size"))); /* This only matters when we are using J2KImageProxy for the preview, which will never use this constructor (which is only used for passing data to encode servers). So we can put anything in here. It's a bit of a hack. */ _pixel_format = AV_PIX_FMT_XYZ12LE; - socket->read (_data.data().get (), _data.size ()); + socket->read (data->data(), data->size()); + _data = data; } int @@ -144,7 +138,8 @@ J2KImageProxy::prepare (optional target_size) const } try { - shared_ptr decompressed = dcp::decompress_j2k (const_cast (_data.data().get()), _data.size (), reduce); + /* XXX: should check that potentially trashing _data here doesn't matter */ + shared_ptr decompressed = dcp::decompress_j2k (const_cast(_data->data()), _data->size(), reduce); _image.reset (new Image (_pixel_format, decompressed->size(), true)); int const shift = 16 - decompressed->precision (0); @@ -202,13 +197,13 @@ J2KImageProxy::add_metadata (xmlpp::Node* node) const if (_eye) { node->add_child("Eye")->add_child_text (raw_convert (static_cast (_eye.get ()))); } - node->add_child("Size")->add_child_text (raw_convert (_data.size ())); + node->add_child("Size")->add_child_text (raw_convert(_data->size())); } void J2KImageProxy::write_to_socket (shared_ptr socket) const { - socket->write (_data.data().get(), _data.size()); + socket->write (_data->data(), _data->size()); } bool @@ -219,15 +214,11 @@ J2KImageProxy::same (shared_ptr other) const return false; } - if (_data.size() != jp->_data.size()) { - return false; - } - - return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0; + return *_data == *jp->_data; } -J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format) - : _data (data) +J2KImageProxy::J2KImageProxy (ArrayData data, dcp::Size size, AVPixelFormat pixel_format) + : _data (new ArrayData(data)) , _size (size) , _pixel_format (pixel_format) { @@ -238,7 +229,7 @@ J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_for size_t J2KImageProxy::memory_used () const { - size_t m = _data.size(); + size_t m = _data->size(); if (_image) { /* 3 components, 16-bits per pixel */ m += 3 * 2 * _image->size().width * _image->size().height; diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index 71bcffb2c..3eccc213d 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -19,8 +19,8 @@ */ #include "image_proxy.h" +#include #include -#include #include namespace dcp { @@ -60,7 +60,7 @@ public: bool same (boost::shared_ptr) const; int prepare (boost::optional = boost::optional()) const; - dcp::Data j2k () const { + boost::shared_ptr j2k () const { return _data; } @@ -74,9 +74,9 @@ private: friend struct client_server_test_j2k; /* For tests */ - J2KImageProxy (dcp::Data data, dcp::Size size, AVPixelFormat pixel_format); + J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format); - dcp::Data _data; + boost::shared_ptr _data; dcp::Size _size; boost::optional _eye; mutable boost::shared_ptr _image; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index 10e798ed5..620245781 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -232,7 +232,7 @@ PlayerVideo::has_j2k () const return _crop == Crop () && _out_size == j2k->size() && !_text && !_fade && !_colour_conversion; } -Data +shared_ptr PlayerVideo::j2k () const { shared_ptr j2k = dynamic_pointer_cast (_in); diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 1a4a01d58..6043632c2 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -79,7 +79,7 @@ public: bool reset_metadata (boost::shared_ptr film, dcp::Size video_container_size, dcp::Size film_frame_size); bool has_j2k () const; - dcp::Data j2k () const; + boost::shared_ptr j2k () const; Eyes eyes () const { return _eyes; diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 097b9d84b..7ed79d818 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -67,6 +67,7 @@ using boost::dynamic_pointer_cast; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif +using dcp::ArrayData; using dcp::Data; using dcp::raw_convert; using namespace dcpomatic; @@ -289,14 +290,14 @@ ReelWriter::check_existing_picture_asset (boost::filesystem::path asset) } void -ReelWriter::write (optional encoded, Frame frame, Eyes eyes) +ReelWriter::write (shared_ptr encoded, Frame frame, Eyes eyes) { if (!_picture_asset_writer) { /* We're not writing any data */ return; } - dcp::FrameInfo fin = _picture_asset_writer->write (encoded->data().get (), encoded->size()); + dcp::FrameInfo fin = _picture_asset_writer->write (encoded->data(), encoded->size()); write_frame_info (frame, eyes, fin); _last_written[eyes] = encoded; } @@ -338,7 +339,7 @@ ReelWriter::repeat_write (Frame frame, Eyes eyes) } dcp::FrameInfo fin = _picture_asset_writer->write ( - _last_written[eyes]->data().get(), + _last_written[eyes]->data(), _last_written[eyes]->size() ); write_frame_info (frame, eyes, fin); diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index 17bfc7ba2..09c29adae 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -66,7 +66,7 @@ public: boost::optional content_summary ); - void write (boost::optional encoded, Frame frame, Eyes eyes); + void write (boost::shared_ptr encoded, Frame frame, Eyes eyes); void fake_write (int size); void repeat_write (Frame frame, Eyes eyes); void write (boost::shared_ptr audio); @@ -104,7 +104,7 @@ private: /** the first picture frame index that does not already exist in our MXF */ int _first_nonexistant_frame; /** the data of the last written frame, if there is one */ - boost::optional _last_written[EYES_COUNT]; + boost::shared_ptr _last_written[EYES_COUNT]; /** index of this reel within the DCP (starting from 0) */ int _reel_index; /** number of reels in the DCP */ diff --git a/src/lib/writer.cc b/src/lib/writer.cc index d3fdc5128..346cbb0c2 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -66,6 +66,7 @@ using boost::optional; using namespace boost::placeholders; #endif using dcp::Data; +using dcp::ArrayData; using namespace dcpomatic; Writer::Writer (shared_ptr film, weak_ptr j) @@ -130,7 +131,7 @@ Writer::~Writer () * @param eyes Eyes that this frame image is for. */ void -Writer::write (Data encoded, Frame frame, Eyes eyes) +Writer::write (shared_ptr encoded, Frame frame, Eyes eyes) { boost::mutex::scoped_lock lock (_state_mutex); @@ -426,7 +427,7 @@ try case QueueItem::FULL: LOG_DEBUG_ENCODE (N_("Writer FULL-writes %1 (%2)"), qi.frame, (int) qi.eyes); if (!qi.encoded) { - qi.encoded = Data (_film->j2c_path (qi.reel, qi.frame, qi.eyes, false)); + qi.encoded.reset (new ArrayData(_film->j2c_path(qi.reel, qi.frame, qi.eyes, false))); } reel.write (qi.encoded, qi.frame, qi.eyes); ++_full_written; diff --git a/src/lib/writer.h b/src/lib/writer.h index 71e04df96..459bc5a88 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -70,7 +70,7 @@ public: } type; /** encoded data for FULL */ - boost::optional encoded; + boost::shared_ptr encoded; /** size of data for FAKE */ int size; /** reel index */ @@ -105,7 +105,7 @@ public: bool can_fake_write (Frame) const; - void write (dcp::Data, Frame, Eyes); + void write (boost::shared_ptr, Frame, Eyes); void fake_write (Frame, Eyes); bool can_repeat (Frame) const; void repeat (Frame, Eyes); -- cgit v1.2.3