- /* Clean up _decoded; keep the frame we are returning, if any (which may have two images
- for 3D), but nothing before that */
- while (!_decoded.empty() && !dec.empty() && _decoded.front().frame.index() < dec.front().frame.index()) {
- _decoded.pop_front ();
- }
-
- return dec;
-}
-
-/** Fill _decoded from `from' up to, but not including, `to' with
- * a frame for one particular Eyes value (which could be EYES_BOTH,
- * EYES_LEFT or EYES_RIGHT)
- */
-void
-VideoDecoder::fill_one_eye (Frame from, Frame to, Eyes eye)
-{
- if (to == 0) {
- /* Already OK */
- return;
- }
-
- /* Fill with black... */
- shared_ptr<const ImageProxy> filler_image (new RawImageProxy (_black_image));
- Part filler_part = PART_WHOLE;
-
- /* ...unless there's some video we can fill with */
- if (!_decoded.empty ()) {
- filler_image = _decoded.back().image;
- filler_part = _decoded.back().part;
- }
-
- for (Frame i = from; i < to; ++i) {
-#ifdef DCPOMATIC_DEBUG
- test_gaps++;
-#endif
- _decoded.push_back (
- ContentVideo (filler_image, VideoFrame (i, eye), filler_part)
- );
- }
-}
-
-/** Fill _decoded from `from' up to, but not including, `to'
- * adding both left and right eye frames.
- */
-void
-VideoDecoder::fill_both_eyes (VideoFrame from, VideoFrame to)
-{
- /* Fill with black... */
- shared_ptr<const ImageProxy> filler_left_image (new RawImageProxy (_black_image));
- shared_ptr<const ImageProxy> filler_right_image (new RawImageProxy (_black_image));
- Part filler_left_part = PART_WHOLE;
- Part filler_right_part = PART_WHOLE;
-
- /* ...unless there's some video we can fill with */
- for (list<ContentVideo>::const_reverse_iterator i = _decoded.rbegin(); i != _decoded.rend(); ++i) {
- if (i->frame.eyes() == EYES_LEFT && !filler_left_image) {
- filler_left_image = i->image;
- filler_left_part = i->part;
- } else if (i->frame.eyes() == EYES_RIGHT && !filler_right_image) {
- filler_right_image = i->image;
- filler_right_part = i->part;
+ Frame frame;
+ Eyes eyes = EYES_BOTH;
+ 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 (vft == VIDEO_FRAME_TYPE_3D_ALTERNATE) {
+ frame = decoder_frame / 2;
+ _last_emitted_eyes = EYES_RIGHT;
+ } else {
+ frame = decoder_frame;