/*
- 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
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
/*
- 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
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) {
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);
}
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;
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;
}
#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().
: 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"))
{
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;
+}
/*
- 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
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;
};
fwrite (&info.size, sizeof (info.size), 1, file);
fwrite (info.hash.c_str(), 1, info.hash.size(), file);
}
+