Look up unknown subtitle end times from the data prepared by the examiner.
authorCarl Hetherington <cth@carlh.net>
Tue, 12 May 2015 23:41:50 +0000 (00:41 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 12 May 2015 23:41:50 +0000 (00:41 +0100)
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_content.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/ffmpeg_examiner.cc
src/lib/ffmpeg_subtitle_stream.cc
src/lib/ffmpeg_subtitle_stream.h
src/lib/util.cc

index 3a42b169fd3000a3cce43fcd76b73f27177b4cb5..ad9096b92adadcb903312c34669989037c3724c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2015 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
@@ -377,21 +377,12 @@ FFmpegContent::audio_analysis_path () const
 list<ContentTimePeriod>
 FFmpegContent::subtitles_during (ContentTimePeriod period, bool starting) const
 {
-       list<ContentTimePeriod> d;
-       
        shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
        if (!stream) {
-               return d;
-       }
-
-       /* XXX: inefficient */
-       for (vector<ContentTimePeriod>::const_iterator i = stream->periods.begin(); i != stream->periods.end(); ++i) {
-               if ((starting && period.contains (i->from)) || (!starting && period.overlaps (*i))) {
-                       d.push_back (*i);
-               }
+               return list<ContentTimePeriod> ();
        }
 
-       return d;
+       return stream->subtitles_during (period, starting);
 }
 
 bool
index 76ba43567d9961ea2c1798c3ebfe13fb27e9772b..d6edb2bdbd10978688c8c9c88bd614b52507baa6 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2015 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
index 5dc06fa8e44f68f7b57201ac36ad50296cce8fd7..a3d647cdecd1e3bf3d2db8ce8891bbb8357ed0e5 100644 (file)
@@ -426,35 +426,30 @@ FFmpegDecoder::decode_subtitle_packet ()
        if (avcodec_decode_subtitle2 (subtitle_codec_context(), &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) {
                return;
        }
-
-       /* Subtitle PTS (within the source, not taking into account any of the
-          source that we may have chopped off for the DCP)
-       */
-       FFmpegSubtitlePeriod period = subtitle_period (sub);
-       period.from += _pts_offset;
-       if (period.to) {
-               period.to = period.to.get() + _pts_offset;
-       }
        
        if (sub.num_rects <= 0) {
                /* Sometimes we get an empty AVSubtitle, which is used by some codecs to
-                  indicate that the previous subtitle should stop.  Emit the pending one.
+                  indicate that the previous subtitle should stop.  We can ignore it here.
                */
-               if (_pending_subtitle_from && _pending_subtitle_image && _pending_subtitle_rect) {
-                       image_subtitle (
-                               ContentTimePeriod (_pending_subtitle_from.get(), period.from),
-                               _pending_subtitle_image,
-                               _pending_subtitle_rect.get ()
-                               );
-                       _pending_subtitle_from = optional<ContentTime> ();
-                       _pending_subtitle_image.reset ();
-                       _pending_subtitle_rect = optional<dcpomatic::Rect<double> > ();
-               }                       
                return;
        } else if (sub.num_rects > 1) {
                throw DecodeError (_("multi-part subtitles not yet supported"));
        }
-               
+
+       /* Subtitle PTS (within the source, not taking into account any of the
+          source that we may have chopped off for the DCP).
+       */
+       FFmpegSubtitlePeriod sub_period = subtitle_period (sub);
+       ContentTimePeriod period;
+       period.from = sub_period.from + _pts_offset;
+       if (sub_period.to) {
+               /* We already know the subtitle period `to' time */
+               period.to = sub_period.to.get() + _pts_offset;
+       } else {
+               /* We have to look up the `to' time in the stream's records */
+               period.to = ffmpeg_content()->subtitle_stream()->find_subtitle_to (sub_period.from);
+       }
+       
        AVSubtitleRect const * rect = sub.rects[0];
 
        if (rect->type != SUBTITLE_BITMAP) {
@@ -494,14 +489,7 @@ FFmpegDecoder::decode_subtitle_packet ()
                static_cast<double> (rect->h) / vs.height
                );
 
-       if (period.to) {
-               image_subtitle (ContentTimePeriod (period.from, period.to.get()), image, scaled_rect);
-       } else {
-               /* We don't know when this subtitle stops, so store it until we find out */
-               _pending_subtitle_from = period.from;
-               _pending_subtitle_image = image;
-               _pending_subtitle_rect = scaled_rect;
-       }
+       image_subtitle (ContentTimePeriod (period.from, period.to), image, scaled_rect);
        
        avsubtitle_free (&sub);
 }
index b5bcdd35800fbaa07a0556ce00c082f8e4964e91..0a0eea18a7380ee9423d5b0b8076908a65654e4b 100644 (file)
@@ -67,10 +67,6 @@ private:
        void maybe_add_subtitle ();
        boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t** data, int size);
 
-       boost::optional<ContentTime> _pending_subtitle_from;
-       boost::shared_ptr<Image> _pending_subtitle_image;
-       boost::optional<dcpomatic::Rect<double> > _pending_subtitle_rect;
-
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
        std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod, bool starting) const;
        
index e4f4e6f2904c3a263fc176e78fbb7da23d13f3c3..8afd4c164a85a54c1fc8dd11e147bc49cd407334 100644 (file)
@@ -152,11 +152,11 @@ FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr<FFmpegSubti
        if (avcodec_decode_subtitle2 (context, &sub, &frame_finished, &_packet) >= 0 && frame_finished) {
                FFmpegSubtitlePeriod const period = subtitle_period (sub);
                if (sub.num_rects <= 0 && _last_subtitle_start) {
-                       stream->periods.push_back (ContentTimePeriod (_last_subtitle_start.get (), period.from));
+                       stream->add_subtitle (ContentTimePeriod (_last_subtitle_start.get (), period.from));
                        _last_subtitle_start = optional<ContentTime> ();
                } else if (sub.num_rects == 1) {
                        if (period.to) {
-                               stream->periods.push_back (ContentTimePeriod (period.from, period.to.get ()));
+                               stream->add_subtitle (ContentTimePeriod (period.from, period.to.get ()));
                        } else {
                                _last_subtitle_start = period.from;
                        }
index 66b587209af7c55f2a5958bd3e16af9327e390da..77a56e330297f608c84e6077c797190d5cad2809 100644 (file)
@@ -23,6 +23,8 @@
 #include <boost/foreach.hpp>
 
 using std::string;
+using std::map;
+using std::list;
 
 /** Construct a SubtitleStream from a value returned from to_string().
  *  @param t String returned from to_string().
@@ -32,7 +34,7 @@ FFmpegSubtitleStream::FFmpegSubtitleStream (cxml::ConstNodePtr node)
        : FFmpegStream (node)
 {
        BOOST_FOREACH (cxml::NodePtr i, node->node_children ("Period")) {
-               periods.push_back (
+               add_subtitle (
                        ContentTimePeriod (
                                ContentTime (node->number_child<ContentTime::Type> ("From")),
                                ContentTime (node->number_child<ContentTime::Type> ("To"))
@@ -46,9 +48,39 @@ FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const
 {
        FFmpegStream::as_xml (root);
 
-       BOOST_FOREACH (ContentTimePeriod const & i, periods) {
-               xmlpp::Node* node = root->add_child ("Period");
-               node->add_child("From")->add_child_text (raw_convert<string> (i.from.get ()));
-               node->add_child("To")->add_child_text (raw_convert<string> (i.to.get ()));
+       for (map<ContentTime, ContentTime>::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+               xmlpp::Node* node = root->add_child ("Subtitle");
+               node->add_child("From")->add_child_text (raw_convert<string> (i->first.get ()));
+               node->add_child("To")->add_child_text (raw_convert<string> (i->second.get ()));
        }
 }
+
+void
+FFmpegSubtitleStream::add_subtitle (ContentTimePeriod period)
+{
+       DCPOMATIC_ASSERT (_subtitles.find (period.from) == _subtitles.end ());
+       _subtitles[period.from] = period.to;
+}
+
+list<ContentTimePeriod> 
+FFmpegSubtitleStream::subtitles_during (ContentTimePeriod period, bool starting) const
+{
+       list<ContentTimePeriod> d;
+       
+       /* XXX: inefficient */
+       for (map<ContentTime, ContentTime>::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+               if ((starting && period.contains (i->first)) || (!starting && period.overlaps (ContentTimePeriod (i->first, i->second)))) {
+                       d.push_back (ContentTimePeriod (i->first, i->second));
+               }
+       }
+
+       return d;
+}
+
+ContentTime
+FFmpegSubtitleStream::find_subtitle_to (ContentTime from) const
+{
+       map<ContentTime, ContentTime>::const_iterator i = _subtitles.find (from);
+       DCPOMATIC_ASSERT (i != _subtitles.end ());
+       return i->second;
+}
index b16b825e7d76b3a401bc36c94a28b382771b1cd8..3ed931b8c996b1691cf0acbe25dc9434d28b1cd1 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2015 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
@@ -31,6 +31,11 @@ public:
 
        void as_xml (xmlpp::Node *) const;
 
-       std::vector<ContentTimePeriod> periods;
+       void add_subtitle (ContentTimePeriod period);
+       std::list<ContentTimePeriod> subtitles_during (ContentTimePeriod period, bool starting) const;
+       ContentTime find_subtitle_to (ContentTime from) const;
+
+private:
+       std::map<ContentTime, ContentTime> _subtitles;
 };
 
index d8c754607f47a5940b51e95921ead82c11a2daca..99d9ba2c4f55654f12e2af866585121b2f6cb92e 100644 (file)
@@ -670,3 +670,4 @@ write_frame_info (FILE* file, int frame, Eyes eyes, dcp::FrameInfo info)
        fwrite (&info.size, sizeof (info.size), 1, file);
        fwrite (info.hash.c_str(), 1, info.hash.size(), file);
 }
+