summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/out/ao.c6
-rw-r--r--audio/out/ao.h3
-rw-r--r--audio/out/ao_lavc.c59
-rw-r--r--mpvcore/player/audio.c25
-rw-r--r--mpvcore/player/loadfile.c26
-rw-r--r--mpvcore/player/playloop.c4
6 files changed, 77 insertions, 46 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index 3f0865af22..ccbcc16e88 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -198,11 +198,7 @@ autoprobe:
void ao_uninit(struct ao *ao, bool cut_audio)
{
- assert(ao->buffer.len >= ao->buffer_playable_size);
- ao->buffer.len = ao->buffer_playable_size;
ao->driver->uninit(ao, cut_audio);
- if (!cut_audio && ao->buffer.len)
- mp_msg(MSGT_AO, MSGL_WARN, "Audio output truncated at end.\n");
talloc_free(ao);
}
@@ -234,8 +230,6 @@ int ao_get_space(struct ao *ao)
void ao_reset(struct ao *ao)
{
- ao->buffer.len = 0;
- ao->buffer_playable_size = 0;
if (ao->driver->reset)
ao->driver->reset(ao);
}
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 3d64102ada..7e7b6968bb 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -73,7 +73,8 @@ struct ao {
int bps; // bytes per second
double pts; // some mplayer.c state (why is this here?)
struct bstr buffer;
- int buffer_playable_size;
+ int buffer_playable_size; // part of the part of the buffer the AO hasn't
+ // accepted yet with play()
bool probing; // if true, don't fail loudly on init
bool untimed;
bool no_persistent_volume; // the AO does the equivalent of af_volume
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index eb41710b82..4364b9054d 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -299,7 +299,6 @@ static int encode(struct ao *ao, double apts, void *data);
static int play(struct ao *ao, void *data, int len, int flags);
static void uninit(struct ao *ao, bool cut_audio)
{
- struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
if (!encode_lavc_start(ectx)) {
@@ -307,33 +306,6 @@ static void uninit(struct ao *ao, bool cut_audio)
return;
}
- if (ac->buffer) {
- if (ao->buffer.len > 0) {
- // TRICK: append aframesize-1 samples to the end, then play() will
- // encode all it can
- size_t extralen =
- (ac->aframesize - 1) * ao->channels.num * ac->sample_size;
- void *paddingbuf = talloc_size(ao, ao->buffer.len + extralen);
- memcpy(paddingbuf, ao->buffer.start, ao->buffer.len);
- fill_with_padding((char *) paddingbuf + ao->buffer.len,
- extralen / ac->sample_size,
- ac->sample_size, ac->sample_padding);
- int written = play(ao, paddingbuf, ao->buffer.len + extralen, 0);
- if (written < ao->buffer.len) {
- MP_ERR(ao, "did not write enough data at the end\n");
- }
- talloc_free(paddingbuf);
- ao->buffer.len = 0;
- }
-
- double outpts = ac->expected_next_pts;
- if (!ectx->options->rawts && ectx->options->copyts)
- outpts += ectx->discontinuity_pts_offset;
- outpts += encode_lavc_getoffset(ectx, ac->stream);
-
- while (encode(ao, outpts, NULL) > 0) ;
- }
-
ao->priv = NULL;
}
@@ -484,6 +456,7 @@ static int play(struct ao *ao, void *data, int len, int flags)
double nextpts;
double pts = ao->pts;
double outpts;
+ int bytelen = len;
len /= ac->sample_size * ao->channels.num;
@@ -491,6 +464,36 @@ static int play(struct ao *ao, void *data, int len, int flags)
MP_WARN(ao, "not ready yet for encoding audio\n");
return 0;
}
+
+ if (flags & AOPLAY_FINAL_CHUNK) {
+ int written = 0;
+ if (len > 0) {
+ size_t extralen =
+ (ac->aframesize - 1) * ao->channels.num * ac->sample_size;
+ paddingbuf = talloc_size(NULL, bytelen + extralen);
+ memcpy(paddingbuf, data, bytelen);
+ fill_with_padding((char *) paddingbuf + bytelen,
+ extralen / ac->sample_size,
+ ac->sample_size, ac->sample_padding);
+ // No danger of recursion, because AOPLAY_FINAL_CHUNK not set
+ written = play(ao, paddingbuf, bytelen + extralen, 0);
+ if (written < bytelen) {
+ MP_ERR(ao, "did not write enough data at the end\n");
+ }
+ talloc_free(paddingbuf);
+ paddingbuf = NULL;
+ }
+
+ outpts = ac->expected_next_pts;
+ if (!ectx->options->rawts && ectx->options->copyts)
+ outpts += ectx->discontinuity_pts_offset;
+ outpts += encode_lavc_getoffset(ectx, ac->stream);
+
+ while (encode(ao, outpts, NULL) > 0) ;
+
+ return FFMIN(written, bytelen);
+ }
+
if (pts == MP_NOPTS_VALUE) {
MP_WARN(ao, "frame without pts, please report; synthesizing pts instead\n");
// synthesize pts from previous expected next pts
diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c
index 443a1eed90..2c3d044c41 100644
--- a/mpvcore/player/audio.c
+++ b/mpvcore/player/audio.c
@@ -225,10 +225,13 @@ static int write_to_ao(struct MPContext *mpctx, void *data, int len, int flags,
return 0;
struct ao *ao = mpctx->ao;
double bps = ao->bps / mpctx->opts->playback_speed;
+ int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8;
ao->pts = pts;
int played = ao_play(mpctx->ao, data, len, flags);
+ assert(played <= len);
+ assert(played % unitsize == 0);
if (played > 0) {
- mpctx->shown_aframes += played / (af_fmt2bits(ao->format) / 8);
+ mpctx->shown_aframes += played / unitsize;
mpctx->delay += played / bps;
// Keep correct pts for remaining data - could be used to flush
// remaining buffer when closing ao.
@@ -332,6 +335,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
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);
@@ -377,7 +381,6 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
* ao->bps / opts->playback_speed;
if (playsize > bytes) {
playsize = MPMAX(bytes, 0);
- playflags |= AOPLAY_FINAL_CHUNK;
audio_eof = true;
partial_fill = true;
}
@@ -387,18 +390,24 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
if (playsize > ao->buffer.len) {
partial_fill = true;
playsize = ao->buffer.len;
- if (audio_eof)
- playflags |= AOPLAY_FINAL_CHUNK;
}
playsize -= playsize % unitsize;
if (!playsize)
return partial_fill && audio_eof ? -2 : -partial_fill;
- // play audio:
+ 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));
- assert(played % unitsize == 0);
ao->buffer_playable_size = playsize - played;
if (played > 0) {
@@ -407,8 +416,8 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
} 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
- return -2;
+ signal_eof = true;
}
- return -partial_fill;
+ return signal_eof ? -2 : -partial_fill;
}
diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c
index baa49f0db5..569532840c 100644
--- a/mpvcore/player/loadfile.c
+++ b/mpvcore/player/loadfile.c
@@ -62,6 +62,8 @@
void uninit_player(struct MPContext *mpctx, unsigned int mask)
{
+ struct MPOpts *opts = mpctx->opts;
+
mask &= mpctx->initialized_flags;
MP_DBG(mpctx, "\n*** uninit(0x%X)\n", mask);
@@ -154,9 +156,22 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
}
if (mask & INITIALIZED_AO) {
+ struct ao *ao = mpctx->ao;
mpctx->initialized_flags &= ~INITIALIZED_AO;
- if (mpctx->ao)
- ao_uninit(mpctx->ao, mpctx->stop_play != AT_END_OF_FILE);
+ if (ao) {
+ bool drain = false;
+ // Note: with gapless_audio, stop_play is not correctly set
+ if (opts->gapless_audio || mpctx->stop_play == AT_END_OF_FILE) {
+ drain = true;
+ int len = ao->buffer_playable_size;
+ assert(len <= ao->buffer.len);
+ int played = ao_play(ao, ao->buffer.start, len,
+ AOPLAY_FINAL_CHUNK);
+ if (played < len)
+ MP_WARN(ao, "Audio output truncated at end.\n");
+ }
+ ao_uninit(ao, drain);
+ }
mpctx->ao = NULL;
}
@@ -1277,6 +1292,13 @@ terminate_playback: // don't jump here after ao/vo/getch initialization!
if (mpctx->stop_play == KEEP_PLAYING)
mpctx->stop_play = AT_END_OF_FILE;
+ // Drop audio left in the buffers
+ if (mpctx->stop_play != AT_END_OF_FILE && mpctx->ao) {
+ mpctx->ao->buffer_playable_size = 0;
+ mpctx->ao->buffer.len = 0;
+ ao_reset(mpctx->ao);
+ }
+
if (opts->position_save_on_quit && mpctx->stop_play == PT_QUIT)
mp_write_watch_later_conf(mpctx);
diff --git a/mpvcore/player/playloop.c b/mpvcore/player/playloop.c
index d4db03c446..6cd53214a2 100644
--- a/mpvcore/player/playloop.c
+++ b/mpvcore/player/playloop.c
@@ -254,10 +254,12 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
if (demuxer_amount == -1) {
assert(!need_reset);
mpctx->stop_play = AT_END_OF_FILE;
- // Clear audio from current position
if (mpctx->sh_audio && !timeline_fallthrough) {
+ // Seek outside of the file -> clear audio from current position
ao_reset(mpctx->ao);
mpctx->sh_audio->a_buffer_len = 0;
+ mpctx->ao->buffer.len = 0;
+ mpctx->ao->buffer_playable_size = 0;
}
return -1;
}