X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=c7dd83d6daa152a47ad294ffcf80bf077059589d;hb=02b74112721d13a27b0bbaece714d5c8ea743d43;hp=e9ca38c81d551c3ca9caee170f0d6f20932f1cca;hpb=053bf81d7ef24843cc2eea62e24c2296fed48950;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index e9ca38c81..c7dd83d6d 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -140,18 +140,102 @@ Player::construct () auto film = _film.lock(); DCPOMATIC_ASSERT(film); + connect(); + set_video_container_size(film->frame_size()); + + film_change (ChangeType::DONE, Film::Property::AUDIO_PROCESSOR); + + setup_pieces (); + seek (DCPTime (), true); +} + + +void +Player::connect() +{ + auto film = _film.lock(); + DCPOMATIC_ASSERT(film); + _film_changed_connection = film->Change.connect(bind(&Player::film_change, this, _1, _2)); /* The butler must hear about this first, so since we are proxying this through to the butler we must be first. */ _playlist_change_connection = playlist()->Change.connect (bind (&Player::playlist_change, this, _1), boost::signals2::at_front); _playlist_content_change_connection = playlist()->ContentChange.connect (bind(&Player::playlist_content_change, this, _1, _3, _4)); - set_video_container_size(film->frame_size()); +} - film_change (ChangeType::DONE, Film::Property::AUDIO_PROCESSOR); - setup_pieces (); - seek (DCPTime (), true); +Player::Player(Player&& other) + : _film(other._film) + , _playlist(std::move(other._playlist)) + , _suspended(other._suspended.load()) + , _pieces(std::move(other._pieces)) + , _video_container_size(other._video_container_size.load()) + , _black_image(std::move(other._black_image)) + , _ignore_video(other._ignore_video.load()) + , _ignore_audio(other._ignore_audio.load()) + , _ignore_text(other._ignore_text.load()) + , _always_burn_open_subtitles(other._always_burn_open_subtitles.load()) + , _fast(other._fast.load()) + , _tolerant(other._tolerant) + , _play_referenced(other._play_referenced.load()) + , _next_video_time(other._next_video_time) + , _next_audio_time(other._next_audio_time) + , _dcp_decode_reduction(other._dcp_decode_reduction.load()) + , _last_video(std::move(other._last_video)) + , _audio_merger(std::move(other._audio_merger)) + , _shuffler(std::move(other._shuffler)) + , _delay(std::move(other._delay)) + , _stream_states(std::move(other._stream_states)) + , _black(std::move(other._black)) + , _silent(std::move(other._silent)) + , _active_texts(std::move(other._active_texts)) + , _audio_processor(std::move(other._audio_processor)) + , _playback_length(other._playback_length.load()) + , _subtitle_alignment(other._subtitle_alignment) +{ + connect(); +} + + +Player& +Player::operator=(Player&& other) +{ + if (this == &other) { + return *this; + } + + _film = std::move(other._film); + _playlist = std::move(other._playlist); + _suspended = other._suspended.load(); + _pieces = std::move(other._pieces); + _video_container_size = other._video_container_size.load(); + _black_image = std::move(other._black_image); + _ignore_video = other._ignore_video.load(); + _ignore_audio = other._ignore_audio.load(); + _ignore_text = other._ignore_text.load(); + _always_burn_open_subtitles = other._always_burn_open_subtitles.load(); + _fast = other._fast.load(); + _tolerant = other._tolerant; + _play_referenced = other._play_referenced.load(); + _next_video_time = other._next_video_time; + _next_audio_time = other._next_audio_time; + _dcp_decode_reduction = other._dcp_decode_reduction.load(); + _last_video = std::move(other._last_video); + _audio_merger = std::move(other._audio_merger); + _shuffler = std::move(other._shuffler); + _delay = std::move(other._delay); + _stream_states = std::move(other._stream_states); + _black = std::move(other._black); + _silent = std::move(other._silent); + _active_texts = std::move(other._active_texts); + _audio_processor = std::move(other._audio_processor); + _playback_length = other._playback_length.load(); + _subtitle_alignment = other._subtitle_alignment; + + connect(); + + return *this; } @@ -198,29 +282,29 @@ Player::setup_pieces () _shuffler->Video.connect(bind(&Player::video, this, _1, _2)); } - for (auto i: playlist()->content()) { + for (auto content: playlist()->content()) { - if (!i->paths_valid ()) { + if (!content->paths_valid()) { continue; } - if (_ignore_video && _ignore_audio && i->text.empty()) { + if (_ignore_video && _ignore_audio && content->text.empty()) { /* We're only interested in text and this content has none */ continue; } shared_ptr old_decoder; for (auto j: old_pieces) { - if (j->content == i) { + if (j->content == content) { old_decoder = j->decoder; break; } } - auto decoder = decoder_factory(film, i, _fast, _tolerant, old_decoder); + auto decoder = decoder_factory(film, content, _fast, _tolerant, old_decoder); DCPOMATIC_ASSERT (decoder); - FrameRateChange frc(film, i); + FrameRateChange frc(film, content); if (decoder->video && _ignore_video) { decoder->video->set_ignore (true); @@ -244,7 +328,7 @@ Player::setup_pieces () } } - auto piece = make_shared(i, decoder, frc); + auto piece = make_shared(content, decoder, frc); _pieces.push_back (piece); if (decoder->video) { @@ -285,7 +369,7 @@ Player::setup_pieces () for (auto i: _pieces) { if (i->content->audio) { for (auto j: i->content->audio->streams()) { - _stream_states[j] = StreamState (i, i->content->position ()); + _stream_states[j] = StreamState(i); } } } @@ -716,21 +800,25 @@ Player::pass () using state_pair = std::pair; + /* Find streams that have pushed */ + std::vector have_pushed; + std::copy_if(_stream_states.begin(), _stream_states.end(), std::back_inserter(have_pushed), [](state_pair const& a) { return static_cast(a.second.last_push_end); }); + /* Find the 'leading' stream (i.e. the one that pushed data most recently) */ auto latest_last_push_end = std::max_element( - _stream_states.begin(), - _stream_states.end(), - [](state_pair const& a, state_pair const& b) { return a.second.last_push_end < b.second.last_push_end; } + have_pushed.begin(), + have_pushed.end(), + [](state_pair const& a, state_pair const& b) { return a.second.last_push_end.get() < b.second.last_push_end.get(); } ); - if (latest_last_push_end != _stream_states.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)); + 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 alive_stream_states; for (auto const& i: _stream_states) { - if ((latest_last_push_end->second.last_push_end - i.second.last_push_end) < dcpomatic::DCPTime::from_seconds(ignore_streams_behind)) { + 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)); @@ -739,8 +827,9 @@ Player::pass () auto pull_to = _playback_length.load(); for (auto const& i: alive_stream_states) { - if (!i.second.piece->done && i.second.last_push_end < pull_to) { - pull_to = i.second.last_push_end; + auto position = i.second.last_push_end.get_value_or(i.second.piece->content->position()); + if (!i.second.piece->done && position < pull_to) { + pull_to = position; } } if (!_silent.done() && _silent.position() < pull_to) { @@ -843,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 weak_piece, ContentVideo video) { @@ -995,10 +1096,10 @@ Player::audio (weak_ptr weak_piece, AudioStreamPtr stream, ContentAudio c /* Compute time in the DCP */ auto time = resampled_audio_to_dcp (piece, content_audio.frame); - LOG_DEBUG_PLAYER("Received audio frame %1 at %2", content_audio.frame, to_string(time)); /* And the end of this block in the DCP */ auto end = time + DCPTime::from_frames(content_audio.audio->frames(), rfr); + LOG_DEBUG_PLAYER("Received audio frame %1 covering %2 to %3 (%4)", content_audio.frame, to_string(time), to_string(end), piece->content->path(0).filename()); /* Remove anything that comes before the start or after the end of the content */ if (time < piece->content->position()) { @@ -1258,6 +1359,10 @@ Player::seek (DCPTime time, bool accurate) _silent.set_position (time); _last_video.clear (); + + for (auto& state: _stream_states) { + state.second.last_push_end = {}; + } }