summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/filter/af.c6
-rw-r--r--audio/filter/af.h1
-rw-r--r--player/audio.c59
3 files changed, 47 insertions, 19 deletions
diff --git a/audio/filter/af.c b/audio/filter/af.c
index a132965295..f380459747 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -779,6 +779,12 @@ struct mp_audio *af_read_output_frame(struct af_stream *s)
return af_dequeue_output_frame(s->last);
}
+void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame)
+{
+ struct af_instance *af = s->last;
+ MP_TARRAY_INSERT_AT(af, af->out_queued, af->num_out_queued, 0, frame);
+}
+
// Make sure the caller can change data referenced by the frame.
// Return negative error code on failure (i.e. you can't write).
int af_make_writeable(struct af_instance *af, struct mp_audio *frame)
diff --git a/audio/filter/af.h b/audio/filter/af.h
index 697024b781..a773f561b3 100644
--- a/audio/filter/af.h
+++ b/audio/filter/af.h
@@ -148,6 +148,7 @@ void af_add_output_frame(struct af_instance *af, struct mp_audio *frame);
int af_filter_frame(struct af_stream *s, struct mp_audio *frame);
int af_output_frame(struct af_stream *s, bool eof);
struct mp_audio *af_read_output_frame(struct af_stream *s);
+void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame);
int af_make_writeable(struct af_instance *af, struct mp_audio *frame);
double af_calc_delay(struct af_stream *s);
diff --git a/player/audio.c b/player/audio.c
index 9fe7eb802a..a98fa7784d 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -722,15 +722,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 +789,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 +814,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 +846,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;
@@ -918,10 +950,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 +1047,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;