Don't bother decoding video frames when we're seeking around trying to find subtitles.
authorCarl Hetherington <cth@carlh.net>
Wed, 13 May 2015 09:15:26 +0000 (10:15 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 13 May 2015 09:15:26 +0000 (10:15 +0100)
17 files changed:
src/lib/audio_decoder.cc
src/lib/dcp_decoder.cc
src/lib/dcp_decoder.h
src/lib/dcp_subtitle_decoder.cc
src/lib/dcp_subtitle_decoder.h
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/sndfile_decoder.cc
src/lib/sndfile_decoder.h
src/lib/subrip_decoder.cc
src/lib/subrip_decoder.h
src/lib/subtitle_decoder.cc
src/lib/video_decoder.cc
test/audio_decoder_test.cc

index 22376e3e36bb2c19d19fb77f82000f3a7cba987e..f6133947a0e4ad7e6ef57d38cd063102eb682411 100644 (file)
@@ -80,10 +80,10 @@ AudioDecoder::get_audio (AudioFrame frame, AudioFrame length, bool accurate)
         */
        if (accurate) {
                /* Keep stuffing data into _decoded_audio until we have enough data, or the subclass does not want to give us any more */
         */
        if (accurate) {
                /* Keep stuffing data into _decoded_audio until we have enough data, or the subclass does not want to give us any more */
-               while ((_decoded_audio.frame > frame || (_decoded_audio.frame + _decoded_audio.audio->frames()) < end) && !pass ()) {}
+               while ((_decoded_audio.frame > frame || (_decoded_audio.frame + _decoded_audio.audio->frames()) < end) && !pass (PASS_REASON_AUDIO)) {}
                decoded_offset = frame - _decoded_audio.frame;
        } else {
                decoded_offset = frame - _decoded_audio.frame;
        } else {
-               while (_decoded_audio.audio->frames() < length && !pass ()) {}
+               while (_decoded_audio.audio->frames() < length && !pass (PASS_REASON_AUDIO)) {}
                /* Use decoded_offset of 0, as we don't really care what frames we return */
        }
 
                /* Use decoded_offset of 0, as we don't really care what frames we return */
        }
 
index ab0df8a8641d660315be9cc7068a6243896c0ba9..3bfbd7720c9e04cf99b951db455e306bd2be3cb9 100644 (file)
@@ -55,7 +55,7 @@ DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c)
 }
 
 bool
 }
 
 bool
-DCPDecoder::pass ()
+DCPDecoder::pass (PassReason)
 {
        if (_reel == _reels.end () || !_dcp_content->can_be_played ()) {
                return true;
 {
        if (_reel == _reels.end () || !_dcp_content->can_be_played ()) {
                return true;
index 20ca2bb6774a5263caad2824e56cb7783418e9ca..3a05325c744ec195ed0b3320193840804b4e4dc1 100644 (file)
@@ -38,8 +38,9 @@ public:
        DCPDecoder (boost::shared_ptr<const DCPContent>);
 
 private:
        DCPDecoder (boost::shared_ptr<const DCPContent>);
 
 private:
+       bool pass (PassReason);
        void seek (ContentTime t, bool accurate);
        void seek (ContentTime t, bool accurate);
-       bool pass ();
+       
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
        std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod, bool starting) const;
 
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
        std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod, bool starting) const;
 
index 236e999969e243e9ac5eae4f062348d050d78111..93a122590749b848d3eea519177c5f8bd61ce56a 100644 (file)
@@ -46,7 +46,7 @@ DCPSubtitleDecoder::seek (ContentTime time, bool accurate)
 }
 
 bool
 }
 
 bool
-DCPSubtitleDecoder::pass ()
+DCPSubtitleDecoder::pass (PassReason)
 {
        if (_next == _subtitles.end ()) {
                return true;
 {
        if (_next == _subtitles.end ()) {
                return true;
index 9a16fb7c850dcf92e57ddf1ee7a80f8372386dc1..52e40041683f61119a7445dc0fcc11d1ff1b9387 100644 (file)
@@ -28,8 +28,8 @@ public:
        DCPSubtitleDecoder (boost::shared_ptr<const DCPSubtitleContent>);
 
 protected:
        DCPSubtitleDecoder (boost::shared_ptr<const DCPSubtitleContent>);
 
 protected:
+       bool pass (PassReason);
        void seek (ContentTime time, bool accurate);
        void seek (ContentTime time, bool accurate);
-       bool pass ();
 
 private:
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
 
 private:
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
index c1b8598650357b6a9978efdbcc28eb495ba69511..0703a542686933e3065f3b3cd5a343498ef0cebd 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
-    Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-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
 
     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
@@ -41,6 +41,7 @@ public:
        virtual ~Decoder () {}
 
 protected:     
        virtual ~Decoder () {}
 
 protected:     
+
        /** Seek so that the next pass() will yield the next thing
         *  (video/sound frame, subtitle etc.) at or after the requested
         *  time.  Pass accurate = true to try harder to ensure that, at worst,
        /** Seek so that the next pass() will yield the next thing
         *  (video/sound frame, subtitle etc.) at or after the requested
         *  time.  Pass accurate = true to try harder to ensure that, at worst,
@@ -50,7 +51,14 @@ protected:
         *  it may seek to just the right spot.
         */
        virtual void seek (ContentTime time, bool accurate) = 0;
         *  it may seek to just the right spot.
         */
        virtual void seek (ContentTime time, bool accurate) = 0;
-       virtual bool pass () = 0;
+
+       enum PassReason {
+               PASS_REASON_VIDEO,
+               PASS_REASON_AUDIO,
+               PASS_REASON_SUBTITLE
+       };
+       
+       virtual bool pass (PassReason reason) = 0;
 };
 
 #endif
 };
 
 #endif
index a3d647cdecd1e3bf3d2db8ce8891bbb8357ed0e5..6122a547ed3b9f816345b0f092ccdc95c403ab88 100644 (file)
@@ -132,7 +132,7 @@ FFmpegDecoder::flush ()
 }
 
 bool
 }
 
 bool
-FFmpegDecoder::pass ()
+FFmpegDecoder::pass (PassReason reason)
 {
        int r = av_read_frame (_format_context, &_packet);
 
 {
        int r = av_read_frame (_format_context, &_packet);
 
@@ -153,12 +153,13 @@ FFmpegDecoder::pass ()
        }
 
        int const si = _packet.stream_index;
        }
 
        int const si = _packet.stream_index;
+       shared_ptr<const FFmpegContent> fc = _ffmpeg_content;
 
 
-       if (si == _video_stream && !_ignore_video) {
+       if (si == _video_stream && !_ignore_video && reason != PASS_REASON_SUBTITLE) {
                decode_video_packet ();
                decode_video_packet ();
-       } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si)) {
+       } else if (fc->audio_stream() && fc->audio_stream()->uses_index (_format_context, si) && reason != PASS_REASON_SUBTITLE) {
                decode_audio_packet ();
                decode_audio_packet ();
-       } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si)) {
+       } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index (_format_context, si)) {
                decode_subtitle_packet ();
        }
 
                decode_subtitle_packet ();
        }
 
index 0a0eea18a7380ee9423d5b0b8076908a65654e4b..616fa88dd42f3f40f3ab993785ef89fe89a0e075 100644 (file)
@@ -53,8 +53,8 @@ public:
 private:
        friend struct ::ffmpeg_pts_offset_test;
 
 private:
        friend struct ::ffmpeg_pts_offset_test;
 
+       bool pass (PassReason reason);
        void seek (ContentTime time, bool);
        void seek (ContentTime time, bool);
-       bool pass ();
        void flush ();
 
        AVSampleFormat audio_sample_format () const;
        void flush ();
 
        AVSampleFormat audio_sample_format () const;
index 78201fc23d9d7b838d30ed6edbb0d09e4c258369..250c8f845b6c2f10141aac2c3c46dd2e7fe55dbd 100644 (file)
@@ -43,7 +43,7 @@ ImageDecoder::ImageDecoder (shared_ptr<const ImageContent> c)
 }
 
 bool
 }
 
 bool
-ImageDecoder::pass ()
+ImageDecoder::pass (PassReason)
 {
        if (_video_position >= _image_content->video_length().frames (_image_content->video_frame_rate ())) {
                return true;
 {
        if (_video_position >= _image_content->video_length().frames (_image_content->video_frame_rate ())) {
                return true;
index 242f69477826a499d915505cd0b9486808aba68d..ec90051daf8e43c45a565d69d9ad43f212636c52 100644 (file)
@@ -34,10 +34,9 @@ public:
                return _image_content;
        }
 
                return _image_content;
        }
 
-       void seek (ContentTime, bool);
-
 private:
 private:
-       bool pass ();
+       bool pass (PassReason);
+       void seek (ContentTime, bool);
        
        boost::shared_ptr<const ImageContent> _image_content;
        boost::shared_ptr<ImageProxy> _image;
        
        boost::shared_ptr<const ImageContent> _image_content;
        boost::shared_ptr<ImageProxy> _image;
index 602014d5883d2dba1381588bb44a7036debc9c96..09059a8b0717adbf2b8df12b11c6ec48a941477b 100644 (file)
@@ -65,7 +65,7 @@ SndfileDecoder::~SndfileDecoder ()
 }
 
 bool
 }
 
 bool
-SndfileDecoder::pass ()
+SndfileDecoder::pass (PassReason)
 {
        if (_remaining == 0) {
                return true;
 {
        if (_remaining == 0) {
                return true;
index 5ebe1da7b251852ee523df1e24fc9597406570f2..68c8633a0d604df5e7e6aa3f19dfc07993422d2e 100644 (file)
@@ -30,14 +30,13 @@ public:
        SndfileDecoder (boost::shared_ptr<const SndfileContent> c);
        ~SndfileDecoder ();
 
        SndfileDecoder (boost::shared_ptr<const SndfileContent> c);
        ~SndfileDecoder ();
 
-       void seek (ContentTime, bool);
-
        int audio_channels () const;
        ContentTime audio_length () const;
        int audio_frame_rate () const;
 
 private:
        int audio_channels () const;
        ContentTime audio_length () const;
        int audio_frame_rate () const;
 
 private:
-       bool pass ();
+       bool pass (PassReason);
+       void seek (ContentTime, bool);
        
        boost::shared_ptr<const SndfileContent> _sndfile_content;
        SNDFILE* _sndfile;
        
        boost::shared_ptr<const SndfileContent> _sndfile_content;
        SNDFILE* _sndfile;
index bef48ba78458203c65c726be0dba341f8e46b34b..6ed2e5254fb5c9be4847fd00c3df4eb31a42b865 100644 (file)
@@ -48,7 +48,7 @@ SubRipDecoder::seek (ContentTime time, bool accurate)
 }
 
 bool
 }
 
 bool
-SubRipDecoder::pass ()
+SubRipDecoder::pass (PassReason)
 {
        if (_next >= _subtitles.size ()) {
                return true;
 {
        if (_next >= _subtitles.size ()) {
                return true;
index 876f763d3a5ffe1c39f1952226250eccb95db4c6..264ca88996b2b93dafd4b1521f4c4f3a98f8f609 100644 (file)
@@ -32,7 +32,7 @@ public:
 
 protected:
        void seek (ContentTime time, bool accurate);
 
 protected:
        void seek (ContentTime time, bool accurate);
-       bool pass ();
+       bool pass (PassReason);
 
 private:
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
 
 private:
        std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
index ac9a67e33f18405eb0704cc63c587f3fc866f379..edb291ab8dc65924c1f314a944fff21b0e1fd825 100644 (file)
@@ -70,7 +70,7 @@ SubtitleDecoder::get (list<T> const & subs, list<ContentTimePeriod> const & sp,
         *  (a) give us what we want, or
         *  (b) hit the end of the decoder.
         */
         *  (a) give us what we want, or
         *  (b) hit the end of the decoder.
         */
-       while (!pass() && (subs.empty() || (subs.back().period().to < sp.back().to))) {}
+       while (!pass(PASS_REASON_SUBTITLE) && (subs.empty() || (subs.back().period().to < sp.back().to))) {}
 
        /* Now look for what we wanted in the data we have collected */
        /* XXX: inefficient */
 
        /* Now look for what we wanted in the data we have collected */
        /* XXX: inefficient */
@@ -82,6 +82,8 @@ SubtitleDecoder::get (list<T> const & subs, list<ContentTimePeriod> const & sp,
                }
        }
 
                }
        }
 
+       /* XXX: should clear out _decoded_* at some point */
+
        return out;
 }
 
        return out;
 }
 
index b7cf1641b57d6b999c7c62b3c05f405e1f7b7075..31dc3cdc204836e821b385b0280d2c13f2defb31 100644 (file)
@@ -96,7 +96,7 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                                break;
                        }
 
                                break;
                        }
 
-                       if (pass ()) {
+                       if (pass (PASS_REASON_VIDEO)) {
                                /* The decoder has nothing more for us */
                                break;
                        }
                                /* The decoder has nothing more for us */
                                break;
                        }
@@ -113,7 +113,7 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                dec = decoded_video (frame);
        } else {
                /* Any frame will do: use the first one that comes out of pass() */
                dec = decoded_video (frame);
        } else {
                /* Any frame will do: use the first one that comes out of pass() */
-               while (_decoded_video.empty() && !pass ()) {}
+               while (_decoded_video.empty() && !pass (PASS_REASON_VIDEO)) {}
                if (!_decoded_video.empty ()) {
                        dec.push_back (_decoded_video.front ());
                }
                if (!_decoded_video.empty ()) {
                        dec.push_back (_decoded_video.front ());
                }
@@ -237,7 +237,7 @@ VideoDecoder::video (shared_ptr<const ImageProxy> image, VideoFrame frame)
        if (_ignore_video) {
                return;
        }
        if (_ignore_video) {
                return;
        }
-       
+
        /* We may receive the same frame index twice for 3D, and we need to know
           when that happens.
        */
        /* We may receive the same frame index twice for 3D, and we need to know
           when that happens.
        */
index a14e2f9be0ace14299c1c6d756828699af53236c..b1f672356415f9c62b38db16bfdd9f955da12c72 100644 (file)
@@ -40,7 +40,7 @@ public:
                , _position (0)
        {}
 
                , _position (0)
        {}
 
-       bool pass ()
+       bool pass (PassReason)
        {
                AudioFrame const N = min (
                        AudioFrame (2000),
        {
                AudioFrame const N = min (
                        AudioFrame (2000),