Optimise the feel of some GUI functions by doing the seek after
authorCarl Hetherington <cth@carlh.net>
Wed, 24 Jul 2019 19:42:50 +0000 (20:42 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 24 Jul 2019 19:42:50 +0000 (20:42 +0100)
many content changes in an idle handler, rather than blocking
the UI update until the seek and image redisplay have finished.

src/lib/butler.cc
src/lib/butler.h
src/lib/ffmpeg_encoder.cc
src/wx/film_viewer.cc
src/wx/film_viewer.h
test/butler_test.cc
test/dcp_playback_test.cc
test/player_test.cc

index 8c46d51904262aab9f4598032ed344e264a5eb86..2d6c46c7eea0b04f7cc880e0819fad7bb1badf4c 100644 (file)
@@ -216,12 +216,16 @@ try
        _arrived.notify_all ();
 }
 
        _arrived.notify_all ();
 }
 
+/** @param blocking true if we should block until video is available.  If blocking is false
+ *  and no video is immediately available the method will return a 0 PlayerVideo and the error AGAIN.
+ *  @param e if non-0 this is filled with an error code (if an error occurs) or is untouched if no error occurs.
+ */
 pair<shared_ptr<PlayerVideo>, DCPTime>
 pair<shared_ptr<PlayerVideo>, DCPTime>
-Butler::get_video (Error* e)
+Butler::get_video (bool blocking, Error* e)
 {
        boost::mutex::scoped_lock lm (_mutex);
 
 {
        boost::mutex::scoped_lock lm (_mutex);
 
-       if (_suspended) {
+       if (_suspended || (_video.empty() && !blocking)) {
                if (e) {
                        *e = AGAIN;
                }
                if (e) {
                        *e = AGAIN;
                }
index 09c182f9cf717fb3c53d6371c7dd949add01fe41..e5581ccb42169e6f07e555d174c348d1b49517ec 100644 (file)
@@ -54,7 +54,7 @@ public:
                AGAIN
        };
 
                AGAIN
        };
 
-       std::pair<boost::shared_ptr<PlayerVideo>, dcpomatic::DCPTime> get_video (Error* e = 0);
+       std::pair<boost::shared_ptr<PlayerVideo>, dcpomatic::DCPTime> get_video (bool blocking, Error* e = 0);
        boost::optional<dcpomatic::DCPTime> get_audio (float* out, Frame frames);
        boost::optional<TextRingBuffers::Data> get_closed_caption ();
 
        boost::optional<dcpomatic::DCPTime> get_audio (float* out, Frame frames);
        boost::optional<TextRingBuffers::Data> get_closed_caption ();
 
index 7c641f5ab5e684720bc0187ef48307bdff4cea88..572e7ae16080ef7b8bc2a44bf781a0defe2299d7 100644 (file)
@@ -150,7 +150,7 @@ FFmpegEncoder::go ()
                }
 
                for (int j = 0; j < gets_per_frame; ++j) {
                }
 
                for (int j = 0; j < gets_per_frame; ++j) {
-                       pair<shared_ptr<PlayerVideo>, DCPTime> v = _butler->get_video ();
+                       pair<shared_ptr<PlayerVideo>, DCPTime> v = _butler->get_video (true, 0);
                        encoder->get(v.first->eyes())->video(v.first, v.second);
                }
 
                        encoder->get(v.first->eyes())->video(v.first, v.second);
                }
 
index a2b055934e9a1fdda844115f9628132172493006..edb451e74b8f1ce15d1947dc7792651342258f83 100644 (file)
@@ -231,17 +231,22 @@ FilmViewer::refresh_view ()
        _state_timer.unset ();
 }
 
        _state_timer.unset ();
 }
 
+/** @param lazy true if it is *not* important that the display be updated as quickly as possible.
+ *  If lazy is true we will try to return from this method quickly and postpone any time-consuming
+ *  work until the UI is next idle.  Otherwise we will block here and try to get the image on
+ *  screen as soon as possible.
+ */
 void
 void
-FilmViewer::get ()
+FilmViewer::get (bool lazy)
 {
        DCPOMATIC_ASSERT (_butler);
        ++_gets;
 
        do {
                Butler::Error e;
 {
        DCPOMATIC_ASSERT (_butler);
        ++_gets;
 
        do {
                Butler::Error e;
-               _player_video = _butler->get_video (&e);
+               _player_video = _butler->get_video (!lazy, &e);
                if (!_player_video.first && e == Butler::AGAIN) {
                if (!_player_video.first && e == Butler::AGAIN) {
-                       signal_manager->when_idle (boost::bind(&FilmViewer::get, this));
+                       signal_manager->when_idle (boost::bind(&FilmViewer::get, this, lazy));
                        return;
                }
        } while (
                        return;
                }
        } while (
@@ -257,7 +262,11 @@ FilmViewer::get ()
                error_dialog (_video_view->get(), e.what());
        }
 
                error_dialog (_video_view->get(), e.what());
        }
 
-       display_player_video ();
+       if (lazy) {
+               signal_manager->when_idle (boost::bind(&FilmViewer::display_player_video, this));
+       } else {
+               display_player_video ();
+       }
 }
 
 void
 }
 
 void
@@ -322,7 +331,7 @@ FilmViewer::timer ()
                return;
        }
 
                return;
        }
 
-       get ();
+       get (false);
        PositionChanged ();
        DCPTime const next = _video_position + one_video_frame();
 
        PositionChanged ();
        DCPTime const next = _video_position + one_video_frame();
 
@@ -541,7 +550,7 @@ FilmViewer::seek (DCPTime t, bool accurate)
 
        _closed_captions_dialog->clear ();
        _butler->seek (t, accurate);
 
        _closed_captions_dialog->clear ();
        _butler->seek (t, accurate);
-       get ();
+       get (true);
 
        if (was_running) {
                start ();
 
        if (was_running) {
                start ();
index 5ddb12bafd0e2045422c60a3a98c2efd6682f286..298e9dd00591ca22e7e1609077c30fa45c4efb9d 100644 (file)
@@ -151,7 +151,7 @@ private:
        void timer ();
        void calculate_sizes ();
        void player_change (ChangeType type, int, bool);
        void timer ();
        void calculate_sizes ();
        void player_change (ChangeType type, int, bool);
-       void get ();
+       void get (bool lazy);
        void display_player_video ();
        void film_change (ChangeType, Film::Property);
        void recreate_butler ();
        void display_player_video ();
        void film_change (ChangeType, Film::Property);
        void recreate_butler ();
index cc28412689937c4db139ffa0fb2f19b6f33dbe69..7aeba78f952e8d13c95d8c7ef6b7a46dc5364dbd 100644 (file)
@@ -54,9 +54,9 @@ BOOST_AUTO_TEST_CASE (butler_test1)
 
        Butler butler (shared_ptr<Player>(new Player(film, film->playlist())), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, false);
 
 
        Butler butler (shared_ptr<Player>(new Player(film, film->playlist())), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, false);
 
-       BOOST_CHECK (butler.get_video().second == DCPTime());
-       BOOST_CHECK (butler.get_video().second == DCPTime::from_frames(1, 24));
-       BOOST_CHECK (butler.get_video().second == DCPTime::from_frames(2, 24));
+       BOOST_CHECK (butler.get_video(true, 0).second == DCPTime());
+       BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(1, 24));
+       BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(2, 24));
        /* XXX: check the frame contents */
 
        float buffer[256 * 6];
        /* XXX: check the frame contents */
 
        float buffer[256 * 6];
index 9fef1801b83e8f84a5bd433ec7bcfbde57835909..1dda667a08ab825bac698cb9e2fe6ca83a7bbf53 100644 (file)
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test)
                );
        float* audio_buffer = new float[2000*6];
        while (true) {
                );
        float* audio_buffer = new float[2000*6];
        while (true) {
-               pair<shared_ptr<PlayerVideo>, DCPTime> p = butler->get_video ();
+               pair<shared_ptr<PlayerVideo>, DCPTime> p = butler->get_video (true, 0);
                if (!p.first) {
                        break;
                }
                if (!p.first) {
                        break;
                }
index 7b65783c6047dcfd646b1cae21e44bbc3550a531..af40002deb06191af6cae40311395f68498de9a3 100644 (file)
@@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test)
        for (int i = 0; i < 10; ++i) {
                DCPTime t = DCPTime::from_frames (i, 24);
                butler->seek (t, true);
        for (int i = 0; i < 10; ++i) {
                DCPTime t = DCPTime::from_frames (i, 24);
                butler->seek (t, true);
-               pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video();
+               pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
                write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test_%1.png", i), "RGB");
                /* This 0.055 is empirically chosen (hopefully) to accept changes in rendering between the reference and a test machine
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
                write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test_%1.png", i), "RGB");
                /* This 0.055 is empirically chosen (hopefully) to accept changes in rendering between the reference and a test machine
@@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test2)
        for (int i = 0; i < 10; ++i) {
                DCPTime t = DCPTime::from_seconds(5) + DCPTime::from_frames (i, 24);
                butler->seek (t, true);
        for (int i = 0; i < 10; ++i) {
                DCPTime t = DCPTime::from_seconds(5) + DCPTime::from_frames (i, 24);
                butler->seek (t, true);
-               pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video();
+               pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
                write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test2_%1.png", i), "RGB");
                check_image(String::compose("test/data/player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 0.055);
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
                write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test2_%1.png", i), "RGB");
                check_image(String::compose("test/data/player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 0.055);