summaryrefslogtreecommitdiffstats
path: root/player/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/audio.c')
-rw-r--r--player/audio.c81
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;
+ }
}
}