From 6f071ce94bb7cff1106e2ef6d8eb4363694435f2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 1 Jul 2014 15:05:13 +0100 Subject: [PATCH] Remove FFmpegDecoder minimal_run and care on seeking, as the VideoDecoder/AudioDecoder has to cope with stuff per-stream anyway. --- src/lib/ffmpeg_decoder.cc | 79 -------------------------------------- src/lib/ffmpeg_decoder.h | 3 -- src/lib/player.cc | 19 +++++++-- src/lib/player.h | 3 +- src/lib/player_video.cc | 4 ++ src/lib/player_video.h | 7 +++- src/lib/video_decoder.cc | 15 +++++--- src/wx/film_viewer.cc | 4 +- test/client_server_test.cc | 2 + 9 files changed, 42 insertions(+), 94 deletions(-) diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 42be8227e..dfd8786b3 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -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, optional, int)> finished) -{ - int frames_read = 0; - optional last_video; - optional 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 last_video, optional 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 diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 2859e2345..e44ac152f 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -66,9 +66,6 @@ private: void maybe_add_subtitle (); boost::shared_ptr deinterleave_audio (uint8_t** data, int size); - bool seek_overrun_finished (ContentTime, boost::optional, boost::optional) const; - bool seek_final_finished (int, int) const; - int minimal_run (boost::function, boost::optional, int)>); void seek_and_flush (ContentTime); bool has_subtitle_during (ContentTimePeriod) const; diff --git a/src/lib/player.cc b/src/lib/player.cc index b634028ba..925719169 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -293,11 +293,12 @@ Player::set_approximate_size () } shared_ptr -Player::black_player_video_frame () const +Player::black_player_video_frame (DCPTime time) const { return shared_ptr ( new PlayerVideo ( shared_ptr (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 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 ( 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 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 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 piece, DCPTime t) const { diff --git a/src/lib/player.h b/src/lib/player.h index 04503c27a..3ee909f97 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -117,9 +117,10 @@ private: std::list process_content_text_subtitles (std::list >) const; void update_subtitle_from_text (); VideoFrame dcp_to_content_video (boost::shared_ptr piece, DCPTime t) const; + DCPTime content_video_to_dcp (boost::shared_ptr piece, VideoFrame f) const; AudioFrame dcp_to_content_audio (boost::shared_ptr piece, DCPTime t) const; ContentTime dcp_to_content_subtitle (boost::shared_ptr piece, DCPTime t) const; - boost::shared_ptr black_player_video_frame () const; + boost::shared_ptr black_player_video_frame (DCPTime) const; /** @return Pieces of content type C that overlap a specified time range in the DCP */ template diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index f8e4a3e66..3c513848a 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -30,6 +30,7 @@ using dcp::raw_convert; PlayerVideo::PlayerVideo ( shared_ptr 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 node, shared_ptr socket, shared_ptr log) { + _time = DCPTime (node->number_child ("Time")); _crop = Crop (node); _inter_size = dcp::Size (node->number_child ("InterWidth"), node->number_child ("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 (_time.get ())); _crop.as_xml (node); _in->add_metadata (node->add_child ("In")); node->add_child("InterWidth")->add_child_text (raw_convert (_inter_size.width)); diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 73557bbfd..7d2787783 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -36,7 +36,7 @@ class Log; class PlayerVideo { public: - PlayerVideo (boost::shared_ptr, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion); + PlayerVideo (boost::shared_ptr, DCPTime, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion); PlayerVideo (boost::shared_ptr, boost::shared_ptr, boost::shared_ptr); void set_subtitle (PositionImage); @@ -46,6 +46,10 @@ public: void add_metadata (xmlpp::Node* node) const; void send_binary (boost::shared_ptr socket) const; + DCPTime time () const { + return _time; + } + Eyes eyes () const { return _eyes; } @@ -56,6 +60,7 @@ public: private: boost::shared_ptr _in; + DCPTime _time; Crop _crop; dcp::Size _inter_size; dcp::Size _out_size; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 43b1049cc..bfd7a7e3e 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -61,8 +61,12 @@ VideoDecoder::decoded_video (VideoFrame frame) list 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 (); } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index dd3d9ebe9..6499aa409 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -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 (); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index eab84cc39..148f5ae64 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) shared_ptr pvf ( new PlayerVideo ( shared_ptr (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 pvf ( new PlayerVideo ( shared_ptr (new RawImageProxy (image, log)), + DCPTime (), Crop (), dcp::Size (1998, 1080), dcp::Size (1998, 1080), -- 2.30.2