From 83e5567530d0be24490abdda46d196e4279c5030 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 13 May 2015 00:41:50 +0100 Subject: [PATCH] Look up unknown subtitle end times from the data prepared by the examiner. --- src/lib/ffmpeg_content.cc | 15 ++-------- src/lib/ffmpeg_content.h | 2 +- src/lib/ffmpeg_decoder.cc | 46 ++++++++++++------------------- src/lib/ffmpeg_decoder.h | 4 --- src/lib/ffmpeg_examiner.cc | 4 +-- src/lib/ffmpeg_subtitle_stream.cc | 42 ++++++++++++++++++++++++---- src/lib/ffmpeg_subtitle_stream.h | 9 ++++-- src/lib/util.cc | 1 + 8 files changed, 68 insertions(+), 55 deletions(-) diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 3a42b169f..ad9096b92 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2015 Carl Hetherington 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 FFmpegContent::subtitles_during (ContentTimePeriod period, bool starting) const { - list d; - shared_ptr stream = subtitle_stream (); if (!stream) { - return d; - } - - /* XXX: inefficient */ - for (vector::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 (); } - return d; + return stream->subtitles_during (period, starting); } bool diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 76ba43567..d6edb2bdb 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2015 Carl Hetherington 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 diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 5dc06fa8e..a3d647cde 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -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 (); - _pending_subtitle_image.reset (); - _pending_subtitle_rect = optional > (); - } 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 (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); } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index b5bcdd358..0a0eea18a 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -67,10 +67,6 @@ private: void maybe_add_subtitle (); boost::shared_ptr deinterleave_audio (uint8_t** data, int size); - boost::optional _pending_subtitle_from; - boost::shared_ptr _pending_subtitle_image; - boost::optional > _pending_subtitle_rect; - std::list image_subtitles_during (ContentTimePeriod, bool starting) const; std::list text_subtitles_during (ContentTimePeriod, bool starting) const; diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc index e4f4e6f29..8afd4c164 100644 --- a/src/lib/ffmpeg_examiner.cc +++ b/src/lib/ffmpeg_examiner.cc @@ -152,11 +152,11 @@ FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr= 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 (); } 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; } diff --git a/src/lib/ffmpeg_subtitle_stream.cc b/src/lib/ffmpeg_subtitle_stream.cc index 66b587209..77a56e330 100644 --- a/src/lib/ffmpeg_subtitle_stream.cc +++ b/src/lib/ffmpeg_subtitle_stream.cc @@ -23,6 +23,8 @@ #include 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 ("From")), ContentTime (node->number_child ("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 (i.from.get ())); - node->add_child("To")->add_child_text (raw_convert (i.to.get ())); + for (map::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 (i->first.get ())); + node->add_child("To")->add_child_text (raw_convert (i->second.get ())); } } + +void +FFmpegSubtitleStream::add_subtitle (ContentTimePeriod period) +{ + DCPOMATIC_ASSERT (_subtitles.find (period.from) == _subtitles.end ()); + _subtitles[period.from] = period.to; +} + +list +FFmpegSubtitleStream::subtitles_during (ContentTimePeriod period, bool starting) const +{ + list d; + + /* XXX: inefficient */ + for (map::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::const_iterator i = _subtitles.find (from); + DCPOMATIC_ASSERT (i != _subtitles.end ()); + return i->second; +} diff --git a/src/lib/ffmpeg_subtitle_stream.h b/src/lib/ffmpeg_subtitle_stream.h index b16b825e7..3ed931b8c 100644 --- a/src/lib/ffmpeg_subtitle_stream.h +++ b/src/lib/ffmpeg_subtitle_stream.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2015 Carl Hetherington 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 periods; + void add_subtitle (ContentTimePeriod period); + std::list subtitles_during (ContentTimePeriod period, bool starting) const; + ContentTime find_subtitle_to (ContentTime from) const; + +private: + std::map _subtitles; }; diff --git a/src/lib/util.cc b/src/lib/util.cc index d8c754607..99d9ba2c4 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -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); } + -- 2.30.2