#endif
, _state_timer ("viewer")
, _gets (0)
+ , _idle_get (false)
{
switch (Config::instance()->video_view_type()) {
case Config::VIDEO_VIEW_OPENGL:
stop ();
}
+/** Ask for ::get() to be called next time we are idle */
+void
+FilmViewer::request_idle_get ()
+{
+ if (_idle_get) {
+ return;
+ }
+
+ _idle_get = true;
+ DCPOMATIC_ASSERT (signal_manager);
+ signal_manager->when_idle (boost::bind(&FilmViewer::idle_handler, this));
+}
+
+void
+FilmViewer::idle_handler ()
+{
+ if (!_idle_get) {
+ return;
+ }
+
+ if (get(true)) {
+ _idle_get = false;
+ } else {
+ /* get() could not complete quickly so we'll try again later */
+ signal_manager->when_idle (boost::bind(&FilmViewer::idle_handler, this));
+ }
+}
+
void
FilmViewer::set_film (shared_ptr<Film> film)
{
Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
*/
- map.set (dcp::LEFT, 0, 1 / sqrt(2)); // L -> Lt
- map.set (dcp::RIGHT, 1, 1 / sqrt(2)); // R -> Rt
- map.set (dcp::CENTRE, 0, 1 / 2.0); // C -> Lt
- map.set (dcp::CENTRE, 1, 1 / 2.0); // C -> Rt
- map.set (dcp::LFE, 0, 1 / sqrt(10)); // Lfe -> Lt
- map.set (dcp::LFE, 1, 1 / sqrt(10)); // Lfe -> Rt
- map.set (dcp::LS, 0, 1 / sqrt(2)); // Ls -> Lt
- map.set (dcp::RS, 1, 1 / sqrt(2)); // Rs -> Rt
+ if (_film->audio_channels() > 0) {
+ map.set (dcp::LEFT, 0, 1 / sqrt(2)); // L -> Lt
+ }
+ if (_film->audio_channels() > 1) {
+ map.set (dcp::RIGHT, 1, 1 / sqrt(2)); // R -> Rt
+ }
+ if (_film->audio_channels() > 2) {
+ map.set (dcp::CENTRE, 0, 1 / 2.0); // C -> Lt
+ map.set (dcp::CENTRE, 1, 1 / 2.0); // C -> Rt
+ }
+ if (_film->audio_channels() > 3) {
+ map.set (dcp::LFE, 0, 1 / sqrt(10)); // Lfe -> Lt
+ map.set (dcp::LFE, 1, 1 / sqrt(10)); // Lfe -> Rt
+ }
+ if (_film->audio_channels() > 4) {
+ map.set (dcp::LS, 0, 1 / sqrt(2)); // Ls -> Lt
+ }
+ if (_film->audio_channels() > 5) {
+ map.set (dcp::RS, 1, 1 / sqrt(2)); // Rs -> Rt
+ }
}
_butler.reset (new Butler(_player, map, _audio_channels, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
_state_timer.unset ();
}
-void
-FilmViewer::get ()
+/** Try to get a frame from the butler and display it.
+ * @param lazy true to return false quickly if no video is available quickly (i.e. we are waiting for the butler).
+ * false to ask the butler to block until it has video (unless it is suspended).
+ * @return true on success, false if we did nothing because it would have taken too long.
+ */
+bool
+FilmViewer::get (bool lazy)
{
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) {
- signal_manager->when_idle (boost::bind(&FilmViewer::get, this));
- return;
+ if (lazy) {
+ /* No video available; return saying we failed */
+ return false;
+ } else {
+ /* Player was suspended; come back later */
+ signal_manager->when_idle (boost::bind(&FilmViewer::get, this, false));
+ return false;
+ }
}
} while (
_player_video.first &&
_player_video.first->eyes() != EYES_BOTH
);
- _butler->rethrow ();
+ try {
+ _butler->rethrow ();
+ } catch (DecodeError& e) {
+ error_dialog (_video_view->get(), e.what());
+ }
display_player_video ();
+ PositionChanged ();
+
+ return true;
}
void
return;
}
- get ();
- PositionChanged ();
+ get (false);
DCPTime const next = _video_position + one_video_frame();
if (next >= _film->length()) {
_closed_captions_dialog->clear ();
_butler->seek (t, accurate);
- get ();
+ request_idle_get ();
if (was_running) {
start ();
}
-
- PositionChanged ();
}
void