summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-05-22 16:53:38 +0100
committerCarl Hetherington <cth@carlh.net>2014-05-22 16:53:38 +0100
commit24d54ea7fe1ba128cf8d3521d6738fc73a7c623e (patch)
tree7c3674e34b30f81334dc8f35a91d3cbb31b7ff9d /src/lib
parentd156fe45ee21fc416ce6b9e43ceed95bf42fde41 (diff)
Basics of noting subtitle times in FFmpegSubtitleStreams.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/dcpomatic_time.h4
-rw-r--r--src/lib/ffmpeg.cc12
-rw-r--r--src/lib/ffmpeg_content.cc15
-rw-r--r--src/lib/ffmpeg_content.h3
-rw-r--r--src/lib/ffmpeg_decoder.cc8
-rw-r--r--src/lib/ffmpeg_examiner.cc24
-rw-r--r--src/lib/ffmpeg_subtitle_stream.h2
-rw-r--r--src/lib/subrip_content.cc7
-rw-r--r--src/lib/subrip_content.h2
-rw-r--r--src/lib/subrip_decoder.cc4
-rw-r--r--src/lib/subtitle_content.h6
-rw-r--r--src/lib/subtitle_decoder.cc10
-rw-r--r--src/lib/subtitle_decoder.h4
-rw-r--r--src/lib/util.cc13
-rw-r--r--src/lib/util.h2
15 files changed, 94 insertions, 22 deletions
diff --git a/src/lib/dcpomatic_time.h b/src/lib/dcpomatic_time.h
index e56f58c4b..2a871889a 100644
--- a/src/lib/dcpomatic_time.h
+++ b/src/lib/dcpomatic_time.h
@@ -157,6 +157,10 @@ public:
ContentTime from;
ContentTime to;
+
+ ContentTimePeriod operator+ (ContentTime const & o) const {
+ return ContentTimePeriod (from + o, to + o);
+ }
};
class DCPTime : public Time
diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc
index ec7ec452e..8505626df 100644
--- a/src/lib/ffmpeg.cc
+++ b/src/lib/ffmpeg.cc
@@ -148,13 +148,13 @@ FFmpeg::setup_decoders ()
AVCodecContext* context = _format_context->streams[i]->codec;
AVCodec* codec = avcodec_find_decoder (context->codec_id);
- if (codec == 0) {
- throw DecodeError (N_("could not find decoder"));
- }
-
- if (avcodec_open2 (context, codec, 0) < 0) {
- throw DecodeError (N_("could not open decoder"));
+ if (codec) {
+ if (avcodec_open2 (context, codec, 0) < 0) {
+ throw DecodeError (N_("could not open decoder"));
+ }
}
+
+ /* We are silently ignoring any failures to find suitable decoders here */
}
}
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index a191959fc..2b507ab37 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -392,3 +392,18 @@ FFmpegContent::audio_analysis_path () const
p /= name;
return p;
}
+
+bool
+FFmpegContent::has_subtitle_during (ContentTimePeriod period) const
+{
+ shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
+
+ /* XXX: inefficient */
+ for (vector<ContentTimePeriod>::const_iterator i = stream->periods.begin(); i != stream->periods.end(); ++i) {
+ if (i->from <= period.to && i->to >= period.from) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index 6f4980dc7..1a30fb606 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -73,6 +73,9 @@ public:
void set_audio_mapping (AudioMapping);
boost::filesystem::path audio_analysis_path () const;
+ /* SubtitleContent */
+ bool has_subtitle_during (ContentTimePeriod) const;
+
void set_filters (std::vector<Filter const *> const &);
std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const {
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 7d152e490..d668deb6f 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -62,6 +62,7 @@ using dcp::Size;
FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log)
: VideoDecoder (c)
, AudioDecoder (c)
+ , SubtitleDecoder (c)
, FFmpeg (c)
, _log (log)
, _subtitle_codec_context (0)
@@ -516,12 +517,7 @@ FFmpegDecoder::decode_subtitle_packet ()
/* Subtitle PTS (within the source, not taking into account any of the
source that we may have chopped off for the DCP)
*/
- ContentTime packet_time = ContentTime::from_seconds (static_cast<double> (sub.pts) / AV_TIME_BASE) + _pts_offset;
-
- ContentTimePeriod period (
- packet_time + ContentTime::from_seconds (sub.start_display_time / 1e3),
- packet_time + ContentTime::from_seconds (sub.end_display_time / 1e3)
- );
+ ContentTimePeriod period = subtitle_period (sub) + _pts_offset;
AVSubtitleRect const * rect = sub.rects[0];
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 013799d03..df12830f8 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -25,6 +25,7 @@ extern "C" {
#include "ffmpeg_content.h"
#include "ffmpeg_audio_stream.h"
#include "ffmpeg_subtitle_stream.h"
+#include "util.h"
#include "i18n.h"
@@ -63,8 +64,15 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c)
}
}
- /* Run through until we find the first audio (for each stream) and video */
-
+ /* Run through until we find:
+ * - the first video.
+ * - the first audio for each stream.
+ * - the subtitle periods for each stream.
+ *
+ * We have to note subtitle periods as otherwise we have no way of knowing
+ * where we should look for subtitles (video and audio are always present,
+ * so they are ok).
+ */
while (1) {
int r = av_read_frame (_format_context, &_packet);
if (r < 0) {
@@ -122,7 +130,17 @@ FFmpegExaminer::audio_packet (AVCodecContext* context, shared_ptr<FFmpegAudioStr
void
FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr<FFmpegSubtitleStream> stream)
{
-
+ int frame_finished;
+ AVSubtitle sub;
+ if (avcodec_decode_subtitle2 (context, &sub, &frame_finished, &_packet) >= 0 && frame_finished) {
+ ContentTimePeriod const period = subtitle_period (sub);
+ if (sub.num_rects == 0 && !stream->periods.empty () && stream->periods.back().to > period.from) {
+ /* Finish the last subtitle */
+ stream->periods.back().to = period.from;
+ } else if (sub.num_rects == 1) {
+ stream->periods.push_back (period);
+ }
+ }
}
optional<ContentTime>
diff --git a/src/lib/ffmpeg_subtitle_stream.h b/src/lib/ffmpeg_subtitle_stream.h
index 76c71f016..b16b825e7 100644
--- a/src/lib/ffmpeg_subtitle_stream.h
+++ b/src/lib/ffmpeg_subtitle_stream.h
@@ -30,5 +30,7 @@ public:
FFmpegSubtitleStream (cxml::ConstNodePtr);
void as_xml (xmlpp::Node *) const;
+
+ std::vector<ContentTimePeriod> periods;
};
diff --git a/src/lib/subrip_content.cc b/src/lib/subrip_content.cc
index 892578ade..d7825f518 100644
--- a/src/lib/subrip_content.cc
+++ b/src/lib/subrip_content.cc
@@ -109,3 +109,10 @@ SubRipContent::identifier () const
return s.str ();
}
+
+bool
+SubRipContent::has_subtitle_during (ContentTimePeriod) const
+{
+ /* XXX */
+ return false;
+}
diff --git a/src/lib/subrip_content.h b/src/lib/subrip_content.h
index 5688f81d5..91de08350 100644
--- a/src/lib/subrip_content.h
+++ b/src/lib/subrip_content.h
@@ -37,6 +37,8 @@ public:
DCPTime full_length () const;
std::string identifier () const;
+ bool has_subtitle_during (ContentTimePeriod) const;
+
private:
DCPTime _length;
};
diff --git a/src/lib/subrip_decoder.cc b/src/lib/subrip_decoder.cc
index cdc8ccbfe..e832c2d84 100644
--- a/src/lib/subrip_decoder.cc
+++ b/src/lib/subrip_decoder.cc
@@ -19,12 +19,14 @@
#include <dcp/subtitle_string.h>
#include "subrip_decoder.h"
+#include "subrip_content.h"
using std::list;
using boost::shared_ptr;
SubRipDecoder::SubRipDecoder (shared_ptr<const SubRipContent> content)
- : SubRip (content)
+ : SubtitleDecoder (content)
+ , SubRip (content)
, _next (0)
{
diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h
index 92d072ca6..cc91a2df8 100644
--- a/src/lib/subtitle_content.h
+++ b/src/lib/subtitle_content.h
@@ -36,9 +36,11 @@ public:
SubtitleContent (boost::shared_ptr<const Film>, boost::filesystem::path);
SubtitleContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int version);
SubtitleContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
-
+
void as_xml (xmlpp::Node *) const;
+ virtual bool has_subtitle_during (ContentTimePeriod) const = 0;
+
void set_subtitle_x_offset (double);
void set_subtitle_y_offset (double);
void set_subtitle_scale (double);
@@ -57,7 +59,7 @@ public:
boost::mutex::scoped_lock lm (_mutex);
return _subtitle_scale;
}
-
+
private:
friend class ffmpeg_pts_offset_test;
diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc
index d114df979..13cf481c8 100644
--- a/src/lib/subtitle_decoder.cc
+++ b/src/lib/subtitle_decoder.cc
@@ -19,13 +19,15 @@
#include <boost/shared_ptr.hpp>
#include "subtitle_decoder.h"
+#include "subtitle_content.h"
using std::list;
using std::cout;
using boost::shared_ptr;
using boost::optional;
-SubtitleDecoder::SubtitleDecoder ()
+SubtitleDecoder::SubtitleDecoder (shared_ptr<const SubtitleContent> c)
+ : _subtitle_content (c)
{
}
@@ -49,6 +51,10 @@ template <class T>
list<shared_ptr<T> >
SubtitleDecoder::get (list<shared_ptr<T> > const & subs, ContentTimePeriod period)
{
+ if (!_subtitle_content->has_subtitle_during (period)) {
+ return list<shared_ptr<T> > ();
+ }
+
if (subs.empty() || period.from < subs.front()->period().from || period.to > (subs.back()->period().to + ContentTime::from_seconds (10))) {
/* Either we have no decoded data, or what we do have is a long way from what we want: seek */
seek (period.from, true);
@@ -57,8 +63,6 @@ SubtitleDecoder::get (list<shared_ptr<T> > const & subs, ContentTimePeriod perio
/* Now enough pass() calls will either:
* (a) give us what we want, or
* (b) hit the end of the decoder.
- *
- * XXX: with subs being sparse, this may need more care...
*/
while (!pass() && (subs.empty() || (subs.front()->period().from > period.from || period.to < subs.back()->period().to))) {}
diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h
index fea4ab973..164c151e6 100644
--- a/src/lib/subtitle_decoder.h
+++ b/src/lib/subtitle_decoder.h
@@ -33,7 +33,7 @@ class Image;
class SubtitleDecoder : public virtual Decoder
{
public:
- SubtitleDecoder ();
+ SubtitleDecoder (boost::shared_ptr<const SubtitleContent>);
std::list<boost::shared_ptr<ContentImageSubtitle> > get_image_subtitles (ContentTimePeriod period);
std::list<boost::shared_ptr<ContentTextSubtitle> > get_text_subtitles (ContentTimePeriod period);
@@ -50,6 +50,8 @@ protected:
private:
template <class T>
std::list<boost::shared_ptr<T> > get (std::list<boost::shared_ptr<T> > const & subs, ContentTimePeriod period);
+
+ boost::shared_ptr<const SubtitleContent> _subtitle_content;
};
#endif
diff --git a/src/lib/util.cc b/src/lib/util.cc
index 14dfd1fa5..6e370f577 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -982,3 +982,16 @@ ScopedTemporary::close ()
_open = 0;
}
}
+
+ContentTimePeriod
+subtitle_period (AVSubtitle const & sub)
+{
+ ContentTime const packet_time = ContentTime::from_seconds (static_cast<double> (sub.pts) / AV_TIME_BASE);
+
+ ContentTimePeriod period (
+ packet_time + ContentTime::from_seconds (sub.start_display_time / 1e3),
+ packet_time + ContentTime::from_seconds (sub.end_display_time / 1e3)
+ );
+
+ return period;
+}
diff --git a/src/lib/util.h b/src/lib/util.h
index 58c2771b7..196a6e8f9 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -59,6 +59,7 @@ namespace libdcp {
}
class Job;
+struct AVSubtitle;
extern std::string seconds_to_hms (int);
extern std::string seconds_to_approximate_hms (int);
@@ -91,6 +92,7 @@ extern int get_optional_int (std::multimap<std::string, std::string> const & kv,
extern std::string get_optional_string (std::multimap<std::string, std::string> const & kv, std::string k);
extern void* wrapped_av_malloc (size_t);
extern int64_t divide_with_round (int64_t a, int64_t b);
+extern ContentTimePeriod subtitle_period (AVSubtitle const &);
/** @class Socket
* @brief A class to wrap a boost::asio::ip::tcp::socket with some things