X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=6e6cd75d7d774b1ef3f3d1c3388ed507fd2b2bcf;hb=a95e78ea9d4c39f05fc8f7b58141a6a5bdc91ad6;hp=fa6c1b055a6670750ed10388eb6d2a6f01e24386;hpb=b73576594b252e033539bec964d72403d3775585;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index fa6c1b055..6e6cd75d7 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -231,7 +231,6 @@ Player::setup_pieces_unlocked () _last_video_time = DCPTime (); _last_video_eyes = EYES_BOTH; _last_audio_time = DCPTime (); - _suspended = false; } void @@ -247,6 +246,7 @@ Player::playlist_content_change (ChangeType type, int property, bool frequent) } else if (type == CHANGE_TYPE_DONE) { /* A change in our content has gone through. Re-build our pieces. */ setup_pieces (); + _suspended = false; } else if (type == CHANGE_TYPE_CANCELLED) { boost::mutex::scoped_lock lm (_mutex); _suspended = false; @@ -463,6 +463,19 @@ Player::set_play_referenced () setup_pieces_unlocked (); } +static void +maybe_add_asset (list& a, shared_ptr r, Frame reel_trim_start, Frame reel_trim_end, DCPTime from, int const ffr) +{ + DCPOMATIC_ASSERT (r); + r->set_entry_point (r->entry_point() + reel_trim_start); + r->set_duration (r->duration() - reel_trim_start - reel_trim_end); + if (r->duration() > 0) { + a.push_back ( + ReferencedReelAsset(r, DCPTimePeriod(from, from + DCPTime::from_frames(r->duration(), ffr))) + ); + } +} + list Player::get_reel_assets () { @@ -483,59 +496,51 @@ Player::get_reel_assets () return a; } - int64_t offset = 0; + DCPOMATIC_ASSERT (j->video_frame_rate ()); + double const cfr = j->video_frame_rate().get(); + Frame const trim_start = j->trim_start().frames_round (cfr); + Frame const trim_end = j->trim_end().frames_round (cfr); + int const ffr = _film->video_frame_rate (); + + /* position in the asset from the start */ + int64_t offset_from_start = 0; + /* position in the asset from the end */ + int64_t offset_from_end = 0; BOOST_FOREACH (shared_ptr k, decoder->reels()) { + /* Assume that main picture duration is the length of the reel */ + offset_from_end += k->main_picture()->duration(); + } + + BOOST_FOREACH (shared_ptr k, decoder->reels()) { + + /* Assume that main picture duration is the length of the reel */ + int64_t const reel_duration = k->main_picture()->duration(); - DCPOMATIC_ASSERT (j->video_frame_rate ()); - double const cfr = j->video_frame_rate().get(); - Frame const trim_start = j->trim_start().frames_round (cfr); - Frame const trim_end = j->trim_end().frames_round (cfr); - int const ffr = _film->video_frame_rate (); + /* See doc/design/trim_reels.svg */ + Frame const reel_trim_start = min(reel_duration, max(int64_t(0), trim_start - offset_from_start)); + Frame const reel_trim_end = min(reel_duration, max(int64_t(0), reel_duration - (offset_from_end - trim_end))); - DCPTime const from = i->position() + DCPTime::from_frames (offset, _film->video_frame_rate()); + DCPTime const from = i->position() + DCPTime::from_frames (offset_from_start, _film->video_frame_rate()); if (j->reference_video ()) { - shared_ptr ra = k->main_picture (); - DCPOMATIC_ASSERT (ra); - ra->set_entry_point (ra->entry_point() + trim_start); - ra->set_duration (ra->duration() - trim_start - trim_end); - a.push_back ( - ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr))) - ); + maybe_add_asset (a, k->main_picture(), reel_trim_start, reel_trim_end, from, ffr); } if (j->reference_audio ()) { - shared_ptr ra = k->main_sound (); - DCPOMATIC_ASSERT (ra); - ra->set_entry_point (ra->entry_point() + trim_start); - ra->set_duration (ra->duration() - trim_start - trim_end); - a.push_back ( - ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr))) - ); + maybe_add_asset (a, k->main_sound(), reel_trim_start, reel_trim_end, from, ffr); } if (j->reference_text (TEXT_OPEN_SUBTITLE)) { - shared_ptr ra = k->main_subtitle (); - DCPOMATIC_ASSERT (ra); - ra->set_entry_point (ra->entry_point() + trim_start); - ra->set_duration (ra->duration() - trim_start - trim_end); - a.push_back ( - ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr))) - ); + maybe_add_asset (a, k->main_subtitle(), reel_trim_start, reel_trim_end, from, ffr); } if (j->reference_text (TEXT_CLOSED_CAPTION)) { BOOST_FOREACH (shared_ptr l, k->closed_captions()) { - DCPOMATIC_ASSERT (l); - l->set_entry_point (l->entry_point() + trim_start); - l->set_duration (l->duration() - trim_start - trim_end); - a.push_back ( - ReferencedReelAsset (l, DCPTimePeriod (from, from + DCPTime::from_frames (l->duration(), ffr))) - ); + maybe_add_asset (a, l, reel_trim_start, reel_trim_end, from, ffr); } } - /* Assume that main picture duration is the length of the reel */ - offset += k->main_picture()->duration (); + offset_from_start += reel_duration; + offset_from_end -= reel_duration; } } @@ -619,11 +624,10 @@ Player::pass () DCPTimePeriod period (_silent.period_at_position()); if (_last_audio_time) { /* Sometimes the thing that happened last finishes fractionally before - this silence. Bodge the start time of the silence to fix it. I'm - not sure if this is the right solution --- maybe the last thing should - be padded `forward' rather than this thing padding `back'. + or after this silence. Bodge the start time of the silence to fix it. */ - period.from = min(period.from, *_last_audio_time); + DCPOMATIC_ASSERT (labs(period.from.get() - _last_audio_time->get()) < 2); + period.from = *_last_audio_time; } if (period.duration() > one_video_frame()) { period.to = period.from + one_video_frame(); @@ -756,40 +760,44 @@ Player::video (weak_ptr wp, ContentVideo video) if (_last_video_time) { DCPTime fill_from = max (*_last_video_time, piece->content->position()); - LastVideoMap::const_iterator last = _last_video.find (wp); - if (_film->three_d()) { - Eyes fill_to_eyes = video.eyes; - if (fill_to_eyes == EYES_BOTH) { - fill_to_eyes = EYES_LEFT; - } - if (fill_to == piece->content->end(_film)) { - /* Don't fill after the end of the content */ - fill_to_eyes = EYES_LEFT; - } - DCPTime j = fill_from; - Eyes eyes = _last_video_eyes.get_value_or(EYES_LEFT); - if (eyes == EYES_BOTH) { - eyes = EYES_LEFT; - } - while (j < fill_to || eyes != fill_to_eyes) { - if (last != _last_video.end()) { - shared_ptr copy = last->second->shallow_copy(); - copy->set_eyes (eyes); - emit_video (copy, j); - } else { - emit_video (black_player_video_frame(eyes), j); + + /* Fill if we have more than half a frame to do */ + if ((fill_to - fill_from) > one_video_frame() / 2) { + LastVideoMap::const_iterator last = _last_video.find (wp); + if (_film->three_d()) { + Eyes fill_to_eyes = video.eyes; + if (fill_to_eyes == EYES_BOTH) { + fill_to_eyes = EYES_LEFT; } - if (eyes == EYES_RIGHT) { - j += one_video_frame(); + if (fill_to == piece->content->end(_film)) { + /* Don't fill after the end of the content */ + fill_to_eyes = EYES_LEFT; } - eyes = increment_eyes (eyes); - } - } else { - for (DCPTime j = fill_from; j < fill_to; j += one_video_frame()) { - if (last != _last_video.end()) { - emit_video (last->second, j); - } else { - emit_video (black_player_video_frame(EYES_BOTH), j); + DCPTime j = fill_from; + Eyes eyes = _last_video_eyes.get_value_or(EYES_LEFT); + if (eyes == EYES_BOTH) { + eyes = EYES_LEFT; + } + while (j < fill_to || eyes != fill_to_eyes) { + if (last != _last_video.end()) { + shared_ptr copy = last->second->shallow_copy(); + copy->set_eyes (eyes); + emit_video (copy, j); + } else { + emit_video (black_player_video_frame(eyes), j); + } + if (eyes == EYES_RIGHT) { + j += one_video_frame(); + } + eyes = increment_eyes (eyes); + } + } else { + for (DCPTime j = fill_from; j < fill_to; j += one_video_frame()) { + if (last != _last_video.end()) { + emit_video (last->second, j); + } else { + emit_video (black_player_video_frame(EYES_BOTH), j); + } } } } @@ -1093,12 +1101,12 @@ void Player::emit_audio (shared_ptr data, DCPTime time) { /* Log if the assert below is about to fail */ - if (_last_audio_time && time != *_last_audio_time) { + if (_last_audio_time && labs(time.get() - _last_audio_time->get()) > 1) { _film->log()->log(String::compose("Out-of-sequence emit %1 vs %2", to_string(time), to_string(*_last_audio_time)), LogEntry::TYPE_WARNING); } - /* This audio must follow on from the previous */ - DCPOMATIC_ASSERT (!_last_audio_time || time == *_last_audio_time); + /* This audio must follow on from the previous, allowing for half a sample (at 48kHz) leeway */ + DCPOMATIC_ASSERT (!_last_audio_time || labs(time.get() - _last_audio_time->get()) < 2); Audio (data, time, _film->audio_frame_rate()); _last_audio_time = time + DCPTime::from_frames (data->frames(), _film->audio_frame_rate()); }