Show an explanatory message if the player is not performing very well (#1932).
authorCarl Hetherington <cth@carlh.net>
Sat, 3 Apr 2021 21:17:56 +0000 (23:17 +0200)
committerCarl Hetherington <cth@carlh.net>
Sat, 3 Apr 2021 21:17:56 +0000 (23:17 +0200)
src/lib/config.h
src/wx/film_viewer.cc
src/wx/film_viewer.h
src/wx/nag_dialog.cc
src/wx/video_view.cc
src/wx/video_view.h

index 3371e48bfc3b5dfa5cc1815b04de8d9f33c8d1c4..0a48a00e1dfc8a71ac66e77ca26a07d73610e2c4 100644 (file)
@@ -392,6 +392,9 @@ public:
                return _jump_to_selected;
        }
 
+       /* This could be an enum class but we use the enum a lot to index _nagged
+        * so it means a lot of casts.
+        */
        enum Nag {
                NAG_DKDM_CONFIG,
                NAG_ENCRYPTED_METADATA,
@@ -400,6 +403,7 @@ public:
                NAG_IMPORT_DECRYPTION_CHAIN,
                NAG_DELETE_DKDM,
                NAG_32_ON_64,
+               NAG_TOO_MANY_DROPPED_FRAMES,
                NAG_COUNT
        };
 
index b9e9bd5331ae07c9b2959446a5a50a8ae9b69e4c..14737d0094626d3775c2a6b05a5bcd58b7cde67c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 
 */
 
+
 /** @file  src/film_viewer.cc
  *  @brief A wx widget to view a preview of a Film.
  */
 
-#include "film_viewer.h"
-#include "playhead_to_timecode_dialog.h"
-#include "playhead_to_frame_dialog.h"
-#include "wx_util.h"
+
 #include "closed_captions_dialog.h"
+#include "film_viewer.h"
 #include "gl_video_view.h"
+#include "nag_dialog.h"
+#include "playhead_to_frame_dialog.h"
+#include "playhead_to_timecode_dialog.h"
 #include "simple_video_view.h"
+#include "wx_util.h"
 #include "lib/film.h"
 #include "lib/ratio.h"
 #include "lib/util.h"
@@ -106,6 +109,7 @@ FilmViewer::FilmViewer (wxWindow* p)
        }
 
        _video_view->Sized.connect (boost::bind(&FilmViewer::video_view_sized, this));
+       _video_view->TooManyDropped.connect (boost::bind(&FilmViewer::too_many_frames_dropped, this));
 
        set_film (shared_ptr<Film> ());
 
@@ -730,3 +734,22 @@ FilmViewer::image_changed (shared_ptr<PlayerVideo> pv)
        emit (boost::bind(boost::ref(ImageChanged), pv));
 }
 
+
+void
+FilmViewer::too_many_frames_dropped ()
+{
+       if (!Config::instance()->nagged(Config::NAG_TOO_MANY_DROPPED_FRAMES)) {
+               stop ();
+       }
+
+       bool shown = NagDialog::maybe_nag (
+               panel(),
+               Config::NAG_TOO_MANY_DROPPED_FRAMES,
+               _("The player is dropping a lot of frames, so playback may not be accurate.\n\n"
+                 "<b>This does not necessarily mean that the DCP you are playing is defective!</b>\n\n"
+                 "You may be able to improve player performance by:\n"
+                 "• choosing 'decode at half resolution' or 'decode at quarter resolution' from the View menu\n"
+                 "• using a more powerful computer.\n"
+                )
+               );
+}
index 8024bb1bfc16ff9020b5596e057c1dbd0b9fb3df..52b97f0f63201d8686ad2262c05fec53f2a9dc2c 100644 (file)
@@ -161,6 +161,7 @@ private:
        void config_changed (Config::Property);
        void film_length_change ();
        void ui_finished ();
+       void too_many_frames_dropped ();
 
        dcpomatic::DCPTime uncorrected_time () const;
        Frame average_latency () const;
index 466b80b6bb0baf77b5948dcc26dd10e22cf0a1c8..85f2d0110828afe240fbd6458566298d695a8c8d 100644 (file)
@@ -70,7 +70,7 @@ NagDialog::maybe_nag (wxWindow* parent, Config::Nag nag, wxString message, bool
                return false;
        }
 
-       NagDialog* d = new NagDialog (parent, nag, message, can_cancel);
+       auto d = new NagDialog (parent, nag, message, can_cancel);
        int const r = d->ShowModal();
        d->Destroy ();
 
index 5f44c37d61779db3cced384221af5fdba9289506..387d4052fd87b1f02298b8c6ba8dbac083b43dc8 100644 (file)
 #include "lib/butler.h"
 #include "lib/dcpomatic_log.h"
 #include <boost/optional.hpp>
+#include <sys/time.h>
+
 
 using std::pair;
 using std::shared_ptr;
 using boost::optional;
 
 
+static constexpr int TOO_MANY_DROPPED_FRAMES = 20;
+static constexpr int TOO_MANY_DROPPED_PERIOD = 5.0;
+
+
 VideoView::VideoView (FilmViewer* viewer)
        : _viewer (viewer)
        , _state_timer ("viewer")
@@ -124,6 +130,7 @@ VideoView::start ()
        boost::mutex::scoped_lock lm (_mutex);
        _dropped = 0;
        _errored = 0;
+       gettimeofday(&_dropped_check_period_start, nullptr);
 }
 
 
@@ -143,3 +150,26 @@ VideoView::reset_metadata (shared_ptr<const Film> film, dcp::Size player_video_c
        return true;
 }
 
+
+void
+VideoView::add_dropped ()
+{
+       bool too_many = false;
+
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               ++_dropped;
+               if (_dropped > TOO_MANY_DROPPED_FRAMES) {
+                       struct timeval now;
+                       gettimeofday (&now, nullptr);
+                       double const elapsed = seconds(now) - seconds(_dropped_check_period_start);
+                       too_many = elapsed < TOO_MANY_DROPPED_PERIOD;
+                       _dropped = 0;
+                       _dropped_check_period_start = now;
+               }
+       }
+
+       if (too_many) {
+               emit (boost::bind(boost::ref(TooManyDropped)));
+       }
+}
index d3a15d38c3e9573a252acecf49134333120be24a..d7d60c21da14b4e933af418a8ea79ad223fdc574 100644 (file)
 
 
 #include "lib/dcpomatic_time.h"
+#include "lib/exception_store.h"
+#include "lib/signaller.h"
 #include "lib/timer.h"
 #include "lib/types.h"
-#include "lib/exception_store.h"
 #include <boost/signals2.hpp>
 #include <boost/thread.hpp>
 
@@ -38,7 +39,7 @@ class Player;
 class PlayerVideo;
 
 
-class VideoView : public ExceptionStore
+class VideoView : public ExceptionStore, public Signaller
 {
 public:
        VideoView (FilmViewer* viewer);
@@ -70,6 +71,8 @@ public:
 
        /** Emitted from the GUI thread when our display changes in size */
        boost::signals2::signal<void()> Sized;
+       /** Emitted from the GUI thread when a lot of frames are being dropped */
+       boost::signals2::signal<void()> TooManyDropped;
 
 
        /* Accessors for FilmViewer */
@@ -143,10 +146,7 @@ protected:
                return _player_video;
        }
 
-       void add_dropped () {
-               boost::mutex::scoped_lock lm (_mutex);
-               ++_dropped;
-       }
+       void add_dropped ();
 
        void add_get () {
                boost::mutex::scoped_lock lm (_mutex);
@@ -169,6 +169,7 @@ private:
        bool _three_d = false;
 
        int _dropped = 0;
+       struct timeval _dropped_check_period_start;
        int _errored = 0;
        int _gets = 0;
 };