diff options
| author | Carl Hetherington <cth@carlh.net> | 2019-11-10 22:59:39 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-02-15 01:53:19 +0100 |
| commit | c259c459f5d326e7c42806b41de06c71ad4a3ad8 (patch) | |
| tree | a3a976edbefb9638c11c5fa477e81efde60234c8 | |
| parent | 9482a41238c370e093c896145b844dac0b221345 (diff) | |
Don't trust video timestamps from FFmpegDecoder.
Back-ported from 98342fb53eae4d32440fc69c279f2ca0fef785b5 in v2.15.x.
| -rw-r--r-- | src/lib/audio_decoder.cc | 4 | ||||
| -rw-r--r-- | src/lib/audio_decoder.h | 2 | ||||
| -rw-r--r-- | src/lib/decoder_part.h | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/text_decoder.h | 2 | ||||
| -rw-r--r-- | src/lib/video_decoder.cc | 44 | ||||
| -rw-r--r-- | src/lib/video_decoder.h | 6 |
7 files changed, 49 insertions, 13 deletions
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 440510ce5..2ab527f59 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -110,7 +110,7 @@ AudioDecoder::stream_position (shared_ptr<const Film> film, AudioStreamPtr strea return ContentTime::from_frames (i->second, _content->resampled_frame_rate(film)); } -ContentTime +optional<ContentTime> AudioDecoder::position (shared_ptr<const Film> film) const { optional<ContentTime> p; @@ -121,7 +121,7 @@ AudioDecoder::position (shared_ptr<const Film> film) const } } - return p.get_value_or(ContentTime()); + return p; } void diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 50e361e8f..002d839e9 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -47,7 +47,7 @@ class AudioDecoder : public boost::enable_shared_from_this<AudioDecoder>, public public: AudioDecoder (Decoder* parent, boost::shared_ptr<const AudioContent> content, bool fast); - ContentTime position (boost::shared_ptr<const Film> film) const; + boost::optional<ContentTime> position (boost::shared_ptr<const Film> film) const; void emit (boost::shared_ptr<const Film> film, AudioStreamPtr stream, boost::shared_ptr<const AudioBuffers>, ContentTime); void seek (); void flush (); diff --git a/src/lib/decoder_part.h b/src/lib/decoder_part.h index 7ba2cb2eb..e763b7313 100644 --- a/src/lib/decoder_part.h +++ b/src/lib/decoder_part.h @@ -34,7 +34,7 @@ public: DecoderPart (Decoder* parent); virtual ~DecoderPart () {} - virtual ContentTime position (boost::shared_ptr<const Film> film) const = 0; + virtual boost::optional<ContentTime> position (boost::shared_ptr<const Film> film) const = 0; virtual void seek () = 0; void set_ignore (bool i) { diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 0f39f7727..fd248c39a 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -126,7 +126,7 @@ FFmpegDecoder::flush () if (video) { double const vfr = _ffmpeg_content->video_frame_rate().get(); Frame const f = full_length.frames_round (vfr); - Frame v = video->position(film()).frames_round(vfr) + 1; + Frame v = video->position(film()).get_value_or(ContentTime()).frames_round(vfr) + 1; while (v < f) { video->emit (film(), shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)), v); ++v; diff --git a/src/lib/text_decoder.h b/src/lib/text_decoder.h index a82f43f51..a320e146b 100644 --- a/src/lib/text_decoder.h +++ b/src/lib/text_decoder.h @@ -44,7 +44,7 @@ public: ContentTime first ); - ContentTime position (boost::shared_ptr<const Film>) const { + boost::optional<ContentTime> position (boost::shared_ptr<const Film>) const { return _position; } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index de1df727f..46611bbed 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -53,12 +53,44 @@ VideoDecoder::VideoDecoder (Decoder* parent, shared_ptr<const Content> c) * and so on. */ void -VideoDecoder::emit (shared_ptr<const Film> film, shared_ptr<const ImageProxy> image, Frame frame) +VideoDecoder::emit (shared_ptr<const Film> film, shared_ptr<const ImageProxy> 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)); @@ -90,9 +122,13 @@ VideoDecoder::emit (shared_ptr<const Film> film, shared_ptr<const ImageProxy> 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)); @@ -111,7 +147,7 @@ VideoDecoder::emit (shared_ptr<const Film> film, shared_ptr<const ImageProxy> 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 ed56feea0..98a8e7b7a 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -51,7 +51,7 @@ public: friend struct ffmpeg_pts_offset_test; friend void ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int gaps, int video_length); - ContentTime position (boost::shared_ptr<const Film>) const { + boost::optional<ContentTime> position (boost::shared_ptr<const Film>) const { return _position; } @@ -63,10 +63,10 @@ public: private: boost::shared_ptr<const Content> _content; - /** Frame of last thing to be emitted */ + /** Frame of last thing to be emitted; only used for 3D */ boost::optional<Frame> _last_emitted_frame; boost::optional<Eyes> _last_emitted_eyes; - ContentTime _position; + boost::optional<ContentTime> _position; }; #endif |
