Fix error when padding is needed in 3D encodes (#2476).
[dcpomatic.git] / src / lib / player.cc
index c7dd83d6daa152a47ad294ffcf80bf077059589d..abcefcab5c57fcae7afbc5db48589cd12088d343 100644 (file)
@@ -378,13 +378,29 @@ Player::setup_pieces ()
                return v && v->use() && v->frame_type() != VideoFrameType::THREE_D_LEFT && v->frame_type() != VideoFrameType::THREE_D_RIGHT;
        };
 
-       for (auto i = _pieces.begin(); i != _pieces.end(); ++i) {
-               if (ignore_overlap((*i)->content->video)) {
+       for (auto piece = _pieces.begin(); piece != _pieces.end(); ++piece) {
+               if (ignore_overlap((*piece)->content->video)) {
                        /* Look for content later in the content list with in-use video that overlaps this */
-                       auto const period = DCPTimePeriod((*i)->content->position(), (*i)->content->end(film));
-                       for (auto j = std::next(i); j != _pieces.end(); ++j) {
-                               if ((*j)->content->video && ignore_overlap((*j)->content->video)) {
-                                       (*i)->ignore_video = DCPTimePeriod((*j)->content->position(), (*j)->content->end(film)).overlap(period);
+                       auto const period = (*piece)->content->period(film);
+                       for (auto later_piece = std::next(piece); later_piece != _pieces.end(); ++later_piece) {
+                               if (ignore_overlap((*later_piece)->content->video)) {
+                                       if (auto overlap = (*later_piece)->content->period(film).overlap(period)) {
+                                               (*piece)->ignore_video.push_back(*overlap);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       for (auto piece = _pieces.begin(); piece != _pieces.end(); ++piece) {
+               if ((*piece)->content->atmos) {
+                       /* Look for content later in the content list with ATMOS that overlaps this */
+                       auto const period = (*piece)->content->period(film);
+                       for (auto later_piece = std::next(piece); later_piece != _pieces.end(); ++later_piece) {
+                               if ((*later_piece)->content->atmos) {
+                                       if (auto overlap = (*later_piece)->content->period(film).overlap(period)) {
+                                               (*piece)->ignore_atmos.push_back(*overlap);
+                                       }
                                }
                        }
                }
@@ -754,7 +770,12 @@ Player::pass ()
        }
        case BLACK:
                LOG_DEBUG_PLAYER ("Emit black for gap at %1", to_string(_black.position()));
-               emit_video (black_player_video_frame(Eyes::BOTH), _black.position());
+               if (film->three_d()) {
+                       emit_video(black_player_video_frame(Eyes::LEFT), _black.position());
+                       emit_video(black_player_video_frame(Eyes::RIGHT), _black.position());
+               } else {
+                       emit_video(black_player_video_frame(Eyes::BOTH), _black.position());
+               }
                _black.set_position (_black.position() + one_video_frame());
                break;
        case SILENT:
@@ -970,6 +991,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));
@@ -982,7 +1025,12 @@ Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
                return;
        }
 
-       if (piece->ignore_video && piece->ignore_video->contains(time)) {
+       auto ignore_video = std::find_if(
+               piece->ignore_video.begin(),
+               piece->ignore_video.end(),
+               [time](DCPTimePeriod period) { return period.contains(time); }
+               );
+       if (ignore_video != piece->ignore_video.end()) {
                return;
        }
 
@@ -998,7 +1046,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;
                                }
@@ -1040,32 +1088,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 ();
        }
 }
 
@@ -1361,7 +1411,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;
        }
 }
 
@@ -1568,6 +1618,15 @@ Player::atmos (weak_ptr<Piece> weak_piece, ContentAtmos data)
                return;
        }
 
+       auto ignore_atmos = std::find_if(
+               piece->ignore_atmos.begin(),
+               piece->ignore_atmos.end(),
+               [dcp_time](DCPTimePeriod period) { return period.contains(dcp_time); }
+               );
+       if (ignore_atmos != piece->ignore_atmos.end()) {
+               return;
+       }
+
        Atmos (data.data, dcp_time, data.metadata);
 }