Cope with offsets between video/audio/subtitle data in a muxed file.
authorCarl Hetherington <cth@carlh.net>
Sat, 19 Nov 2016 00:31:37 +0000 (00:31 +0000)
committerCarl Hetherington <cth@carlh.net>
Sat, 19 Nov 2016 00:51:05 +0000 (00:51 +0000)
13 files changed:
src/lib/audio_decoder_stream.cc
src/lib/dcp_decoder.cc
src/lib/dcp_subtitle_decoder.cc
src/lib/decoder.cc
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/image_decoder.cc
src/lib/image_decoder.h
src/lib/subtitle_decoder.cc
src/lib/text_subtitle_decoder.cc
src/lib/video_decoder.cc
src/lib/video_mxf_decoder.cc

index c14dc654e904cd611d961e4941f1356a1f8cdc17..7e8e304ef63e83e4d44d9556dfe9ee2f4a0eb969 100644 (file)
@@ -86,7 +86,7 @@ AudioDecoderStream::get (Frame frame, Frame length, bool accurate)
        }
 
        if (missing) {
-               _decoder->maybe_seek (ContentTime::from_frames (*missing, _content->resampled_frame_rate()), accurate);
+               _decoder->maybe_seek_audio (ContentTime::from_frames (*missing, _content->resampled_frame_rate()), accurate);
        }
 
        /* Offset of the data that we want from the start of _decoded.audio
index 38c2a7ccfa2bdcab2bb96ecf850eed4de53ba5e4..4f17bdb3b9293b1c6359e39b90a018ae4a677776 100644 (file)
@@ -163,7 +163,7 @@ DCPDecoder::pass (PassReason reason, bool)
                }
        }
 
-       _position = _next;
+       _video_position = _audio_position = _subtitle_position = _next;
        _next += ContentTime::from_frames (1, vfr);
 
        if ((*_reel)->main_picture ()) {
index d4e1a7fa29ce7d1cacf061c95256268f21ddfffb..c67133012df9e3998bb1187ceb17bb0e96839905 100644 (file)
@@ -79,7 +79,7 @@ DCPSubtitleDecoder::pass (PassReason, bool)
        }
 
        subtitle->give_text (p, s);
-       _position = p.from;
+       _subtitle_position = p.from;
 
        return false;
 }
index cba674d0415ed9df573c5fb955cd3ea72104392b..50356da788e84c018f175e6c611a6d5a6313f52b 100644 (file)
 */
 
 #include "decoder.h"
+#include <iostream>
+
+using std::cout;
+using boost::optional;
 
 void
-Decoder::maybe_seek (ContentTime time, bool accurate)
+Decoder::maybe_seek (optional<ContentTime>& position, ContentTime time, bool accurate)
 {
-       if (!_position) {
+       if (!position) {
                /* A seek has just happened */
                return;
        }
 
-       if (time >= *_position && time < (*_position + ContentTime::from_seconds(1))) {
+       if (time >= *position && time < (*position + ContentTime::from_seconds(1))) {
                /* No need to seek: caller should just pass() */
                return;
        }
 
-       _position.reset ();
+       position.reset ();
        seek (time, accurate);
 }
+
+void
+Decoder::maybe_seek_video (ContentTime time, bool accurate)
+{
+       maybe_seek (_video_position, time, accurate);
+}
+
+void
+Decoder::maybe_seek_audio (ContentTime time, bool accurate)
+{
+       maybe_seek (_audio_position, time, accurate);
+}
+
+void
+Decoder::maybe_seek_subtitle (ContentTime time, bool accurate)
+{
+       maybe_seek (_subtitle_position, time, accurate);
+}
index 84661ee8c4a1637b79a2796cce5ad1083f142e44..d2302d7a20d3057bcfde04fd9df1b11934f45420 100644 (file)
@@ -52,7 +52,9 @@ public:
                PASS_REASON_SUBTITLE
        };
 
-       void maybe_seek (ContentTime time, bool accurate);
+       void maybe_seek_video (ContentTime time, bool accurate);
+       void maybe_seek_audio (ContentTime time, bool accurate);
+       void maybe_seek_subtitle (ContentTime time, bool accurate);
 
        /** @return true if this decoder has already returned all its data and will give no more */
        virtual bool pass (PassReason, bool accurate) = 0;
@@ -63,7 +65,9 @@ public:
        virtual void reset () {}
 
 protected:
-       boost::optional<ContentTime> _position;
+       boost::optional<ContentTime> _video_position;
+       boost::optional<ContentTime> _audio_position;
+       boost::optional<ContentTime> _subtitle_position;
 
 private:
        /** Seek so that the next pass() will yield the next thing
@@ -75,6 +79,7 @@ private:
         *  it may seek to just the right spot.
         */
        virtual void seek (ContentTime time, bool accurate) = 0;
+       void maybe_seek (boost::optional<ContentTime>& position, ContentTime time, bool accurate);
 };
 
 #endif
index 253272e9638a3387f529b7d5548eff86321ddaf6..8f196542a1ea5b10005598c04fcd7290643f0235 100644 (file)
@@ -425,7 +425,7 @@ FFmpegDecoder::decode_audio_packet ()
                                LOG_WARNING ("Crazy timestamp %s", to_string (ct));
                        }
 
-                       update_position (ct);
+                       update_position (_audio_position, ct);
 
                        /* Give this data provided there is some, and its time is sane */
                        if (ct >= ContentTime() && data->frames() > 0) {
@@ -478,7 +478,7 @@ FFmpegDecoder::decode_video_packet ()
                                shared_ptr<ImageProxy> (new RawImageProxy (image)),
                                llrint (pts * _ffmpeg_content->active_video_frame_rate ())
                                );
-                       update_position (ContentTime::from_seconds (pts));
+                       update_position (_video_position, ContentTime::from_seconds (pts));
                } else {
                        LOG_WARNING_NC ("Dropping frame without PTS");
                }
@@ -509,7 +509,7 @@ FFmpegDecoder::decode_subtitle_packet ()
        FFmpegSubtitlePeriod sub_period = subtitle_period (sub);
        ContentTimePeriod period;
        period.from = sub_period.from + _pts_offset;
-       update_position (period.from);
+       update_position (_subtitle_position, period.from);
        if (sub_period.to) {
                /* We already know the subtitle period `to' time */
                period.to = sub_period.to.get() + _pts_offset;
@@ -646,14 +646,14 @@ FFmpegDecoder::decode_ass_subtitle (string ass, ContentTimePeriod period)
 }
 
 void
-FFmpegDecoder::update_position (ContentTime p)
+FFmpegDecoder::update_position (optional<ContentTime>& current, ContentTime p)
 {
-       /* _position should err on the side of being too big, as then there is less
-          chance that we will erroneously decide not to seek when _position > request.
+       /* current should err on the side of being too big, as then there is less
+          chance that we will erroneously decide not to seek when current > request.
        */
-       if (!_position) {
-               _position = p;
+       if (!current) {
+               current = p;
        } else {
-               _position = max (*_position, p);
+               current = max (*current, p);
        }
 }
index dfe1f26940c59d6477f96bfb217dd0db01d3681c..d6f50cd43511769d2089e79654bcd8d22aa18aa5 100644 (file)
@@ -52,7 +52,7 @@ private:
        bool pass (PassReason, bool accurate);
        void seek (ContentTime time, bool);
        void flush ();
-       void update_position (ContentTime p);
+       void update_position (boost::optional<ContentTime>& current, ContentTime p);
 
        AVSampleFormat audio_sample_format (boost::shared_ptr<FFmpegAudioStream> stream) const;
        int bytes_per_audio_sample (boost::shared_ptr<FFmpegAudioStream> stream) const;
index 41a4949ba34bc8397db266d746b7e08163e3b252..7270c97829acf218abd0318b53e9e6f21855d869 100644 (file)
@@ -39,7 +39,7 @@ using dcp::Size;
 
 ImageDecoder::ImageDecoder (shared_ptr<const ImageContent> c, shared_ptr<Log> log)
        : _image_content (c)
-       , _video_position (0)
+       , _frame_video_position (0)
 {
        video.reset (new VideoDecoder (this, c, log));
 }
@@ -47,13 +47,13 @@ ImageDecoder::ImageDecoder (shared_ptr<const ImageContent> c, shared_ptr<Log> lo
 bool
 ImageDecoder::pass (PassReason, bool)
 {
-       if (_video_position >= _image_content->video->length()) {
+       if (_frame_video_position >= _image_content->video->length()) {
                return true;
        }
 
        if (!_image_content->still() || !_image) {
                /* Either we need an image or we are using moving images, so load one */
-               boost::filesystem::path path = _image_content->path (_image_content->still() ? 0 : _video_position);
+               boost::filesystem::path path = _image_content->path (_image_content->still() ? 0 : _frame_video_position);
                if (valid_j2k_file (path)) {
                        AVPixelFormat pf;
                        if (_image_content->video->colour_conversion()) {
@@ -72,9 +72,9 @@ ImageDecoder::pass (PassReason, bool)
                }
        }
 
-       _position = ContentTime::from_frames (_video_position, _image_content->active_video_frame_rate ());
-       video->give (_image, _video_position);
-       ++_video_position;
+       _video_position = ContentTime::from_frames (_frame_video_position, _image_content->active_video_frame_rate ());
+       video->give (_image, _frame_video_position);
+       ++_frame_video_position;
        return false;
 }
 
@@ -82,5 +82,5 @@ void
 ImageDecoder::seek (ContentTime time, bool accurate)
 {
        video->seek (time, accurate);
-       _video_position = time.frames_round (_image_content->active_video_frame_rate ());
+       _frame_video_position = time.frames_round (_image_content->active_video_frame_rate ());
 }
index 9b8cf73bbba6461a5da786d312338b35c25144de..d023636bfe433138db3be83162936a0cd2a1b41d 100644 (file)
@@ -39,5 +39,5 @@ private:
 
        boost::shared_ptr<const ImageContent> _image_content;
        boost::shared_ptr<ImageProxy> _image;
-       Frame _video_position;
+       Frame _frame_video_position;
 };
index 4be5c96b36c7b28b8009e1bb850d9dc271ffd5d3..020a0383c2db81b8c41e6419ed5cfb2ec28f320b 100644 (file)
@@ -104,7 +104,7 @@ SubtitleDecoder::get (list<T> const & subs, list<ContentTimePeriod> const & sp,
 
        /* Suggest to our parent decoder that it might want to seek if we haven't got what we're being asked for */
        if (missing) {
-               _parent->maybe_seek (*missing, true);
+               _parent->maybe_seek_subtitle (*missing, true);
        }
 
        /* Now enough pass() calls will either:
index e29bf580992f534d4056e4780fa0b7008d86b915..5f55451088e9b17472b70c0ff304c26c8eb1fd99 100644 (file)
@@ -68,7 +68,7 @@ TextSubtitleDecoder::pass (PassReason, bool)
 
        ContentTimePeriod const p = content_time_period (_subtitles[_next]);
        subtitle->give_text (p, _subtitles[_next]);
-       _position = p.from;
+       _subtitle_position = p.from;
 
        ++_next;
        return false;
index f240640d02ad4858e686c8ff55b88ab487e4c6fe..e3755e44f0b02881577b1eb83c3fe0819ee3b311 100644 (file)
@@ -99,7 +99,7 @@ VideoDecoder::get (Frame frame, bool accurate)
                        */
                        seek_frame *= 2;
                }
-               _parent->maybe_seek (ContentTime::from_frames (seek_frame, _content->active_video_frame_rate()), accurate);
+               _parent->maybe_seek_video (ContentTime::from_frames (seek_frame, _content->active_video_frame_rate()), accurate);
        }
 
        /* Work out the number of frames that we should return; we
index 84aec869a2a2292c6883e97a9590622524072c5b..321728f58e0e8cd3c2ebfd7649a9e562a0f70069 100644 (file)
@@ -89,7 +89,7 @@ VideoMXFDecoder::pass (PassReason, bool)
                        );
        }
 
-       _position = _next;
+       _video_position = _next;
        _next += ContentTime::from_frames (1, vfr);
        return false;
 }