static int check_framedrop(struct MPContext *mpctx, double frame_time) { struct MPOpts *opts = mpctx->opts; struct track *t_audio = mpctx->current_track[0][STREAM_AUDIO]; struct sh_stream *sh_audio = t_audio ? t_audio->stream : NULL; // check for frame-drop: if (mpctx->d_audio && !mpctx->ao->untimed && sh_audio && !demux_stream_eof(sh_audio)) { float delay = opts->playback_speed * ao_get_delay(mpctx->ao); float d = delay - mpctx->delay; float fps = mpctx->d_video->fps; if (frame_time < 0) frame_time = fps > 0 ? 1.0 / fps : 0; // we should avoid dropping too many frames in sequence unless we // are too late. and we allow 100ms A-V delay here: if (d < -mpctx->dropped_frames * frame_time - 0.100 && !mpctx->paused && !mpctx->restart_playback) { mpctx->drop_frame_cnt++; mpctx->dropped_frames++; return mpctx->opts->frame_dropping; } else mpctx->dropped_frames = 0; } return 0; }
int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) { struct MPOpts *opts = mpctx->opts; struct ao *ao = mpctx->ao; int playsize; int playflags = 0; bool audio_eof = false; bool signal_eof = false; bool partial_fill = false; sh_audio_t * const sh_audio = mpctx->sh_audio; bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK); int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8; if (mpctx->paused) playsize = 1; // just initialize things (audio pts at least) else playsize = ao_get_space(ao); // Coming here with hrseek_active still set means audio-only if (!mpctx->sh_video || !mpctx->sync_audio_to_video) mpctx->syncing_audio = false; if (!opts->initial_audio_sync || !modifiable_audio_format) { mpctx->syncing_audio = false; mpctx->hrseek_active = false; } int res; if (mpctx->syncing_audio || mpctx->hrseek_active) res = audio_start_sync(mpctx, playsize); else res = decode_audio(sh_audio, &ao->buffer, playsize); if (res < 0) { // EOF, error or format change if (res == -2) { /* The format change isn't handled too gracefully. A more precise * implementation would require draining buffered old-format audio * while displaying video, then doing the output format switch. */ if (!mpctx->opts->gapless_audio) uninit_player(mpctx, INITIALIZED_AO); reinit_audio_chain(mpctx); return -1; } else if (res == ASYNC_PLAY_DONE) return 0; else if (demux_stream_eof(mpctx->sh_audio->gsh)) audio_eof = true; } if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) { double bytes = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay) * ao->bps / opts->playback_speed; if (playsize > bytes) { playsize = MPMAX(bytes, 0); audio_eof = true; partial_fill = true; } } assert(ao->buffer.len % unitsize == 0); if (playsize > ao->buffer.len) { partial_fill = true; playsize = ao->buffer.len; } playsize -= playsize % unitsize; if (!playsize) return partial_fill && audio_eof ? -2 : -partial_fill; if (audio_eof && partial_fill) { if (opts->gapless_audio) { // With gapless audio, delay this to ao_uninit. There must be only // 1 final chunk, and that is handled when calling ao_uninit(). signal_eof = true; } else { playflags |= AOPLAY_FINAL_CHUNK; } } assert(ao->buffer_playable_size <= ao->buffer.len); int played = write_to_ao(mpctx, ao->buffer.start, playsize, playflags, written_audio_pts(mpctx)); ao->buffer_playable_size = playsize - played; if (played > 0) { ao->buffer.len -= played; memmove(ao->buffer.start, ao->buffer.start + played, ao->buffer.len); } else if (!mpctx->paused && audio_eof && ao_get_delay(ao) < .04) { // Sanity check to avoid hanging in case current ao doesn't output // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK signal_eof = true; } return signal_eof ? -2 : -partial_fill; }