diff options
| author | Carl Hetherington <cth@carlh.net> | 2017-07-26 15:47:52 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2017-07-26 15:47:52 +0100 |
| commit | 3e230d3785f19bc707fd7ea2b1f55321b93f536f (patch) | |
| tree | 2773a105d2cf218d9c038418e388ff50f9b46236 /src/lib | |
| parent | b395478cbb0706de2b6afa9a34fb33e49c61ee67 (diff) | |
Multi-threaded decode of DCP when previewing.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/butler.cc | 23 | ||||
| -rw-r--r-- | src/lib/butler.h | 6 | ||||
| -rw-r--r-- | src/lib/image_proxy.h | 4 | ||||
| -rw-r--r-- | src/lib/j2k_image_proxy.cc | 50 | ||||
| -rw-r--r-- | src/lib/j2k_image_proxy.h | 5 | ||||
| -rw-r--r-- | src/lib/player_video.cc | 6 | ||||
| -rw-r--r-- | src/lib/player_video.h | 1 |
7 files changed, 74 insertions, 21 deletions
diff --git a/src/lib/butler.cc b/src/lib/butler.cc index 771c4e633..053d7c3bc 100644 --- a/src/lib/butler.cc +++ b/src/lib/butler.cc @@ -48,6 +48,7 @@ using boost::optional; Butler::Butler (weak_ptr<const Film> film, shared_ptr<Player> player, AudioMapping audio_mapping, int audio_channels) : _film (film) , _player (player) + , _prepare_work (new boost::asio::io_service::work (_prepare_service)) , _pending_seek_accurate (false) , _finished (false) , _died (false) @@ -60,6 +61,13 @@ Butler::Butler (weak_ptr<const Film> film, shared_ptr<Player> player, AudioMappi _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1)); _player_changed_connection = _player->Changed.connect (bind (&Butler::player_changed, this)); _thread = new boost::thread (bind (&Butler::thread, this)); + + /* Create some threads to do work on the PlayerVideos we are creating; at present this is used to + multi-thread JPEG2000 decoding. + */ + for (int i = 0; i < boost::thread::hardware_concurrency(); ++i) { + _prepare_pool.create_thread (bind (&boost::asio::io_service::run, &_prepare_service)); + } } Butler::~Butler () @@ -69,6 +77,10 @@ Butler::~Butler () _stop_thread = true; } + _prepare_work.reset (); + _prepare_pool.join_all (); + _prepare_service.stop (); + _thread->interrupt (); try { _thread->join (); @@ -181,6 +193,16 @@ Butler::seek (DCPTime position, bool accurate) } void +Butler::prepare (weak_ptr<PlayerVideo> weak_video) const +{ + shared_ptr<PlayerVideo> video = weak_video.lock (); + /* If the weak_ptr cannot be locked the video obviously no longer requires any work */ + if (video) { + video->prepare (); + } +} + +void Butler::video (shared_ptr<PlayerVideo> video, DCPTime time) { { @@ -191,6 +213,7 @@ Butler::video (shared_ptr<PlayerVideo> video, DCPTime time) } } + _prepare_service.post (bind (&Butler::prepare, this, weak_ptr<PlayerVideo>(video))); _video.put (video, time); } diff --git a/src/lib/butler.h b/src/lib/butler.h index 9949ab79b..1e8947f9d 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -27,6 +27,7 @@ #include <boost/thread.hpp> #include <boost/thread/condition.hpp> #include <boost/signals2.hpp> +#include <boost/asio.hpp> class Film; class Player; @@ -50,6 +51,7 @@ private: void audio (boost::shared_ptr<AudioBuffers> audio); void player_changed (); bool should_run () const; + void prepare (boost::weak_ptr<PlayerVideo> video) const; boost::weak_ptr<const Film> _film; boost::shared_ptr<Player> _player; @@ -58,6 +60,10 @@ private: VideoRingBuffers _video; AudioRingBuffers _audio; + boost::thread_group _prepare_pool; + boost::asio::io_service _prepare_service; + boost::shared_ptr<boost::asio::io_service::work> _prepare_work; + /** mutex to protect _pending_seek_position, _pending_seek_acurate, _finished, _died, _stop_thread */ boost::mutex _mutex; boost::condition _summon; diff --git a/src/lib/image_proxy.h b/src/lib/image_proxy.h index d7bd7b0e6..f9a06d1b7 100644 --- a/src/lib/image_proxy.h +++ b/src/lib/image_proxy.h @@ -74,6 +74,10 @@ public: virtual void send_binary (boost::shared_ptr<Socket>) const = 0; /** @return true if our image is definitely the same as another, false if it is probably not */ virtual bool same (boost::shared_ptr<const ImageProxy>) const = 0; + /** Do any useful work that would speed up a subsequent call to ::image(). + * This method may be called in a different thread to image(). + */ + virtual void prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const {} virtual AVPixelFormat pixel_format () const = 0; }; diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index f7e6dd5f4..9e68951e9 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -93,35 +93,45 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc socket->read (_data.data().get (), _data.size ()); } -shared_ptr<Image> -J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_size) const +void +J2KImageProxy::prepare (optional<dcp::Size> target_size) const { - if (!_decompressed || target_size != _target_size) { - int reduce = 0; + boost::mutex::scoped_lock lm (_mutex); - while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) { - ++reduce; - } + if (_decompressed && target_size == _target_size) { + return; + } - --reduce; - reduce = max (0, reduce); - _decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce); + int reduce = 0; - if (_decompressed->precision(0) < 12) { - int const shift = 12 - _decompressed->precision (0); - for (int c = 0; c < 3; ++c) { - int* p = _decompressed->data (c); - for (int y = 0; y < _decompressed->size().height; ++y) { - for (int x = 0; x < _decompressed->size().width; ++x) { - *p++ <<= shift; - } + while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) { + ++reduce; + } + + --reduce; + reduce = max (0, reduce); + _decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce); + + if (_decompressed->precision(0) < 12) { + int const shift = 12 - _decompressed->precision (0); + for (int c = 0; c < 3; ++c) { + int* p = _decompressed->data (c); + for (int y = 0; y < _decompressed->size().height; ++y) { + for (int x = 0; x < _decompressed->size().width; ++x) { + *p++ <<= shift; } } } - - _target_size = target_size; } + _target_size = target_size; +} + +shared_ptr<Image> +J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_size) const +{ + prepare (target_size); + shared_ptr<Image> image (new Image (_pixel_format, _decompressed->size(), true)); /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index 41d68588f..3133aac20 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2015-2017 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -21,6 +21,7 @@ #include "image_proxy.h" #include <dcp/util.h> #include <dcp/data.h> +#include <boost/thread/mutex.hpp> namespace dcp { class MonoPictureFrame; @@ -44,6 +45,7 @@ public: void send_binary (boost::shared_ptr<Socket>) const; /** @return true if our image is definitely the same as another, false if it is probably not */ bool same (boost::shared_ptr<const ImageProxy>) const; + void prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; AVPixelFormat pixel_format () const { return _pixel_format; } @@ -68,4 +70,5 @@ private: mutable boost::shared_ptr<dcp::OpenJPEGImage> _decompressed; mutable boost::optional<dcp::Size> _target_size; AVPixelFormat _pixel_format; + mutable boost::mutex _mutex; }; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index 6f0977e62..14291fc35 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -246,3 +246,9 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p) { return p == AV_PIX_FMT_XYZ12LE ? AV_PIX_FMT_XYZ12LE : AV_PIX_FMT_RGB48LE; } + +void +PlayerVideo::prepare () +{ + _in->prepare (_inter_size); +} diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 5017d0e3c..040145559 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -57,6 +57,7 @@ public: void set_subtitle (PositionImage); + void prepare (); boost::shared_ptr<Image> image (dcp::NoteHandler note, boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const; static AVPixelFormat always_rgb (AVPixelFormat); |
