X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=3db2fe6c9eb19074be6f265f7fd4ffe6918ca61d;hb=d7b23d44dec9d6357619e8e009e564e475215470;hp=037af6f4e1041003e065b305766018a28d03cd7f;hpb=1c5ffd1b20222689439457ab91cd09c3a5a57193;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index 037af6f4e..3db2fe6c9 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" @@ -107,13 +108,37 @@ Player::pass () for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { - shared_ptr dec = (*i)->decoder->peek (); + DCPTime const offset = (*i)->content->position() - (*i)->content->trim_start(); + + bool done = false; + shared_ptr dec; + while (!done) { + dec = (*i)->decoder->peek (); + if (!dec) { + /* Decoder has nothing else to give us */ + break; + } - if (dec) { - dec->set_dcp_times ((*i)->frc.speed_up, (*i)->content->position() - (*i)->content->trim_start()); + dec->set_dcp_times (_film->video_frame_rate(), _film->audio_frame_rate(), (*i)->frc, offset); + DCPTime const t = dec->dcp_time - offset; + if (t >= ((*i)->content->full_length() - (*i)->content->trim_end ())) { + /* In the end-trimmed part; decoder has nothing else to give us */ + dec.reset (); + done = true; + } else if (t >= (*i)->content->trim_start ()) { + /* Within the un-trimmed part; everything's ok */ + done = true; + } else { + /* Within the start-trimmed part; get something else */ + (*i)->decoder->consume (); + } } - if (dec && dec->dcp_time < earliest_time) { + if (!dec) { + continue; + } + + if (dec->dcp_time < earliest_time) { earliest_piece = *i; earliest_decoded = dec; earliest_time = dec->dcp_time; @@ -130,7 +155,7 @@ 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. @@ -147,11 +172,6 @@ Player::pass () /* 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) { if (_just_did_inaccurate_seek) { @@ -160,7 +180,7 @@ Player::pass () emit_video (earliest_piece, dv); step_video_position (dv); - } else if (dv->dcp_time - _video_position > margin) { + } else if (dv->dcp_time > _video_position) { /* Too far ahead */ @@ -172,36 +192,43 @@ Player::pass () if (i == _pieces.end() || !_last_incoming_video.video || !_have_valid_pieces) { /* We're outside all video content */ emit_black (); + _statistics.video.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); + _statistics.video.repeat++; } consume = false; - } else if (abs (dv->dcp_time - _video_position) < margin) { + } else if (dv->dcp_time == _video_position) { /* We're ok */ emit_video (earliest_piece, dv); step_video_position (dv); + _statistics.video.good++; } else { /* Too far behind: skip */ + _statistics.video.skip++; } _just_did_inaccurate_seek = false; } else if (da && _audio) { - if (da->dcp_time - _audio_position > margin) { + if (da->dcp_time > _audio_position) { /* Too far ahead */ emit_silence (da->dcp_time - _audio_position); consume = false; - } else if (abs (da->dcp_time - _audio_position) < margin) { + _statistics.audio.silence += (da->dcp_time - _audio_position); + } else if (da->dcp_time == _audio_position) { /* We're ok */ emit_audio (earliest_piece, da); + _statistics.audio.good += da->data->frames(); } else { /* Too far behind: skip */ + _statistics.audio.skip += da->data->frames(); } } else if (ds && _video) { @@ -304,10 +331,6 @@ Player::emit_audio (weak_ptr weak_piece, shared_ptr audio) audio->data = gain; } - if (content->trimmed (audio->dcp_time - content->position ())) { - return; - } - /* Remap channels */ shared_ptr dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames())); dcp_mapped->make_silent (); @@ -342,16 +365,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); } @@ -379,7 +402,7 @@ Player::seek (DCPTime t, bool accurate) s = min ((*i)->content->length_after_trim(), s); /* Convert this to the content time */ - ContentTime ct = (s * (*i)->frc.speed_up) + (*i)->content->trim_start (); + ContentTime ct = (s + (*i)->content->trim_start()) * (*i)->frc.speed_up; /* And seek the decoder */ (*i)->decoder->seek (ct, accurate); @@ -469,7 +492,8 @@ Player::setup_pieces () } } - decoder->seek ((*i)->trim_start (), true); + ContentTime st = (*i)->trim_start() * frc->speed_up; + decoder->seek (st, true); _pieces.push_back (shared_ptr (new Piece (*i, decoder, frc.get ()))); } @@ -693,3 +717,15 @@ PlayerImage::image (AVPixelFormat format, bool aligned) return out; } +void +PlayerStatistics::dump (shared_ptr log) const +{ + log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat)); + log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence)); +} + +PlayerStatistics const & +Player::statistics () const +{ + return _statistics; +}