Move ScopeGuard into libdcp.
[dcpomatic.git] / src / lib / player.cc
index ab8b59656d72efc655017144648caccc0ddc1fb1..ef7ecde5a4d762bdf2dfc86d24344b2f03fd66b8 100644 (file)
@@ -143,7 +143,7 @@ Player::construct ()
        connect();
        set_video_container_size(film->frame_size());
 
-       film_change (ChangeType::DONE, Film::Property::AUDIO_PROCESSOR);
+       film_change(ChangeType::DONE, FilmProperty::AUDIO_PROCESSOR);
 
        setup_pieces ();
        seek (DCPTime (), true);
@@ -392,6 +392,20 @@ Player::setup_pieces ()
                }
        }
 
+       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);
+                                       }
+                               }
+                       }
+               }
+       }
+
        _black = Empty(film, playlist(), bind(&have_video, _1), _playback_length);
        _silent = Empty(film, playlist(), bind(&have_audio, _1), _playback_length);
 
@@ -467,7 +481,7 @@ Player::playlist_change (ChangeType type)
 
 
 void
-Player::film_change (ChangeType type, Film::Property p)
+Player::film_change(ChangeType type, FilmProperty p)
 {
        /* Here we should notice Film properties that affect our output, and
           alert listeners that our output now would be different to how it was
@@ -479,9 +493,9 @@ Player::film_change (ChangeType type, Film::Property p)
                return;
        }
 
-       if (p == Film::Property::CONTAINER) {
+       if (p == FilmProperty::CONTAINER) {
                Change (type, PlayerProperty::FILM_CONTAINER, false);
-       } else if (p == Film::Property::VIDEO_FRAME_RATE) {
+       } else if (p == FilmProperty::VIDEO_FRAME_RATE) {
                /* Pieces contain a FrameRateChange which contains the DCP frame rate,
                   so we need new pieces here.
                */
@@ -489,12 +503,12 @@ Player::film_change (ChangeType type, Film::Property p)
                        setup_pieces ();
                }
                Change (type, PlayerProperty::FILM_VIDEO_FRAME_RATE, false);
-       } else if (p == Film::Property::AUDIO_PROCESSOR) {
+       } else if (p == FilmProperty::AUDIO_PROCESSOR) {
                if (type == ChangeType::DONE && film->audio_processor ()) {
                        boost::mutex::scoped_lock lm (_mutex);
                        _audio_processor = film->audio_processor()->clone(film->audio_frame_rate());
                }
-       } else if (p == Film::Property::AUDIO_CHANNELS) {
+       } else if (p == FilmProperty::AUDIO_CHANNELS) {
                if (type == ChangeType::DONE) {
                        boost::mutex::scoped_lock lm (_mutex);
                        _audio_merger.clear ();
@@ -756,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:
@@ -813,17 +832,18 @@ Player::pass ()
                [](state_pair const& a, state_pair const& b) { return a.second.last_push_end.get() < b.second.last_push_end.get(); }
                );
 
+       std::map<AudioStreamPtr, StreamState> alive_stream_states;
+
        if (latest_last_push_end != have_pushed.end()) {
                LOG_DEBUG_PLAYER("Leading audio stream is in %1 at %2", latest_last_push_end->second.piece->content->path(0), to_string(latest_last_push_end->second.last_push_end.get()));
-       }
 
-       /* Now make a list of those streams that are less than ignore_streams_behind behind the leader */
-       std::map<AudioStreamPtr, StreamState> alive_stream_states;
-       for (auto const& i: _stream_states) {
-               if (!i.second.last_push_end || (latest_last_push_end->second.last_push_end.get() - i.second.last_push_end.get()) < dcpomatic::DCPTime::from_seconds(ignore_streams_behind)) {
-                       alive_stream_states.insert(i);
-               } else {
-                       LOG_DEBUG_PLAYER("Ignoring stream %1 because it is too far behind", i.second.piece->content->path(0));
+               /* Now make a list of those streams that are less than ignore_streams_behind behind the leader */
+               for (auto const& i: _stream_states) {
+                       if (!i.second.last_push_end || (latest_last_push_end->second.last_push_end.get() - i.second.last_push_end.get()) < dcpomatic::DCPTime::from_seconds(ignore_streams_behind)) {
+                               alive_stream_states.insert(i);
+                       } else {
+                               LOG_DEBUG_PLAYER("Ignoring stream %1 because it is too far behind", i.second.piece->content->path(0));
+                       }
                }
        }
 
@@ -1403,16 +1423,6 @@ Player::emit_video (shared_ptr<PlayerVideo> pv, DCPTime time)
        auto film = _film.lock();
        DCPOMATIC_ASSERT(film);
 
-       if (!film->three_d()) {
-               if (pv->eyes() == Eyes::LEFT) {
-                       /* Use left-eye images for both eyes... */
-                       pv->set_eyes (Eyes::BOTH);
-               } else if (pv->eyes() == Eyes::RIGHT) {
-                       /* ...and discard the right */
-                       return;
-               }
-       }
-
        /* We need a delay to give a little wiggle room to ensure that relevant subtitles arrive at the
           player before the video that requires them.
        */
@@ -1599,6 +1609,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);
 }