Fix subtitle display when the next subtitle is decoded before the
authorCarl Hetherington <cth@carlh.net>
Fri, 25 Apr 2014 22:43:16 +0000 (23:43 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 25 Apr 2014 22:43:16 +0000 (23:43 +0100)
previous one has finished; this requires that more than one subtitle be
kept by the player.

Reported-by: Matthias Damm
ChangeLog
src/lib/player.cc
src/lib/player.h
src/lib/subtitle.cc
src/lib/subtitle.h

index aaed9198321a7b7b049069d3100cdf15d6d319e8..d8307c4f5c3815cf20321f4377448ed7e4e3197b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-04-25  Carl Hetherington  <cth@carlh.net>
+
+       * Fix subtitle display when the next subtitle is decoded before the previous
+       one has finished.
+
 2014-04-24  Carl Hetherington  <cth@carlh.net>
 
        * Version 1.66.14 released.
index d0653bc4302e2322378ec7162553e266d493feb6..1bb2e7cf4329a3fbd303b5b0338d487d9e9c4614 100644 (file)
@@ -219,17 +219,34 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
                        )
                );
        
-       if (_film->with_subtitles () && _subtitle && _subtitle->out_image() && _subtitle->covers (time)) {
+       if (_film->with_subtitles ()) {
+               for (list<Subtitle>::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+                       if (i->covers (time)) {
+                               /* This may be true for more than one of _subtitles, but the last (latest-starting)
+                                  one is the one we want to use, so that's ok.
+                               */
+                               Position<int> const container_offset (
+                                       (_video_container_size.width - image_size.width) / 2,
+                                       (_video_container_size.height - image_size.width) / 2
+                                       );
+                               
+                               pi->set_subtitle (i->out_image(), i->out_position() + container_offset);
+                       }
+               }
+       }
 
-               Position<int> const container_offset (
-                       (_video_container_size.width - image_size.width) / 2,
-                       (_video_container_size.height - image_size.width) / 2
-                       );
+       /* Clear out old subtitles */
+       for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ) {
+               list<Subtitle>::iterator j = i;
+               ++j;
+               
+               if (i->ends_before (time)) {
+                       _subtitles.erase (i);
+               }
 
-               pi->set_subtitle (_subtitle->out_image(), _subtitle->out_position() + container_offset);
+               i = j;
        }
-               
-                                           
+
 #ifdef DCPOMATIC_DEBUG
        _last_video = piece->content;
 #endif
@@ -466,9 +483,10 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
                property == SubtitleContentProperty::SUBTITLE_SCALE
                ) {
 
-               if (_subtitle) {
-                       _subtitle->update (_film, _video_container_size);
+               for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+                       i->update (_film, _video_container_size);
                }
+               
                Changed (frequent);
 
        } else if (
@@ -576,7 +594,14 @@ Player::film_changed (Film::Property p)
 void
 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
 {
-       _subtitle = Subtitle (_film, _video_container_size, weak_piece, image, rect, from, to);
+       if (!image) {
+               /* A null image means that we should stop any current subtitles at `from' */
+               for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+                       i->set_stop (from);
+               }
+       } else {
+               _subtitles.push_back (Subtitle (_film, _video_container_size, weak_piece, image, rect, from, to));
+       }
 }
 
 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
index 5dad80ec7d9192b94d05c641446717485f09816e..4d911a83be3f4ecd9daa715a2aef3848bba025a8 100644 (file)
@@ -143,7 +143,7 @@ private:
        boost::shared_ptr<PlayerImage> _black_frame;
        std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
 
-       boost::optional<Subtitle> _subtitle;
+       std::list<Subtitle> _subtitles;
 
 #ifdef DCPOMATIC_DEBUG
        boost::shared_ptr<Content> _last_video;
index f348833b0de52ad6615090660963df2015ff12c4..0d18861c455f69f2d2649730f93d898d0ed66463 100644 (file)
@@ -97,6 +97,8 @@ Subtitle::update (shared_ptr<const Film> film, libdcp::Size video_container_size
        
        _out_from = from + piece->content->position ();
        _out_to = to + piece->content->position ();
+
+       check_out_to ();
 }
 
 bool
@@ -104,3 +106,11 @@ Subtitle::covers (Time t) const
 {
        return _out_from <= t && t <= _out_to;
 }
+
+void
+Subtitle::check_out_to ()
+{
+       if (_stop && _out_to > _stop.get ()) {
+               _out_to = _stop.get ();
+       }
+}
index 7ba5912e0ccaeb30656b9ab2fcaab506026e17bf..c74f5c1b9f0c7c6c775dc368aea684eea1048f82 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <boost/shared_ptr.hpp>
 #include <boost/weak_ptr.hpp>
+#include <boost/optional.hpp>
 #include <libdcp/util.h>
 #include "rect.h"
 #include "types.h"
@@ -34,8 +35,15 @@ public:
        Subtitle (boost::shared_ptr<const Film>, libdcp::Size, boost::weak_ptr<Piece>, boost::shared_ptr<Image>, dcpomatic::Rect<double>, Time, Time);
 
        void update (boost::shared_ptr<const Film>, libdcp::Size);
+       void set_stop (Time t) {
+               _stop = t;
+               check_out_to ();
+       }
 
        bool covers (Time t) const;
+       bool ends_before (Time t) const {
+               return _out_to < t;
+       }
 
        boost::shared_ptr<Image> out_image () const {
                return _out_image;
@@ -45,7 +53,9 @@ public:
                return _out_position;
        }
        
-private:       
+private:
+       void check_out_to ();
+       
        boost::weak_ptr<Piece> _piece;
        boost::shared_ptr<Image> _in_image;
        dcpomatic::Rect<double> _in_rect;
@@ -56,4 +66,7 @@ private:
        Position<int> _out_position;
        Time _out_from;
        Time _out_to;
+
+       /** Time at which this subtitle should stop (overriding _out_to) */
+       boost::optional<Time> _stop;
 };