Remove FFmpegDecoder minimal_run and care on seeking, as the VideoDecoder/AudioDecode...
authorCarl Hetherington <cth@carlh.net>
Tue, 1 Jul 2014 14:05:13 +0000 (15:05 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 1 Jul 2014 14:05:13 +0000 (15:05 +0100)
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/player.cc
src/lib/player.h
src/lib/player_video.cc
src/lib/player_video.h
src/lib/video_decoder.cc
src/wx/film_viewer.cc
test/client_server_test.cc

index 42be8227e95e57ebd0481e5b500566b1fd6cafb4..dfd8786b37b833621b20d1767279e608ce5335d7 100644 (file)
@@ -282,71 +282,6 @@ FFmpegDecoder::bytes_per_audio_sample () const
        return av_get_bytes_per_sample (audio_sample_format ());
 }
 
-int
-FFmpegDecoder::minimal_run (boost::function<bool (optional<ContentTime>, optional<ContentTime>, int)> finished)
-{
-       int frames_read = 0;
-       optional<ContentTime> last_video;
-       optional<ContentTime> last_audio;
-
-       while (!finished (last_video, last_audio, frames_read)) {
-               int r = av_read_frame (_format_context, &_packet);
-               if (r < 0) {
-                       /* We should flush our decoders here, possibly yielding a few more frames,
-                          but the consequence of having to do that is too hideous to contemplate.
-                          Instead we give up and say that you can't seek too close to the end
-                          of a file.
-                       */
-                       return frames_read;
-               }
-
-               ++frames_read;
-
-               double const time_base = av_q2d (_format_context->streams[_packet.stream_index]->time_base);
-
-               if (_packet.stream_index == _video_stream) {
-
-                       av_frame_unref (_frame);
-                       
-                       int got_picture = 0;
-                       r = avcodec_decode_video2 (video_codec_context(), _frame, &got_picture, &_packet);
-                       if (r >= 0 && got_picture) {
-                               last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
-                       }
-
-               } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, _packet.stream_index)) {
-                       AVPacket copy_packet = _packet;
-                       while (copy_packet.size > 0) {
-
-                               int got_frame;
-                               r = avcodec_decode_audio4 (audio_codec_context(), _frame, &got_frame, &_packet);
-                               if (r >= 0 && got_frame) {
-                                       last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
-                               }
-                                       
-                               copy_packet.data += r;
-                               copy_packet.size -= r;
-                       }
-               }
-               
-               av_free_packet (&_packet);
-       }
-
-       return frames_read;
-}
-
-bool
-FFmpegDecoder::seek_overrun_finished (ContentTime seek, optional<ContentTime> last_video, optional<ContentTime> last_audio) const
-{
-       return (last_video && last_video.get() >= seek) || (last_audio && last_audio.get() >= seek);
-}
-
-bool
-FFmpegDecoder::seek_final_finished (int n, int done) const
-{
-       return n == done;
-}
-
 void
 FFmpegDecoder::seek_and_flush (ContentTime t)
 {
@@ -393,21 +328,7 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
                initial_seek = ContentTime (0);
        }
 
-       /* Initial seek time in the video stream's timebase */
-
-       seek_and_flush (initial_seek);
-
-       if (!accurate) {
-               /* That'll do */
-               return;
-       }
-
-       int const N = minimal_run (boost::bind (&FFmpegDecoder::seek_overrun_finished, this, time, _1, _2));
-
        seek_and_flush (initial_seek);
-       if (N > 0) {
-               minimal_run (boost::bind (&FFmpegDecoder::seek_final_finished, this, N - 1, _3));
-       }
 }
 
 void
index 2859e23450380f7f9435a31f676cf5aa2ca1c58f..e44ac152ffbba560f21ea61508ebb167ff843a25 100644 (file)
@@ -66,9 +66,6 @@ private:
        void maybe_add_subtitle ();
        boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t** data, int size);
 
-       bool seek_overrun_finished (ContentTime, boost::optional<ContentTime>, boost::optional<ContentTime>) const;
-       bool seek_final_finished (int, int) const;
-       int minimal_run (boost::function<bool (boost::optional<ContentTime>, boost::optional<ContentTime>, int)>);
        void seek_and_flush (ContentTime);
 
        bool has_subtitle_during (ContentTimePeriod) const;
index b634028ba3a99ab6b8455041882c8b7eaa6c01fb..9257191693aab11bd89a2c120227071cd51bc6b5 100644 (file)
@@ -293,11 +293,12 @@ Player::set_approximate_size ()
 }
 
 shared_ptr<PlayerVideo>
-Player::black_player_video_frame () const
+Player::black_player_video_frame (DCPTime time) const
 {
        return shared_ptr<PlayerVideo> (
                new PlayerVideo (
                        shared_ptr<const ImageProxy> (new RawImageProxy (_black_image, _film->log ())),
+                       time,
                        Crop (),
                        _video_container_size,
                        _video_container_size,
@@ -326,7 +327,7 @@ Player::get_video (DCPTime time, bool accurate)
 
        if (ov.empty ()) {
                /* No video content at this time */
-               pvf.push_back (black_player_video_frame ());
+               pvf.push_back (black_player_video_frame (time));
        } else {
                /* Create a PlayerVideo from the content's video at this time */
 
@@ -338,7 +339,7 @@ Player::get_video (DCPTime time, bool accurate)
 
                list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
                if (content_video.empty ()) {
-                       pvf.push_back (black_player_video_frame ());
+                       pvf.push_back (black_player_video_frame (time));
                        return pvf;
                }
                
@@ -353,6 +354,7 @@ Player::get_video (DCPTime time, bool accurate)
                                shared_ptr<PlayerVideo> (
                                        new PlayerVideo (
                                                i->image,
+                                               content_video_to_dcp (piece, i->frame),
                                                content->crop (),
                                                image_size,
                                                _video_container_size,
@@ -508,6 +510,17 @@ Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
        return DCPTime (s + piece->content->trim_start()).frames (_film->video_frame_rate()) * piece->frc.factor ();
 }
 
+DCPTime
+Player::content_video_to_dcp (shared_ptr<const Piece> piece, VideoFrame f) const
+{
+       DCPTime t = DCPTime::from_frames (f / piece->frc.factor (), _film->video_frame_rate()) - piece->content->trim_start () + piece->content->position ();
+       if (t < DCPTime ()) {
+               t = DCPTime ();
+       }
+
+       return t;
+}
+
 AudioFrame
 Player::dcp_to_content_audio (shared_ptr<const Piece> piece, DCPTime t) const
 {
index 04503c27a0917c8aaa2e34e6a556fa764b4f3600..3ee909f97b53718c86a4602811a14d49b3220379 100644 (file)
@@ -117,9 +117,10 @@ private:
        std::list<PositionImage> process_content_text_subtitles (std::list<boost::shared_ptr<ContentTextSubtitle> >) const;
        void update_subtitle_from_text ();
        VideoFrame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
+       DCPTime content_video_to_dcp (boost::shared_ptr<const Piece> piece, VideoFrame f) const;
        AudioFrame dcp_to_content_audio (boost::shared_ptr<const Piece> piece, DCPTime t) const;
        ContentTime dcp_to_content_subtitle (boost::shared_ptr<const Piece> piece, DCPTime t) const;
-       boost::shared_ptr<PlayerVideo> black_player_video_frame () const;
+       boost::shared_ptr<PlayerVideo> black_player_video_frame (DCPTime) const;
 
        /** @return Pieces of content type C that overlap a specified time range in the DCP */
        template<class C>
index f8e4a3e668cfbf3249701215a579c2fca4258735..3c513848ac8ab82188f17ade5fbb9ddae3b0372e 100644 (file)
@@ -30,6 +30,7 @@ using dcp::raw_convert;
 
 PlayerVideo::PlayerVideo (
        shared_ptr<const ImageProxy> in,
+       DCPTime time,
        Crop crop,
        dcp::Size inter_size,
        dcp::Size out_size,
@@ -39,6 +40,7 @@ PlayerVideo::PlayerVideo (
        ColourConversion colour_conversion
        )
        : _in (in)
+       , _time (time)
        , _crop (crop)
        , _inter_size (inter_size)
        , _out_size (out_size)
@@ -52,6 +54,7 @@ PlayerVideo::PlayerVideo (
 
 PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket, shared_ptr<Log> log)
 {
+       _time = DCPTime (node->number_child<DCPTime::Type> ("Time"));
        _crop = Crop (node);
 
        _inter_size = dcp::Size (node->number_child<int> ("InterWidth"), node->number_child<int> ("InterHeight"));
@@ -118,6 +121,7 @@ PlayerVideo::image () const
 void
 PlayerVideo::add_metadata (xmlpp::Node* node) const
 {
+       node->add_child("Time")->add_child_text (raw_convert<string> (_time.get ()));
        _crop.as_xml (node);
        _in->add_metadata (node->add_child ("In"));
        node->add_child("InterWidth")->add_child_text (raw_convert<string> (_inter_size.width));
index 73557bbfda96ac8fbad9b1d27bdfd3605605ddc7..7d27877837bc835ef0bba256ed7cd24bde4d6e0f 100644 (file)
@@ -36,7 +36,7 @@ class Log;
 class PlayerVideo
 {
 public:
-       PlayerVideo (boost::shared_ptr<const ImageProxy>, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
+       PlayerVideo (boost::shared_ptr<const ImageProxy>, DCPTime, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
        PlayerVideo (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
 
        void set_subtitle (PositionImage);
@@ -46,6 +46,10 @@ public:
        void add_metadata (xmlpp::Node* node) const;
        void send_binary (boost::shared_ptr<Socket> socket) const;
 
+       DCPTime time () const {
+               return _time;
+       }
+
        Eyes eyes () const {
                return _eyes;
        }
@@ -56,6 +60,7 @@ public:
 
 private:
        boost::shared_ptr<const ImageProxy> _in;
+       DCPTime _time;
        Crop _crop;
        dcp::Size _inter_size;
        dcp::Size _out_size;
index 43b1049ccaf5f89920147f040cf5e96635f66675..bfd7a7e3ef6abeb9a2d3457aaa76894aa060e753 100644 (file)
@@ -61,8 +61,12 @@ VideoDecoder::decoded_video (VideoFrame frame)
 list<ContentVideo>
 VideoDecoder::get_video (VideoFrame frame, bool accurate)
 {
-       if (_decoded_video.empty() || (frame < _decoded_video.front().frame || frame > (_decoded_video.back().frame + 1))) {
-               /* Either we have no decoded data, or what we do have is a long way from what we want: seek */
+       /* At this stage, if we have get_video()ed before, _decoded_video will contain the last frame that this
+          method returned (and possibly a few more).  If the requested frame is not in _decoded_video and it is not the next
+          one after the end of _decoded_video we need to seek.
+       */
+          
+       if (_decoded_video.empty() || frame < _decoded_video.front().frame || frame > (_decoded_video.back().frame + 1)) {
                seek (ContentTime::from_frames (frame, _video_content->video_frame_rate()), accurate);
        }
 
@@ -70,7 +74,8 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
 
        /* Now enough pass() calls should either:
         *  (a) give us what we want, or
-        *  (b) hit the end of the decoder.
+        *  (b) give us something after what we want, indicating that we will never get what we want, or
+        *  (c) hit the end of the decoder.
         */
        if (accurate) {
                /* We are being accurate, so we want the right frame.
@@ -105,8 +110,8 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                }
        }
 
-       /* Clean up decoded_video */
-       while (!_decoded_video.empty() && _decoded_video.front().frame < (frame - 1)) {
+       /* Clean up _decoded_video; keep the frame we are returning, but nothing before that */
+       while (!_decoded_video.empty() && _decoded_video.front().frame < dec.front().frame) {
                _decoded_video.pop_front ();
        }
 
index dd3d9ebe9817b576bf935968ce7cae44c8501bb8..6499aa4099b10b5c580e89da457c5d473aa2c95b 100644 (file)
@@ -155,12 +155,12 @@ FilmViewer::get (DCPTime p, bool accurate)
        if (!pvf.empty ()) {
                _frame = pvf.front()->image ();
                _frame = _frame->scale (_frame->size(), Scaler::from_id ("fastbilinear"), PIX_FMT_RGB24, false);
+               _position = pvf.front()->time ();
        } else {
                _frame.reset ();
+               _position = p;
        }
 
-       _position = p;
-       
        set_position_text ();
        _panel->Refresh ();
        _panel->Update ();
index eab84cc397cb32684b55c5d56ebf57514cd98bc7..148f5ae6496a5853c6e6ff88d5043181a956663a 100644 (file)
@@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb)
        shared_ptr<PlayerVideo> pvf (
                new PlayerVideo (
                        shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
+                       DCPTime (),
                        Crop (),
                        dcp::Size (1998, 1080),
                        dcp::Size (1998, 1080),
@@ -164,6 +165,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv)
        shared_ptr<PlayerVideo> pvf (
                new PlayerVideo (
                        shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
+                       DCPTime (),
                        Crop (),
                        dcp::Size (1998, 1080),
                        dcp::Size (1998, 1080),