X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=c9f9acd942179561184fb2c32bd70e2ee65a24b9;hp=a5f0006d99547cdf000ebad7b0b1e83aa53c6c27;hb=ad49361b303d1ceff7048fa0e89ba609ca9ce376;hpb=e194f0003b60b2607da0822485c56cd8267e78dc diff --git a/src/lib/player.cc b/src/lib/player.cc index a5f0006d9..c9f9acd94 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -18,6 +18,7 @@ */ #include +#include #include "player.h" #include "film.h" #include "ffmpeg_decoder.h" @@ -110,7 +111,7 @@ Player::pass () shared_ptr dec = (*i)->decoder->peek (); if (dec) { - dec->set_dcp_times ((*i)->frc.speed_up, (*i)->content->position()); + dec->set_dcp_times ((*i)->frc.speed_up, (*i)->content->position() - (*i)->content->trim_start()); } if (dec && dec->dcp_time < earliest_time) { @@ -130,8 +131,11 @@ Player::pass () } if (earliest_audio != TIME_MAX) { - TimedAudioBuffers tb = _audio_merger.pull (earliest_audio); + TimedAudioBuffers tb = _audio_merger.pull (max (int64_t (0), earliest_audio)); Audio (tb.audio, tb.time); + /* This assumes that the audio_frames_to_time conversion is exact + so that there are no accumulated errors caused by rounding. + */ _audio_position += _film->audio_frames_to_time (tb.audio->frames ()); } @@ -141,16 +145,26 @@ Player::pass () shared_ptr da = dynamic_pointer_cast (earliest_decoded); shared_ptr ds = dynamic_pointer_cast (earliest_decoded); + /* Will be set to false if we shouldn't consume the peeked DecodedThing */ + bool consume = true; + + /* This is the margin either side of _{video,audio}_position that we will accept + as a starting point for a frame consecutive to the previous. + */ + DCPTime const margin = TIME_HZ / (2 * _film->video_frame_rate ()); + if (dv && _video) { - DCPTime const half_frame = TIME_HZ / (2 * _film->video_frame_rate ()); if (_just_did_inaccurate_seek) { + /* Just emit; no subtlety */ emit_video (earliest_piece, dv); - earliest_piece->decoder->get (); - } else if (earliest_time > (_video_position + half_frame)) { + step_video_position (dv); + + } else if (dv->dcp_time - _video_position > margin) { + + /* Too far ahead */ - /* See if we're inside some video content */ list >::iterator i = _pieces.begin(); while (i != _pieces.end() && ((*i)->content->position() >= _video_position || _video_position >= (*i)->content->end())) { ++i; @@ -160,39 +174,47 @@ Player::pass () /* We're outside all video content */ emit_black (); } else { + /* We're inside some video; repeat the frame */ _last_incoming_video.video->dcp_time = _video_position; emit_video (_last_incoming_video.weak_piece, _last_incoming_video.video); + step_video_position (_last_incoming_video.video); } - } else { - - if ( - dv->dcp_time >= _video_position && - !earliest_piece->content->trimmed (dv->dcp_time - earliest_piece->content->position ()) - ) { + consume = false; - emit_video (earliest_piece, dv); - } - - earliest_piece->decoder->get (); + } else if (abs (dv->dcp_time - _video_position) < margin) { + /* We're ok */ + emit_video (earliest_piece, dv); + step_video_position (dv); + } else { + /* Too far behind: skip */ } + _just_did_inaccurate_seek = false; + } else if (da && _audio) { - if (!_just_did_inaccurate_seek && earliest_time > _audio_position) { - emit_silence (earliest_time - _audio_position); - } else { + + if (da->dcp_time - _audio_position > margin) { + /* Too far ahead */ + emit_silence (da->dcp_time - _audio_position); + consume = false; + } else if (abs (da->dcp_time - _audio_position) < margin) { + /* We're ok */ emit_audio (earliest_piece, da); - earliest_piece->decoder->get (); + } else { + /* Too far behind: skip */ } + } else if (ds && _video) { _in_subtitle.piece = earliest_piece; _in_subtitle.subtitle = ds; update_subtitle (); - earliest_piece->decoder->get (); } - _just_did_inaccurate_seek = false; - + if (consume) { + earliest_piece->decoder->consume (); + } + return false; } @@ -232,16 +254,16 @@ Player::emit_video (weak_ptr weak_piece, shared_ptr video) if ( _film->with_subtitles () && - _out_subtitle.subtitle->image && - video->dcp_time >= _out_subtitle.subtitle->dcp_time && video->dcp_time <= _out_subtitle.subtitle->dcp_time_to + _out_subtitle.image && + video->dcp_time >= _out_subtitle.from && video->dcp_time <= _out_subtitle.to ) { Position const container_offset ( (_video_container_size.width - image_size.width) / 2, - (_video_container_size.height - image_size.width) / 2 + (_video_container_size.height - image_size.height) / 2 ); - pi->set_subtitle (_out_subtitle.subtitle->image, _out_subtitle.position + container_offset); + pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset); } #ifdef DCPOMATIC_DEBUG @@ -251,10 +273,17 @@ Player::emit_video (weak_ptr weak_piece, shared_ptr video) Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time); _last_emit_was_black = false; +} +void +Player::step_video_position (shared_ptr video) +{ /* This is a bit of a hack; don't update _video_position if EYES_RIGHT is on its way */ if (video->eyes != EYES_LEFT) { - _video_position = rint (video->dcp_time + TIME_HZ / _film->video_frame_rate()); + /* This assumes that the video_frames_to_time conversion is exact + so that there are no accumulated errors caused by rounding. + */ + _video_position += _film->video_frames_to_time (1); } } @@ -314,16 +343,16 @@ void Player::flush () { TimedAudioBuffers tb = _audio_merger.flush (); - if (tb.audio) { + if (_audio && tb.audio) { Audio (tb.audio, tb.time); _audio_position += _film->audio_frames_to_time (tb.audio->frames ()); } - while (_video_position < _audio_position) { + while (_video && _video_position < _audio_position) { emit_black (); } - while (_audio_position < _video_position) { + while (_audio && _audio_position < _video_position) { emit_silence (_video_position - _audio_position); } @@ -561,7 +590,7 @@ Player::update_subtitle () } if (!_in_subtitle.subtitle->image) { - _out_subtitle.subtitle->image.reset (); + _out_subtitle.image.reset (); return; } @@ -591,16 +620,16 @@ Player::update_subtitle () _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2))); _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2))); - - _out_subtitle.subtitle->image = _in_subtitle.subtitle->image->scale ( + + _out_subtitle.image = _in_subtitle.subtitle->image->scale ( scaled_size, Scaler::from_id ("bicubic"), - _in_subtitle.subtitle->image->pixel_format (), + PIX_FMT_RGBA, true ); - - _out_subtitle.subtitle->dcp_time = _in_subtitle.subtitle->dcp_time; - _out_subtitle.subtitle->dcp_time = _in_subtitle.subtitle->dcp_time; + + _out_subtitle.from = _in_subtitle.subtitle->dcp_time; + _out_subtitle.to = _in_subtitle.subtitle->dcp_time_to; } /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.