From 0253b4e45c71a1c2e2a8bffaf1c3cb84a0a3e41a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 3 Aug 2017 17:54:06 +0100 Subject: [PATCH] Basics of forced reduction of JPEG2000 decode resolution. --- src/lib/dcp_decoder.cc | 32 +++++++++++++++++++++++++++++--- src/lib/dcp_decoder.h | 2 ++ src/lib/j2k_image_proxy.cc | 30 ++++++++++++++++++++++++------ src/lib/j2k_image_proxy.h | 19 +++++++++++++++++-- src/lib/player.cc | 21 ++++++++++++++++++++- src/lib/player.h | 3 +++ src/lib/video_mxf_decoder.cc | 18 ++++++++++++++---- src/tools/dcpomatic_player.cc | 23 +++++++++++++++++++++++ src/wx/film_viewer.cc | 6 ++++++ src/wx/film_viewer.h | 1 + 10 files changed, 139 insertions(+), 16 deletions(-) diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index c7294bda7..ef40f2ec7 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -48,6 +48,7 @@ using std::list; using std::cout; using boost::shared_ptr; using boost::dynamic_pointer_cast; +using boost::optional; DCPDecoder::DCPDecoder (shared_ptr c, shared_ptr log) : DCP (c) @@ -100,20 +101,39 @@ DCPDecoder::pass () if (_mono_reader) { video->emit ( shared_ptr ( - new J2KImageProxy (_mono_reader->get_frame (entry_point + frame), asset->size(), AV_PIX_FMT_XYZ12LE) + new J2KImageProxy ( + _mono_reader->get_frame (entry_point + frame), + asset->size(), + AV_PIX_FMT_XYZ12LE, + _forced_reduction + ) ), _offset + frame ); } else { video->emit ( shared_ptr ( - new J2KImageProxy (_stereo_reader->get_frame (entry_point + frame), asset->size(), dcp::EYE_LEFT, AV_PIX_FMT_XYZ12LE)), + new J2KImageProxy ( + _stereo_reader->get_frame (entry_point + frame), + asset->size(), + dcp::EYE_LEFT, + AV_PIX_FMT_XYZ12LE, + _forced_reduction + ) + ), _offset + frame ); video->emit ( shared_ptr ( - new J2KImageProxy (_stereo_reader->get_frame (entry_point + frame), asset->size(), dcp::EYE_RIGHT, AV_PIX_FMT_XYZ12LE)), + new J2KImageProxy ( + _stereo_reader->get_frame (entry_point + frame), + asset->size(), + dcp::EYE_RIGHT, + AV_PIX_FMT_XYZ12LE, + _forced_reduction + ) + ), _offset + frame ); } @@ -234,3 +254,9 @@ DCPDecoder::set_decode_referenced () { _decode_referenced = true; } + +void +DCPDecoder::set_forced_reduction (optional reduction) +{ + _forced_reduction = reduction; +} diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index 71687ad15..aa76b83d6 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -46,6 +46,7 @@ public: } void set_decode_referenced (); + void set_forced_reduction (boost::optional reduction); bool pass (); void seek (ContentTime t, bool accurate); @@ -71,4 +72,5 @@ private: boost::shared_ptr _sound_reader; bool _decode_referenced; + boost::optional _forced_reduction; }; diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 9e68951e9..a60af1eb2 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -53,18 +53,31 @@ J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPi } -J2KImageProxy::J2KImageProxy (shared_ptr frame, dcp::Size size, AVPixelFormat pixel_format) +J2KImageProxy::J2KImageProxy ( + shared_ptr frame, + dcp::Size size, + AVPixelFormat pixel_format, + optional forced_reduction + ) : _data (frame->j2k_size ()) , _size (size) , _pixel_format (pixel_format) + , _forced_reduction (forced_reduction) { memcpy (_data.data().get(), frame->j2k_data(), _data.size ()); } -J2KImageProxy::J2KImageProxy (shared_ptr frame, dcp::Size size, dcp::Eye eye, AVPixelFormat pixel_format) +J2KImageProxy::J2KImageProxy ( + shared_ptr frame, + dcp::Size size, + dcp::Eye eye, + AVPixelFormat pixel_format, + optional forced_reduction + ) : _size (size) , _eye (eye) , _pixel_format (pixel_format) + , _forced_reduction (forced_reduction) { switch (eye) { case dcp::EYE_LEFT: @@ -104,12 +117,17 @@ J2KImageProxy::prepare (optional target_size) const int reduce = 0; - while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) { - ++reduce; + if (_forced_reduction) { + reduce = *_forced_reduction; + } else { + 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); } - --reduce; - reduce = max (0, reduce); _decompressed = dcp::decompress_j2k (const_cast (_data.data().get()), _data.size (), reduce); if (_decompressed->precision(0) < 12) { diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index 3133aac20..c20d89340 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -32,8 +32,22 @@ class J2KImageProxy : public ImageProxy { public: J2KImageProxy (boost::filesystem::path path, dcp::Size, AVPixelFormat pixel_format); - J2KImageProxy (boost::shared_ptr frame, dcp::Size, AVPixelFormat pixel_format); - J2KImageProxy (boost::shared_ptr frame, dcp::Size, dcp::Eye, AVPixelFormat pixel_format); + + J2KImageProxy ( + boost::shared_ptr frame, + dcp::Size, + AVPixelFormat pixel_format, + boost::optional forced_reduction + ); + + J2KImageProxy ( + boost::shared_ptr frame, + dcp::Size, + dcp::Eye, + AVPixelFormat pixel_format, + boost::optional forced_reduction + ); + J2KImageProxy (boost::shared_ptr xml, boost::shared_ptr socket); boost::shared_ptr image ( @@ -71,4 +85,5 @@ private: mutable boost::optional _target_size; AVPixelFormat _pixel_format; mutable boost::mutex _mutex; + boost::optional _forced_reduction; }; diff --git a/src/lib/player.cc b/src/lib/player.cc index 3d191a302..7e21ef937 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -127,7 +127,10 @@ Player::setup_pieces () shared_ptr dcp = dynamic_pointer_cast (decoder); if (dcp && _play_referenced) { - dcp->set_decode_referenced (); + if (_play_referenced) { + dcp->set_decode_referenced (); + } + dcp->set_forced_reduction (_dcp_decode_reduction); } shared_ptr piece (new Piece (i, decoder, frc)); @@ -850,6 +853,10 @@ Player::subtitle_stop (weak_ptr wp, ContentTime to) void Player::seek (DCPTime time, bool accurate) { + if (!_have_valid_pieces) { + setup_pieces (); + } + if (_audio_processor) { _audio_processor->flush (); } @@ -950,3 +957,15 @@ Player::discard_audio (shared_ptr audio, DCPTime time, DCPTi cut->copy_from (audio.get(), remaining_frames, discard_frames, 0); return make_pair(cut, time + discard_time); } + +void +Player::set_dcp_decode_reduction (optional reduction) +{ + if (reduction == _dcp_decode_reduction) { + return; + } + + _dcp_decode_reduction = reduction; + _have_valid_pieces = false; + Changed (false); +} diff --git a/src/lib/player.h b/src/lib/player.h index ee7f89aaa..9dd5afd26 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -67,6 +67,7 @@ public: void set_always_burn_subtitles (bool burn); void set_fast (); void set_play_referenced (); + void set_dcp_decode_reduction (boost::optional reduction); /** Emitted when something has changed such that if we went back and emitted * the last frame again it would look different. This is not emitted after @@ -147,6 +148,8 @@ private: /** Time just after the last audio frame we emitted, or the time of the last accurate seek */ boost::optional _last_audio_time; + boost::optional _dcp_decode_reduction; + typedef std::map, boost::shared_ptr > LastVideoMap; LastVideoMap _last_video; diff --git a/src/lib/video_mxf_decoder.cc b/src/lib/video_mxf_decoder.cc index 216721375..194830c63 100644 --- a/src/lib/video_mxf_decoder.cc +++ b/src/lib/video_mxf_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2016 Carl Hetherington + Copyright (C) 2016-2017 Carl Hetherington This file is part of DCP-o-matic. @@ -29,6 +29,7 @@ #include using boost::shared_ptr; +using boost::optional; VideoMXFDecoder::VideoMXFDecoder (shared_ptr content, shared_ptr log) : _content (content) @@ -78,14 +79,23 @@ VideoMXFDecoder::pass () if (_mono_reader) { video->emit ( - shared_ptr (new J2KImageProxy (_mono_reader->get_frame(frame), _size, AV_PIX_FMT_XYZ12LE)), frame + shared_ptr ( + new J2KImageProxy (_mono_reader->get_frame(frame), _size, AV_PIX_FMT_XYZ12LE, optional()) + ), + frame ); } else { video->emit ( - shared_ptr (new J2KImageProxy (_stereo_reader->get_frame(frame), _size, dcp::EYE_LEFT, AV_PIX_FMT_XYZ12LE)), frame + shared_ptr ( + new J2KImageProxy (_stereo_reader->get_frame(frame), _size, dcp::EYE_LEFT, AV_PIX_FMT_XYZ12LE, optional()) + ), + frame ); video->emit ( - shared_ptr (new J2KImageProxy (_stereo_reader->get_frame(frame), _size, dcp::EYE_RIGHT, AV_PIX_FMT_XYZ12LE)), frame + shared_ptr ( + new J2KImageProxy (_stereo_reader->get_frame(frame), _size, dcp::EYE_RIGHT, AV_PIX_FMT_XYZ12LE, optional()) + ), + frame ); } diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 3a7c18f02..567440f88 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -50,6 +50,10 @@ using boost::optional; enum { ID_file_open = 1, + ID_view_scale_appropriate, + ID_view_scale_full, + ID_view_scale_half, + ID_view_scale_quarter, ID_help_report_a_problem, ID_tools_check_for_updates, }; @@ -77,6 +81,10 @@ public: Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_open, this), ID_file_open); Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional()), ID_view_scale_appropriate); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional(0)), ID_view_scale_full); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional(1)), ID_view_scale_half); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional(2)), ID_view_scale_quarter); Bind (wxEVT_MENU, boost::bind (&DOMFrame::help_about, this), wxID_ABOUT); Bind (wxEVT_MENU, boost::bind (&DOMFrame::help_report_a_problem, this), ID_help_report_a_problem); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_check_for_updates, this), ID_tools_check_for_updates); @@ -96,6 +104,11 @@ public: UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this)); } + void set_decode_reduction (optional reduction) + { + _viewer->set_dcp_decode_reduction (reduction); + } + void load_dcp (boost::filesystem::path dir) { _film.reset (new Film (optional())); @@ -146,6 +159,12 @@ private: edit->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P")); #endif + wxMenu* view = new wxMenu; + view->AppendRadioItem (ID_view_scale_appropriate, _("Set decode resolution to match display")); + view->AppendRadioItem (ID_view_scale_full, _("Decode at full resolution")); + view->AppendRadioItem (ID_view_scale_half, _("Decode at half resolution")); + view->AppendRadioItem (ID_view_scale_quarter, _("Decode at quarter resolution")); + wxMenu* tools = new wxMenu; tools->Append (ID_tools_check_for_updates, _("Check for updates")); @@ -158,6 +177,10 @@ private: help->Append (ID_help_report_a_problem, _("Report a problem...")); m->Append (file, _("&File")); +#ifndef __WXOSX__ + m->Append (edit, _("&Edit")); +#endif + m->Append (view, _("&View")); m->Append (tools, _("&Tools")); m->Append (help, _("&Help")); } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 776926fbe..2b7f73e68 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -786,3 +786,9 @@ FilmViewer::average_latency () const return total / _latency_history.size(); } + +void +FilmViewer::set_dcp_decode_reduction (optional reduction) +{ + _player->set_dcp_decode_reduction (reduction); +} diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index f8658be38..3f7a3be33 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -56,6 +56,7 @@ public: void set_position (DCPTime p); void set_coalesce_player_changes (bool c); + void set_dcp_decode_reduction (boost::optional reduction); void refresh (); -- 2.30.2