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;
}
_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<Decoder> 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);
}
}
- auto piece = make_shared<Piece>(i, decoder, frc);
+ auto piece = make_shared<Piece>(content, decoder, frc);
_pieces.push_back (piece);
if (decoder->video) {
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);
}
}
}
using state_pair = std::pair<AudioStreamPtr, StreamState>;
+ /* Find streams that have pushed */
+ std::vector<state_pair> have_pushed;
+ std::copy_if(_stream_states.begin(), _stream_states.end(), std::back_inserter(have_pushed), [](state_pair const& a) { return static_cast<bool>(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<AudioStreamPtr, StreamState> 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));
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) {
}
+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)
{
/* 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()) {
_silent.set_position (time);
_last_video.clear ();
+
+ for (auto& state: _stream_states) {
+ state.second.last_push_end = {};
+ }
}