summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2019-11-10 22:59:39 +0100
committerCarl Hetherington <cth@carlh.net>2020-02-15 01:53:19 +0100
commitc259c459f5d326e7c42806b41de06c71ad4a3ad8 (patch)
treea3a976edbefb9638c11c5fa477e81efde60234c8
parent9482a41238c370e093c896145b844dac0b221345 (diff)
Don't trust video timestamps from FFmpegDecoder.
Back-ported from 98342fb53eae4d32440fc69c279f2ca0fef785b5 in v2.15.x.
-rw-r--r--src/lib/audio_decoder.cc4
-rw-r--r--src/lib/audio_decoder.h2
-rw-r--r--src/lib/decoder_part.h2
-rw-r--r--src/lib/ffmpeg_decoder.cc2
-rw-r--r--src/lib/text_decoder.h2
-rw-r--r--src/lib/video_decoder.cc44
-rw-r--r--src/lib/video_decoder.h6
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