From 98342fb53eae4d32440fc69c279f2ca0fef785b5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 10 Nov 2019 22:59:39 +0100 Subject: [PATCH] Don't trust video timestamps from FFmpegDecoder. --- src/lib/video_decoder.cc | 44 ++++++++++++++++++++++++++++++++++++---- src/lib/video_decoder.h | 2 +- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 7a3a3e19b..19a994197 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -54,12 +54,44 @@ VideoDecoder::VideoDecoder (Decoder* parent, shared_ptr c) * and so on. */ void -VideoDecoder::emit (shared_ptr film, shared_ptr image, Frame frame) +VideoDecoder::emit (shared_ptr film, shared_ptr image, Frame decoder_frame) { if (ignore ()) { return; } + double const afr = _content->active_video_frame_rate(film); + + Frame frame; + if (!_position) { + /* This is the first data we have received since initialisation or seek. Set + the position based on the frame that was given. After this first time + we just cound frames, since (as with audio) it seems that ContentTimes + are unreliable from FFmpegDecoder. They are much better than audio times + but still we get the occasional one which is duplicated. In this case + ffmpeg seems to carry on regardless, processing the video frame as normal. + If we drop the frame with the duplicated timestamp we obviously lose sync. + */ + _position = ContentTime::from_frames (decoder_frame, afr); + if (_content->video->frame_type() == VIDEO_FRAME_TYPE_3D_ALTERNATE) { + frame = decoder_frame / 2; + _last_emitted_eyes = EYES_RIGHT; + } else { + frame = decoder_frame; + } + } else { + if (_content->video->frame_type() == VIDEO_FRAME_TYPE_3D_ALTERNATE) { + DCPOMATIC_ASSERT (_last_emitted_eyes); + if (_last_emitted_eyes.get() == EYES_RIGHT) { + frame = _position->frames_round(afr) + 1; + } else { + frame = _position->frames_round(afr); + } + } else { + frame = _position->frames_round(afr) + 1; + } + } + switch (_content->video->frame_type ()) { case VIDEO_FRAME_TYPE_2D: Data (ContentVideo (image, frame, EYES_BOTH, PART_WHOLE)); @@ -91,9 +123,13 @@ VideoDecoder::emit (shared_ptr film, shared_ptr im break; } case VIDEO_FRAME_TYPE_3D_ALTERNATE: - Data (ContentVideo (image, frame / 2, (frame % 2) ? EYES_RIGHT : EYES_LEFT, PART_WHOLE)); - frame /= 2; + { + DCPOMATIC_ASSERT (_last_emitted_eyes); + Eyes const eyes = _last_emitted_eyes.get() == EYES_LEFT ? EYES_RIGHT : EYES_LEFT; + Data (ContentVideo (image, frame, eyes, PART_WHOLE)); + _last_emitted_eyes = eyes; break; + } case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT: Data (ContentVideo (image, frame, EYES_LEFT, PART_LEFT_HALF)); Data (ContentVideo (image, frame, EYES_RIGHT, PART_RIGHT_HALF)); @@ -112,7 +148,7 @@ VideoDecoder::emit (shared_ptr film, shared_ptr im DCPOMATIC_ASSERT (false); } - _position = ContentTime::from_frames (frame, _content->active_video_frame_rate(film)); + _position = ContentTime::from_frames (frame, afr); } void diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 34ce8f288..954b8f365 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -63,7 +63,7 @@ public: private: boost::shared_ptr _content; - /** Frame of last thing to be emitted */ + /** Frame of last thing to be emitted; only used for 3D */ boost::optional _last_emitted_frame; boost::optional _last_emitted_eyes; boost::optional _position; -- 2.30.2