diff options
Diffstat (limited to 'player/audio.c')
-rw-r--r-- | player/audio.c | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/player/audio.c b/player/audio.c index 5b52eceb11..89f75d9095 100644 --- a/player/audio.c +++ b/player/audio.c @@ -229,7 +229,7 @@ int reinit_audio_filters(struct MPContext *mpctx) mpctx->playback_pts != MP_NOPTS_VALUE && delay > 0.2) { queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->playback_pts, - MPSEEK_EXACT, true); + MPSEEK_EXACT, 0); } return 1; } @@ -379,14 +379,18 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) if (opts->ao_null_fallback && !spdif_fallback) ao_flags |= AO_INIT_NULL_FALLBACK; - if (!opts->audio_output_channels.set || opts->audio_output_channels.auto_safe) - ao_flags |= AO_INIT_SAFE_MULTICHANNEL_ONLY; - if (opts->audio_stream_silence) ao_flags |= AO_INIT_STREAM_SILENCE; - mp_chmap_sel_list(&afs->output.channels, opts->audio_output_channels.chmaps, - opts->audio_output_channels.num_chmaps); + if (af_fmt_is_pcm(afs->output.format)) { + if (!opts->audio_output_channels.set || + opts->audio_output_channels.auto_safe) + ao_flags |= AO_INIT_SAFE_MULTICHANNEL_ONLY; + + mp_chmap_sel_list(&afs->output.channels, + opts->audio_output_channels.chmaps, + opts->audio_output_channels.num_chmaps); + } mp_audio_set_channels(&afs->output, &afs->output.channels); @@ -722,15 +726,40 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip) } -static bool copy_output(struct af_stream *afs, struct mp_audio_buffer *outbuf, - int minsamples, bool eof) +static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf, + int minsamples, double endpts, bool eof, bool *seteof) { + struct af_stream *afs = mpctx->ao_chain->af; + while (mp_audio_buffer_samples(outbuf) < minsamples) { if (af_output_frame(afs, eof) < 0) return true; // error, stop doing stuff + + int cursamples = mp_audio_buffer_samples(outbuf); + int maxsamples = INT_MAX; + if (endpts != MP_NOPTS_VALUE) { + double rate = afs->output.rate / mpctx->audio_speed; + double curpts = written_audio_pts(mpctx); + if (curpts != MP_NOPTS_VALUE) + maxsamples = (endpts - curpts - mpctx->opts->audio_delay) * rate; + } + struct mp_audio *mpa = af_read_output_frame(afs); if (!mpa) return false; // out of data + + if (cursamples + mpa->samples > maxsamples) { + if (cursamples < maxsamples) { + struct mp_audio pre = *mpa; + pre.samples = maxsamples - cursamples; + mp_audio_buffer_append(outbuf, &pre); + mp_audio_skip_samples(mpa, pre.samples); + } + af_unread_output_frame(afs, mpa); + *seteof = true; + return true; + } + mp_audio_buffer_append(outbuf, mpa); talloc_free(mpa); } @@ -764,20 +793,24 @@ static int decode_new_frame(struct ao_chain *ao_c) * Return 0 on success, or negative AD_* error code. * In the former case outbuf has at least minsamples buffered on return. * In case of EOF/error it might or might not be. */ -static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf, +static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf, int minsamples) { + struct ao_chain *ao_c = mpctx->ao_chain; struct af_stream *afs = ao_c->af; if (afs->initialized < 1) return AD_ERR; MP_STATS(ao_c, "start audio"); + double endpts = get_play_end_pts(mpctx); + + bool eof = false; int res; while (1) { res = 0; - if (copy_output(afs, outbuf, minsamples, false)) + if (copy_output(mpctx, outbuf, minsamples, endpts, false, &eof)) break; res = decode_new_frame(ao_c); @@ -785,13 +818,13 @@ static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf, break; if (res < 0) { // drain filters first (especially for true EOF case) - copy_output(afs, outbuf, minsamples, true); + copy_output(mpctx, outbuf, minsamples, endpts, true, &eof); break; } // On format change, make sure to drain the filter chain. if (!mp_audio_config_equals(&afs->input, ao_c->input_frame)) { - copy_output(afs, outbuf, minsamples, true); + copy_output(mpctx, outbuf, minsamples, endpts, true, &eof); res = AD_NEW_FMT; break; } @@ -817,6 +850,9 @@ static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf, return AD_ERR; } + if (res == 0 && mp_audio_buffer_samples(outbuf) < minsamples && eof) + res = AD_EOF; + MP_STATS(ao_c, "end audio"); return res; @@ -826,6 +862,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; struct ao_chain *ao_c = mpctx->ao_chain; + bool was_eof = mpctx->audio_status == STATUS_EOF; dump_audio_stats(mpctx); @@ -918,10 +955,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx) playsize = playsize / align * align; - int status = AD_OK; + int status = mpctx->audio_status >= STATUS_DRAINING ? AD_EOF : AD_OK; bool working = false; if (playsize > mp_audio_buffer_samples(ao_c->ao_buffer)) { - status = filter_audio(mpctx->ao_chain, ao_c->ao_buffer, playsize); + status = filter_audio(mpctx, ao_c->ao_buffer, playsize); if (status == AD_WAIT) return; if (status == AD_NO_PROGRESS) { @@ -1015,17 +1052,6 @@ void fill_audio_out_buffers(struct MPContext *mpctx) bool partial_fill = false; int playflags = 0; - double endpts = get_play_end_pts(mpctx); - if (endpts != MP_NOPTS_VALUE) { - double samples = (endpts - written_audio_pts(mpctx) - opts->audio_delay) - * play_samplerate; - if (playsize > samples) { - playsize = MPMAX((int)samples / align * align, 0); - audio_eof = true; - partial_fill = true; - } - } - if (playsize > mp_audio_buffer_samples(ao_c->ao_buffer)) { playsize = mp_audio_buffer_samples(ao_c->ao_buffer); partial_fill = true; @@ -1057,8 +1083,11 @@ void fill_audio_out_buffers(struct MPContext *mpctx) mpctx->audio_status = STATUS_DRAINING; // Wait until the AO has played all queued data. In the gapless case, // we trigger EOF immediately, and let it play asynchronously. - if (ao_eof_reached(mpctx->ao) || opts->gapless_audio) + if (ao_eof_reached(mpctx->ao) || opts->gapless_audio) { mpctx->audio_status = STATUS_EOF; + if (!was_eof) + mpctx->sleeptime = 0; + } } } |