Option to draw a border around the content's image (#391).
authorCarl Hetherington <cth@carlh.net>
Tue, 22 Jul 2014 15:32:37 +0000 (16:32 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 22 Jul 2014 15:32:37 +0000 (16:32 +0100)
12 files changed:
src/lib/film.cc
src/lib/player.cc
src/lib/player_video.cc
src/lib/player_video.h
src/lib/util.cc
src/lib/util.h
src/lib/video_content.cc
src/lib/video_content.h
src/wx/film_viewer.cc
src/wx/film_viewer.h
src/wx/video_panel.cc
test/ratio_test.cc

index 0de6f2ded75e9cbf0ae1ad8782b830e968e38d19..0891838ff930674548ea90c23e7f117fcdc05905 100644 (file)
@@ -1071,7 +1071,7 @@ Film::full_frame () const
 dcp::Size
 Film::frame_size () const
 {
-       return fit_ratio_within (container()->ratio(), full_frame ());
+       return fit_ratio_within (container()->ratio(), full_frame (), 1);
 }
 
 dcp::EncryptedKDM
index 06f9e1365df3525d4807814bccdf8ec0fa348b54..e46d539f872c90fb1e130cdcd45049f77ddc169b 100644 (file)
@@ -342,7 +342,7 @@ Player::get_video (DCPTime time, bool accurate)
                        return pvf;
                }
                
-               dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
+               dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size (), _approximate_size ? 4 : 1);
                if (_approximate_size) {
                        image_size.width &= ~3;
                        image_size.height &= ~3;
index a44264ceddd23bcad2c3e5dea92512e6e8d0c9ec..8fd966e5fc57a73ff2c0297fe0c893b07ec35e81 100644 (file)
@@ -111,8 +111,6 @@ PlayerVideo::image (bool burn_subtitle) const
                
        shared_ptr<Image> out = im->crop_scale_window (total_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, true);
 
-       Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
-
        if (burn_subtitle && _subtitle.image) {
                out->alpha_blend (_subtitle.image, _subtitle.position);
        }
@@ -171,3 +169,11 @@ PlayerVideo::j2k () const
        assert (j2k);
        return j2k->j2k ();
 }
+
+Position<int>
+PlayerVideo::inter_position () const
+{
+       return Position<int> ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.height) / 2);
+}
+
+
index 4fe8712d489735c9e546c65bc304c8f2b2ad959f..74e05d1e91b46ea654b31148f7439576d0c065e1 100644 (file)
@@ -62,6 +62,14 @@ public:
                return _colour_conversion;
        }
 
+       /** @return Position of the content within the overall image once it has been scaled up */
+       Position<int> inter_position () const;
+
+       /** @return Size of the content within the overall image once it has been scaled up */
+       dcp::Size inter_size () const {
+               return _inter_size;
+       }
+
 private:
        boost::shared_ptr<const ImageProxy> _in;
        DCPTime _time;
index cc8d59f217cd1e4277fa20a9ed4a7dda1caa9391..60953b544d1a0c26b3816c674db3f9612b4ee181 100644 (file)
@@ -636,6 +636,17 @@ stride_round_up (int c, int const * stride, int t)
        return a - (a % t);
 }
 
+/** @param n A number.
+ *  @param r Rounding `boundary' (must be a power of 2)
+ *  @return n rounded to the nearest r
+ */
+int
+round_to (float n, int r)
+{
+       assert (r == 1 || r == 2 || r == 4);
+       return int (n + float(r) / 2) &~ (r - 1);
+}
+
 /** Read a sequence of key / value pairs from a text stream;
  *  the keys are the first words on the line, and the values are
  *  the remainder of the line following the key.  Lines beginning
@@ -837,13 +848,13 @@ split_get_request (string url)
 }
 
 dcp::Size
-fit_ratio_within (float ratio, dcp::Size full_frame)
+fit_ratio_within (float ratio, dcp::Size full_frame, int round)
 {
        if (ratio < full_frame.ratio ()) {
-               return dcp::Size (rint (full_frame.height * ratio), full_frame.height);
+               return dcp::Size (round_to (full_frame.height * ratio, round), full_frame.height);
        }
        
-       return dcp::Size (full_frame.width, rint (full_frame.width / ratio));
+       return dcp::Size (full_frame.width, round_to (full_frame.width / ratio, round));
 }
 
 void *
index b7dc978e32d8a91f56e693ca895f917f03989102..1bbdfb2cf23dc56864241f1669b6cc87f8feea97 100644 (file)
@@ -66,11 +66,12 @@ extern bool valid_image_file (boost::filesystem::path);
 extern boost::filesystem::path mo_path ();
 #endif
 extern std::string tidy_for_filename (std::string);
-extern dcp::Size fit_ratio_within (float ratio, dcp::Size);
+extern dcp::Size fit_ratio_within (float ratio, dcp::Size, int);
 extern std::string entities_to_text (std::string e);
 extern std::map<std::string, std::string> split_get_request (std::string url);
 extern int dcp_audio_frame_rate (int);
 extern int stride_round_up (int, int const *, int);
+extern int round_to (float n, int r);
 extern std::multimap<std::string, std::string> read_key_value (std::istream& s);
 extern int get_required_int (std::multimap<std::string, std::string> const & kv, std::string k);
 extern float get_required_float (std::multimap<std::string, std::string> const & kv, std::string k);
index 0d9a8fc45c491c24b664751daf3f4a4df73f15ab..0a3e378eecb1fda2f05ef3b6894659c6849386fe 100644 (file)
@@ -508,25 +508,25 @@ VideoContentScale::name () const
  *  @param film_container The size of the film's image.
  */
 dcp::Size
-VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container) const
+VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container, int round) const
 {
        if (_ratio) {
-               return fit_ratio_within (_ratio->ratio (), display_container);
+               return fit_ratio_within (_ratio->ratio (), display_container, round);
        }
 
        dcp::Size const ac = c->video_size_after_crop ();
 
        /* Force scale if the film_container is smaller than the content's image */
        if (_scale || film_container.width < ac.width || film_container.height < ac.height) {
-               return fit_ratio_within (ac.ratio (), display_container);
+               return fit_ratio_within (ac.ratio (), display_container, 1);
        }
 
        /* Scale the image so that it will be in the right place in film_container, even if display_container is a
           different size.
        */
        return dcp::Size (
-               c->video_size().width  * float(display_container.width)  / film_container.width,
-               c->video_size().height * float(display_container.height) / film_container.height
+               round_to (c->video_size().width  * float(display_container.width)  / film_container.width, round),
+               round_to (c->video_size().height * float(display_container.height) / film_container.height, round)
                );
 }
 
index 7d9cb4f8f0298eccb5a307b37612b5ab8e6e95be..dc7de8d54a7f557ff2b70fe951b6cabaa98975d0 100644 (file)
@@ -45,7 +45,7 @@ public:
        VideoContentScale (bool);
        VideoContentScale (cxml::NodePtr);
 
-       dcp::Size size (boost::shared_ptr<const VideoContent>, dcp::Size, dcp::Size) const;
+       dcp::Size size (boost::shared_ptr<const VideoContent>, dcp::Size, dcp::Size, int round) const;
        std::string id () const;
        std::string name () const;
        void as_xml (xmlpp::Node *) const;
index 80b12bf7627e797702799bd48a6ac7b3e2898ed8..96e20a281af3b2c1e690b49135be8fa621be5bfc 100644 (file)
@@ -58,6 +58,7 @@ using dcp::Size;
 FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
        : wxPanel (p)
        , _panel (new wxPanel (this))
+       , _outline_content (new wxCheckBox (this, wxID_ANY, _("Outline content")))
        , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096))
        , _back_button (new wxButton (this, wxID_ANY, wxT("<")))
        , _forward_button (new wxButton (this, wxID_ANY, wxT(">")))
@@ -77,6 +78,8 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
 
        _v_sizer->Add (_panel, 1, wxEXPAND);
 
+       _v_sizer->Add (_outline_content, 0, wxALL, DCPOMATIC_SIZER_GAP);
+
        wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL);
 
        wxBoxSizer* time_sizer = new wxBoxSizer (wxVERTICAL);
@@ -97,6 +100,7 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
 
        _panel->Bind          (wxEVT_PAINT,                        boost::bind (&FilmViewer::paint_panel,     this));
        _panel->Bind          (wxEVT_SIZE,                         boost::bind (&FilmViewer::panel_sized,     this, _1));
+       _outline_content->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED,     boost::bind (&FilmViewer::refresh_panel,   this));
        _slider->Bind         (wxEVT_SCROLL_THUMBTRACK,            boost::bind (&FilmViewer::slider_moved,    this));
        _slider->Bind         (wxEVT_SCROLL_PAGEUP,                boost::bind (&FilmViewer::slider_moved,    this));
        _slider->Bind         (wxEVT_SCROLL_PAGEDOWN,              boost::bind (&FilmViewer::slider_moved,    this));
@@ -145,6 +149,13 @@ FilmViewer::set_film (shared_ptr<Film> f)
        get (_position, _last_get_accurate);
 }
 
+void
+FilmViewer::refresh_panel ()
+{
+       _panel->Refresh ();
+       _panel->Update ();
+}
+
 void
 FilmViewer::get (DCPTime p, bool accurate)
 {
@@ -158,6 +169,8 @@ FilmViewer::get (DCPTime p, bool accurate)
                        _frame = pvf.front()->image (true);
                        _frame = _frame->scale (_frame->size(), Scaler::from_id ("fastbilinear"), PIX_FMT_RGB24, false);
                        _position = pvf.front()->time ();
+                       _inter_position = pvf.front()->inter_position ();
+                       _inter_size = pvf.front()->inter_size ();
                } catch (dcp::DCPReadError& e) {
                        /* This can happen on the following sequence of events:
                         * - load encrypted DCP
@@ -178,8 +191,7 @@ FilmViewer::get (DCPTime p, bool accurate)
        }
 
        set_position_text ();
-       _panel->Refresh ();
-       _panel->Update ();
+       refresh_panel ();
 
        _last_get_accurate = accurate;
 }
@@ -228,9 +240,15 @@ FilmViewer::paint_panel ()
                dc.SetPen (p);
                dc.SetBrush (b);
                dc.DrawRectangle (0, _out_size.height, _panel_size.width, _panel_size.height - _out_size.height);
-       }               
-}
+       }
 
+       if (_outline_content->GetValue ()) {
+               wxPen p (wxColour (255, 0, 0), 2);
+               dc.SetPen (p);
+               dc.SetBrush (*wxTRANSPARENT_BRUSH);
+               dc.DrawRectangle (_inter_position.x, _inter_position.y, _inter_size.width, _inter_size.height);
+       }
+}
 
 void
 FilmViewer::slider_moved ()
@@ -252,6 +270,7 @@ FilmViewer::panel_sized (wxSizeEvent& ev)
 {
        _panel_size.width = ev.GetSize().GetWidth();
        _panel_size.height = ev.GetSize().GetHeight();
+
        calculate_sizes ();
        get (_position, _last_get_accurate);
 }
@@ -271,18 +290,18 @@ FilmViewer::calculate_sizes ()
        if (panel_ratio < film_ratio) {
                /* panel is less widscreen than the film; clamp width */
                _out_size.width = _panel_size.width;
-               _out_size.height = _out_size.width / film_ratio;
+               _out_size.height = rint (_out_size.width / film_ratio);
        } else {
                /* panel is more widescreen than the film; clamp height */
                _out_size.height = _panel_size.height;
-               _out_size.width = _out_size.height * film_ratio;
+               _out_size.width = rint (_out_size.height * film_ratio);
        }
 
        /* Catch silly values */
        _out_size.width = max (64, _out_size.width);
        _out_size.height = max (64, _out_size.height);
 
-       /* The player will round its image down to the nearest 4 pixels
+       /* The player will round its image size down to the next lowest 4 pixels
           to speed up its scale, so do similar here to avoid black borders
           around things.  This is a bit of a hack.
        */
index 189b379bf3beeaa68f43a2d343220e307d891ece..930937596ab9afa64fb340463c07c6c0298e851e 100644 (file)
@@ -54,12 +54,14 @@ private:
        void player_changed (bool);
        void set_position_text ();
        void get (DCPTime, bool);
+       void refresh_panel ();
 
        boost::shared_ptr<Film> _film;
        boost::shared_ptr<Player> _player;
 
        wxSizer* _v_sizer;
        wxPanel* _panel;
+       wxCheckBox* _outline_content;
        wxSlider* _slider;
        wxButton* _back_button;
        wxButton* _forward_button;
@@ -70,6 +72,8 @@ private:
 
        boost::shared_ptr<const Image> _frame;
        DCPTime _position;
+       Position<int> _inter_position;
+       dcp::Size _inter_size;
 
        /** Size of our output (including padding if we have any) */
        dcp::Size _out_size;
index d8fdf2d02667c7894477a9e5aaa8691d6758c146..facd0f3d48fcd8d7d38b9bf6c5c12a56b258100a 100644 (file)
@@ -309,7 +309,7 @@ VideoPanel::setup_description ()
        }
 
        dcp::Size const container_size = _parent->film()->frame_size ();
-       dcp::Size const scaled = vcs->scale().size (vcs, container_size, container_size);
+       dcp::Size const scaled = vcs->scale().size (vcs, container_size, container_size, 1);
 
        if (scaled != vcs->video_size_after_crop ()) {
                d << wxString::Format (
index 84e80861b14cf3f0abb8daae63a781edbf884513..eab30ceee02ab3d098b8935d516551fbbc7d8060 100644 (file)
@@ -35,38 +35,38 @@ BOOST_AUTO_TEST_CASE (ratio_test)
 
        Ratio const * r = Ratio::from_id ("119");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1290, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1290, 1080));
 
        r = Ratio::from_id ("133");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1440, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1440, 1080));
 
        r = Ratio::from_id ("137");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1480, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1480, 1080));
 
        r = Ratio::from_id ("138");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1485, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1485, 1080));
 
        r = Ratio::from_id ("166");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1800, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1800, 1080));
 
        r = Ratio::from_id ("178");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1920, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1920, 1080));
 
        r = Ratio::from_id ("185");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (1998, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (1998, 1080));
 
        r = Ratio::from_id ("239");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (2048, 858));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (2048, 858));
 
        r = Ratio::from_id ("full-frame");
        BOOST_CHECK (r);
-       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080)), dcp::Size (2048, 1080));
+       BOOST_CHECK_EQUAL (fit_ratio_within (r->ratio(), dcp::Size (2048, 1080), 1), dcp::Size (2048, 1080));
 }