Improve behaviour of the position slider at the end of films.
[dcpomatic.git] / src / wx / film_viewer.cc
index f569f4c54ae097a43c893cccff62f09689cfaeca..ce5eab00e1db8e8f0bd4bb7e707fe470e59bc7cb 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -35,8 +35,6 @@
 #include "lib/filter.h"
 #include "lib/player.h"
 #include "lib/video_content.h"
-#include "lib/ffmpeg_content.h"
-#include "lib/still_image_content.h"
 #include "lib/video_decoder.h"
 #include "film_viewer.h"
 #include "wx_util.h"
@@ -47,6 +45,7 @@ using std::min;
 using std::max;
 using std::cout;
 using std::list;
+using std::bad_alloc;
 using std::make_pair;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
@@ -120,8 +119,7 @@ FilmViewer::set_film (shared_ptr<Film> f)
        _film = f;
 
        _frame.reset ();
-       _queue.clear ();
-
+       
        _slider->SetValue (0);
        set_position_text (0);
        
@@ -129,13 +127,20 @@ FilmViewer::set_film (shared_ptr<Film> f)
                return;
        }
 
-       _player = f->make_player ();
+       try {
+               _player = f->make_player ();
+       } catch (bad_alloc) {
+               error_dialog (this, _("There is not enough free memory to do that."));
+               _film.reset ();
+               return;
+       }
+       
        _player->disable_audio ();
-       _player->Video.connect (boost::bind (&FilmViewer::process_video, this, _1, _2, _4));
+       _player->Video.connect (boost::bind (&FilmViewer::process_video, this, _1, _2, _5));
        _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1));
 
        calculate_sizes ();
-       fetch_current_frame_again ();
+       fetch_next_frame ();
 }
 
 void
@@ -145,17 +150,17 @@ FilmViewer::fetch_current_frame_again ()
                return;
        }
 
-       /* Player::video_position is the time after the last frame that we received.
-          We want to see it again, so seek back one frame.
+       /* We could do this with a seek and a fetch_next_frame, but this is
+          a shortcut to make it quicker.
        */
 
-       Time p = _player->video_position() - _film->video_frames_to_time (1);
-       if (p < 0) {
-               p = 0;
+       _got_frame = false;
+       if (!_player->repeat_last_video ()) {
+               fetch_next_frame ();
        }
-
-       _player->seek (p, true);
-       fetch_next_frame ();
+       
+       _panel->Refresh ();
+       _panel->Update ();
 }
 
 void
@@ -188,9 +193,7 @@ FilmViewer::paint_panel ()
                return;
        }
 
-       shared_ptr<Image> packed_frame (new Image (_frame, false));
-
-       wxImage frame (_out_size.width, _out_size.height, packed_frame->data()[0], true);
+       wxImage frame (_out_size.width, _out_size.height, _frame->data()[0], true);
        wxBitmap frame_bitmap (frame);
        dc.DrawBitmap (frame_bitmap, 0, 0);
 
@@ -216,7 +219,12 @@ void
 FilmViewer::slider_moved ()
 {
        if (_film && _player) {
-               _player->seek (_slider->GetValue() * _film->length() / 4096, false);
+               Time t = _slider->GetValue() * _film->length() / 4096;
+               /* Ensure that we hit the end of the film at the end of the slider */
+               if (t >= _film->length ()) {
+                       t = _film->length() - _film->video_frames_to_time (1);
+               }
+               _player->seek (t, false);
                fetch_next_frame ();
        }
 }
@@ -239,7 +247,7 @@ FilmViewer::calculate_sizes ()
 
        Ratio const * container = _film->container ();
        
-       float const panel_ratio = static_cast<float> (_panel_size.width) / _panel_size.height;
+       float const panel_ratio = _panel_size.ratio ();
        float const film_ratio = container ? container->ratio () : 1.78;
                        
        if (panel_ratio < film_ratio) {
@@ -280,19 +288,13 @@ FilmViewer::check_play_state ()
 }
 
 void
-FilmViewer::process_video (shared_ptr<const Image> image, Eyes eyes, Time t)
+FilmViewer::process_video (shared_ptr<PlayerImage> image, Eyes eyes, Time t)
 {
        if (eyes == EYES_RIGHT) {
                return;
        }
        
-       if (_got_frame) {
-               /* This is an additional frame emitted by a single pass.  Store it. */
-               _queue.push_front (make_pair (image, t));
-               return;
-       }
-       
-       _frame = image;
+       _frame = image->image ();
        _got_frame = true;
 
        set_position_text (t);
@@ -335,17 +337,16 @@ FilmViewer::fetch_next_frame ()
 
        _got_frame = false;
        
-       if (!_queue.empty ()) {
-               process_video (_queue.back().first, EYES_BOTH, _queue.back().second);
-               _queue.pop_back ();
-       } else {
-               try {
-                       while (!_got_frame && !_player->pass ()) {}
-               } catch (DecodeError& e) {
-                       _play_button->SetValue (false);
-                       check_play_state ();
-                       error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data()));
-               }
+       try {
+               while (!_got_frame && !_player->pass ()) {}
+       } catch (DecodeError& e) {
+               _play_button->SetValue (false);
+               check_play_state ();
+               error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data()));
+       } catch (OpenFileError& e) {
+               /* There was a problem opening a content file; we'll let this slide as it
+                  probably means a missing content file, which we're already taking care of.
+               */
        }
 
        _panel->Refresh ();
@@ -382,8 +383,13 @@ FilmViewer::back_clicked ()
        /* Player::video_position is the time after the last frame that we received.
           We want to see the one before it, so we need to go back 2.
        */
+
+       Time p = _player->video_position() - _film->video_frames_to_time (2);
+       if (p < 0) {
+               p = 0;
+       }
        
-       _player->seek (_player->video_position() - _film->video_frames_to_time(2), true);
+       _player->seek (p, true);
        fetch_next_frame ();
 }
 
@@ -403,7 +409,7 @@ FilmViewer::player_changed (bool frequent)
        if (frequent) {
                return;
        }
-       
+
        calculate_sizes ();
        fetch_current_frame_again ();
 }