Be more careful in a few places.
[dcpomatic.git] / src / wx / film_viewer.cc
index 1cf45fd4e47a568b22ae3af5c94aceb6a069535f..4f99516f2a3e5d1ea6ea2194c5e8c7aed5e7983a 100644 (file)
@@ -86,12 +86,22 @@ FilmViewer::film_changed (Film::Property p)
        {
                shared_ptr<DecodeOptions> o (new DecodeOptions);
                o->decode_audio = false;
+               o->decode_subtitles = true;
                o->video_sync = false;
                _decoders = decoder_factory (_film, o, 0);
                _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2));
                _decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
+               _decoders.video->set_subtitle_stream (_film->subtitle_stream());
                break;
        }
+       case Film::WITH_SUBTITLES:
+       case Film::SUBTITLE_OFFSET:
+       case Film::SUBTITLE_SCALE:
+               update_from_raw ();
+               break;
+       case Film::SUBTITLE_STREAM:
+               _decoders.video->set_subtitle_stream (_film->subtitle_stream ());
+               break;
        default:
                break;
        }
@@ -115,6 +125,10 @@ FilmViewer::set_film (shared_ptr<Film> f)
        film_changed (Film::CONTENT);
        film_changed (Film::CROP);
        film_changed (Film::FORMAT);
+       film_changed (Film::WITH_SUBTITLES);
+       film_changed (Film::SUBTITLE_OFFSET);
+       film_changed (Film::SUBTITLE_SCALE);
+       film_changed (Film::SUBTITLE_STREAM);
 }
 
 void
@@ -126,13 +140,14 @@ FilmViewer::decoder_changed ()
 void
 FilmViewer::timer (wxTimerEvent& ev)
 {
+       if (!_film) {
+               return;
+       }
+       
        _panel->Refresh ();
        _panel->Update ();
 
-       shared_ptr<Image> last = _display;
-       while (last == _display) {
-               _decoders.video->pass ();
-       }
+       get_frame ();
 
        if (_film->length()) {
                int const new_slider_position = 4096 * _decoders.video->last_source_frame() / _film->length().get();
@@ -147,19 +162,30 @@ void
 FilmViewer::paint_panel (wxPaintEvent& ev)
 {
        wxPaintDC dc (_panel);
-       if (!_display) {
+
+       if (!_display_frame || !_film) {
                return;
        }
 
-       wxImage i (_out_width, _out_height, _display->data()[0], true);
-       wxBitmap b (i);
-       dc.DrawBitmap (b, 0, 0);
+       wxImage frame (_out_width, _out_height, _display_frame->data()[0], true);
+       wxBitmap frame_bitmap (frame);
+       dc.DrawBitmap (frame_bitmap, 0, 0);
+
+       if (_film->with_subtitles() && _display_sub) {
+               wxImage sub (_display_sub->size().width, _display_sub->size().height, _display_sub->data()[0], _display_sub->alpha(), true);
+               wxBitmap sub_bitmap (sub);
+               dc.DrawBitmap (sub_bitmap, _display_sub_position.x, _display_sub_position.y);
+       }
 }
 
 
 void
 FilmViewer::slider_moved (wxCommandEvent& ev)
 {
+       if (!_film) {
+               return;
+       }
+       
        if (_film->length()) {
                seek_and_update (_slider->GetValue() * _film->length().get() / 4096);
        }
@@ -168,12 +194,11 @@ FilmViewer::slider_moved (wxCommandEvent& ev)
 void
 FilmViewer::seek_and_update (SourceFrame f)
 {
-       _decoders.video->seek (f);
-       
-       shared_ptr<Image> last = _display;
-       while (last == _display) {
-               _decoders.video->pass ();
+       if (_decoders.video->seek (f)) {
+               return;
        }
+
+       get_frame ();
        _panel->Refresh ();
        _panel->Update ();
 }
@@ -190,21 +215,46 @@ FilmViewer::panel_sized (wxSizeEvent& ev)
 void
 FilmViewer::update_from_raw ()
 {
-       if (!_raw) {
+       if (!_raw_frame) {
                return;
        }
 
-       if (_out_width && _out_height) {
-               _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
-       }
+       raw_to_display ();
        
        _panel->Refresh ();
        _panel->Update ();
 }
 
+void
+FilmViewer::raw_to_display ()
+{
+       if (!_out_width || !_out_height || !_film) {
+               return;
+       }
+       
+       _display_frame = _raw_frame->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, _film->scaler());
+
+       if (_raw_sub) {
+               Rect tx = subtitle_transformed_area (
+                       float (_out_width) / _film->size().width,
+                       float (_out_height) / _film->size().height,
+                       _raw_sub->area(), _film->subtitle_offset(), _film->subtitle_scale()
+                       );
+               
+               _display_sub.reset (new RGBPlusAlphaImage (_raw_sub->image()->scale (tx.size(), _film->scaler ())));
+               _display_sub_position = tx.position();
+       } else {
+               _display_sub.reset ();
+       }
+}      
+
 void
 FilmViewer::calculate_sizes ()
 {
+       if (!_film) {
+               return;
+       }
+       
        float const panel_ratio = static_cast<float> (_panel_width) / _panel_height;
        float const film_ratio = _film->format() ? _film->format()->ratio_as_float(_film) : 1.78;
        if (panel_ratio < film_ratio) {
@@ -227,6 +277,10 @@ FilmViewer::play_clicked (wxCommandEvent &)
 void
 FilmViewer::check_play_state ()
 {
+       if (!_film) {
+               return;
+       }
+       
        if (_play_button->GetValue()) {
                _timer.Start (1000 / _film->frames_per_second());
        } else {
@@ -237,8 +291,21 @@ FilmViewer::check_play_state ()
 void
 FilmViewer::process_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
 {
-       _raw = image;
-       if (_out_width && _out_height) {
-               _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
+       _raw_frame = image;
+       _raw_sub = sub;
+
+       raw_to_display ();
+}
+
+void
+FilmViewer::get_frame ()
+{
+       if (!_out_width || !_out_height) {
+               return;
+       }
+       
+       shared_ptr<Image> last = _display_frame;
+       while (last == _display_frame) {
+               _decoders.video->pass ();
        }
 }