Handle 2D/3D mismatches in the player (#2409).
[dcpomatic.git] / src / lib / player.cc
index 40f726d107b716f7f51606e0e28f93a07f351cc9..510def583279819e6e4c60239dec3f7481325399 100644 (file)
@@ -932,6 +932,18 @@ Player::open_subtitles_for_frame (DCPTime time) const
 }
 
 
+static
+Eyes
+increment_eyes (Eyes e)
+{
+       if (e == Eyes::LEFT) {
+               return Eyes::RIGHT;
+       }
+
+       return Eyes::LEFT;
+}
+
+
 void
 Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
 {
@@ -958,6 +970,28 @@ Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
                return;
        }
 
+       vector<Eyes> eyes_to_emit;
+
+       if (!film->three_d()) {
+               if (video.eyes == Eyes::RIGHT) {
+                       /* 2D film, 3D content: discard right */
+                       return;
+               } else if (video.eyes == Eyes::LEFT) {
+                       /* 2D film, 3D content: emit left as "both" */
+                       video.eyes = Eyes::BOTH;
+                       eyes_to_emit = { Eyes::BOTH };
+               }
+       } else {
+               if (video.eyes == Eyes::BOTH) {
+                       /* 3D film, 2D content; emit "both" for left and right */
+                       eyes_to_emit = { Eyes::LEFT, Eyes::RIGHT };
+               }
+       }
+
+       if (eyes_to_emit.empty()) {
+               eyes_to_emit = { video.eyes };
+       }
+
        /* Time of the first frame we will emit */
        DCPTime const time = content_video_to_dcp (piece, video.frame);
        LOG_DEBUG_PLAYER("Received video frame %1 at %2", video.frame, to_string(time));
@@ -986,7 +1020,7 @@ Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
                if ((fill_to - fill_from) > one_video_frame() / 2) {
                        auto last = _last_video.find (weak_piece);
                        if (film->three_d()) {
-                               auto fill_to_eyes = video.eyes;
+                               auto fill_to_eyes = eyes_to_emit[0];
                                if (fill_to_eyes == Eyes::BOTH) {
                                        fill_to_eyes = Eyes::LEFT;
                                }
@@ -1028,32 +1062,34 @@ Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
 
        auto const content_video = piece->content->video;
 
-       _last_video[weak_piece] = std::make_shared<PlayerVideo>(
-               video.image,
-               content_video->actual_crop(),
-               content_video->fade(film, video.frame),
-               scale_for_display(
-                       content_video->scaled_size(film->frame_size()),
+       for (auto eyes: eyes_to_emit) {
+               _last_video[weak_piece] = std::make_shared<PlayerVideo>(
+                       video.image,
+                       content_video->actual_crop(),
+                       content_video->fade(film, video.frame),
+                       scale_for_display(
+                               content_video->scaled_size(film->frame_size()),
+                               _video_container_size,
+                               film->frame_size(),
+                               content_video->pixel_quanta()
+                               ),
                        _video_container_size,
-                       film->frame_size(),
-                       content_video->pixel_quanta()
-                       ),
-               _video_container_size,
-               video.eyes,
-               video.part,
-               content_video->colour_conversion(),
-               content_video->range(),
-               piece->content,
-               video.frame,
-               false
-               );
-
-       DCPTime t = time;
-       for (int i = 0; i < frc.repeat; ++i) {
-               if (t < piece->content->end(film)) {
-                       emit_video (_last_video[weak_piece], t);
+                       eyes,
+                       video.part,
+                       content_video->colour_conversion(),
+                       content_video->range(),
+                       piece->content,
+                       video.frame,
+                       false
+                       );
+
+               DCPTime t = time;
+               for (int i = 0; i < frc.repeat; ++i) {
+                       if (t < piece->content->end(film)) {
+                               emit_video (_last_video[weak_piece], t);
+                       }
+                       t += one_video_frame ();
                }
-               t += one_video_frame ();
        }
 }
 
@@ -1349,7 +1385,7 @@ Player::seek (DCPTime time, bool accurate)
        _last_video.clear ();
 
        for (auto& state: _stream_states) {
-               state.second.last_push_end = {};
+               state.second.last_push_end = boost::none;
        }
 }