diff options
-rw-r--r-- | audio/decode/dec_audio.c | 54 | ||||
-rw-r--r-- | audio/decode/dec_audio.h | 7 | ||||
-rw-r--r-- | audio/out/ao.c | 12 | ||||
-rw-r--r-- | audio/out/ao.h | 6 | ||||
-rw-r--r-- | mpvcore/player/audio.c | 134 | ||||
-rw-r--r-- | mpvcore/player/loadfile.c | 12 |
6 files changed, 112 insertions, 113 deletions
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index ef7993c83a..3f92c3c4e6 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -38,6 +38,7 @@ #include "dec_audio.h" #include "ad.h" #include "audio/format.h" +#include "audio/audio_buffer.h" #include "audio/filter/af.h" @@ -230,18 +231,9 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, return 1; } -static void set_min_out_buffer_size(struct bstr *outbuf, int len) -{ - size_t oldlen = talloc_get_size(outbuf->start); - if (oldlen < len) { - assert(outbuf->start); // talloc context should be already set - mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size " - "from %zd to %d\n", oldlen, len); - outbuf->start = talloc_realloc_size(NULL, outbuf->start, len); - } -} - -static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) +// Filter len bytes of input, put result into outbuf. +static int filter_n_bytes(sh_audio_t *sh, struct mp_audio_buffer *outbuf, + int len) { assert(len - 1 + sh->audio_out_minsize <= sh->a_buffer_size); @@ -280,10 +272,7 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) struct mp_audio *filter_output = af_play(sh->afilter, &filter_input); if (!filter_output) return -1; - int outlen = filter_output->samples * filter_output->sstride; - set_min_out_buffer_size(outbuf, outbuf->len + outlen); - memcpy(outbuf->start + outbuf->len, filter_output->planes[0], outlen); - outbuf->len += outlen; + mp_audio_buffer_append(outbuf, filter_output); // remove processed data from decoder buffer: sh->a_buffer_len -= len; @@ -292,20 +281,20 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) return error; } -/* Try to get at least minlen decoded+filtered bytes in outbuf +/* Try to get at least minsamples decoded+filtered samples in outbuf * (total length including possible existing data). * Return 0 on success, -1 on error/EOF (not distinguished). - * In the former case outbuf->len is always >= minlen on return. - * In case of EOF/error it might or might not be. - * Outbuf.start must be talloc-allocated, and will be reallocated - * if needed to fit all filter output. */ -int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) + * In the former case outbuf has at least minsamples buffered on return. + * In case of EOF/error it might or might not be. */ +int decode_audio(sh_audio_t *sh_audio, struct mp_audio_buffer *outbuf, + int minsamples) { // Indicates that a filter seems to be buffering large amounts of data int huge_filter_buffer = 0; + int sstride = + af_fmt2bits(sh_audio->sample_format) / 8 * sh_audio->channels.num; // Decoded audio must be cut at boundaries of this many bytes - int bps = af_fmt2bits(sh_audio->sample_format) / 8; - int unitsize = sh_audio->channels.num * bps * 16; + int unitsize = sstride * 16; /* Filter output size will be about filter_multiplier times input size. * If some filter buffers audio in big blocks this might only hold @@ -322,9 +311,13 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) return -1; max_decode_len -= max_decode_len % unitsize; - while (minlen >= 0 && outbuf->len < minlen) { + while (minsamples >= 0 && mp_audio_buffer_samples(outbuf) < minsamples) { + struct af_stream *afs = sh_audio->afilter; + int out_sstride = afs->output.sstride; + int declen = (minsamples - mp_audio_buffer_samples(outbuf)) + * out_sstride / filter_multiplier; // + some extra for possible filter buffering - int declen = (minlen - outbuf->len) / filter_multiplier + (unitsize << 5); + declen += unitsize << 5; if (huge_filter_buffer) /* Some filter must be doing significant buffering if the estimated * input length didn't produce enough output from filters. @@ -349,15 +342,6 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) return 0; } -void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte) -{ - set_min_out_buffer_size(outbuf, outbuf->len + count); - memmove(outbuf->start + count, outbuf->start, outbuf->len); - memset(outbuf->start, byte, count); - outbuf->len += count; -} - - void resync_audio_stream(sh_audio_t *sh_audio) { sh_audio->pts = MP_NOPTS_VALUE; diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index b46f4282fb..3ec5954471 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -22,15 +22,14 @@ #include "audio/chmap.h" #include "demux/stheader.h" -struct bstr; +struct mp_audio_buffer; struct mp_decoder_list; struct mp_decoder_list *mp_audio_decoder_list(void); int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders); -int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen); -void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte); +int decode_audio(sh_audio_t *sh_audio, struct mp_audio_buffer *outbuf, + int minsamples); void resync_audio_stream(sh_audio_t *sh_audio); -void skip_audio_frame(sh_audio_t *sh_audio); void uninit_audio(sh_audio_t *sh_audio); int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, diff --git a/audio/out/ao.c b/audio/out/ao.c index fd20270160..50c95830c3 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -209,10 +209,9 @@ void ao_uninit(struct ao *ao, bool cut_audio) talloc_free(ao); } -int ao_play(struct ao *ao, void *data, int len, int flags) +int ao_play(struct ao *ao, void **data, int samples, int flags) { - int r = ao->driver->play(ao, &data, len / ao->sstride, flags); - return r < 0 ? r : r * ao->sstride; + return ao->driver->play(ao, data, samples, flags); } int ao_control(struct ao *ao, enum aocontrol cmd, void *arg) @@ -233,7 +232,7 @@ double ao_get_delay(struct ao *ao) int ao_get_space(struct ao *ao) { - return ao->driver->get_space(ao) * ao->sstride; + return ao->driver->get_space(ao); } void ao_reset(struct ao *ao) @@ -260,7 +259,10 @@ int ao_play_silence(struct ao *ao, int samples) return 0; char *p = talloc_size(NULL, samples * ao->sstride); af_fill_silence(p, samples * ao->sstride, ao->format); - int r = ao_play(ao, p, samples * ao->sstride, 0); + void *tmp[MP_NUM_CHANNELS]; + for (int n = 0; n < MP_NUM_CHANNELS; n++) + tmp[n] = p; + int r = ao_play(ao, tmp, samples, 0); talloc_free(p); return r; } diff --git a/audio/out/ao.h b/audio/out/ao.h index eb1af990ff..dff9ad6a8b 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -76,8 +76,8 @@ struct ao { int sstride; // size of a sample on each plane // (format_size*num_channels/num_planes) double pts; // some mplayer.c state (why is this here?) - struct bstr buffer; - int buffer_playable_size; // part of the part of the buffer the AO hasn't + struct mp_audio_buffer *buffer; // queued audio; passed to play() later + int buffer_playable_samples;// 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; @@ -97,7 +97,7 @@ struct ao *ao_init_best(struct mpv_global *global, struct encode_lavc_context *encode_lavc_ctx, int samplerate, int format, struct mp_chmap channels); void ao_uninit(struct ao *ao, bool cut_audio); -int ao_play(struct ao *ao, void *data, int len, int flags); +int ao_play(struct ao *ao, void **data, int samples, int flags); int ao_control(struct ao *ao, enum aocontrol cmd, void *arg); double ao_get_delay(struct ao *ao); int ao_get_space(struct ao *ao); diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c index e0c35c628e..fa29778fe9 100644 --- a/mpvcore/player/audio.c +++ b/mpvcore/player/audio.c @@ -30,6 +30,8 @@ #include "mpvcore/mp_common.h" #include "audio/mixer.h" +#include "audio/audio.h" +#include "audio/audio_buffer.h" #include "audio/decode/dec_audio.h" #include "audio/filter/af.h" #include "audio/out/ao.h" @@ -147,7 +149,11 @@ void reinit_audio_chain(struct MPContext *mpctx) MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n"); goto init_error; } - ao->buffer.start = talloc_new(ao); + + ao->buffer = mp_audio_buffer_create(ao); + mp_audio_buffer_reinit_fmt(ao->buffer, ao->format, &ao->channels, + ao->samplerate); + char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format); MP_INFO(mpctx, "AO: [%s] %s\n", ao->driver->name, s); talloc_free(s); @@ -196,16 +202,16 @@ double written_audio_pts(struct MPContext *mpctx) // Decoded but not filtered a_pts -= sh_audio->a_buffer_len / bps; - // Data buffered in audio filters, measured in bytes of "missing" output - double buffered_output = af_calc_delay(sh_audio->afilter); + // Data buffered in audio filters, measured in seconds of "missing" output + double buffered_output = af_calc_delay(sh_audio->afilter) / mpctx->ao->bps; // Data that was ready for ao but was buffered because ao didn't fully // accept everything to internal buffers yet - buffered_output += mpctx->ao->buffer.len; + buffered_output += mp_audio_buffer_seconds(mpctx->ao->buffer); // Filters divide audio length by playback_speed, so multiply by it // to get the length in original units without speedup or slowdown - a_pts -= buffered_output * mpctx->opts->playback_speed / mpctx->ao->bps; + a_pts -= buffered_output * mpctx->opts->playback_speed; return a_pts + mpctx->video_offset; } @@ -219,29 +225,42 @@ double playing_audio_pts(struct MPContext *mpctx) return pts - mpctx->opts->playback_speed * ao_get_delay(mpctx->ao); } -static int write_to_ao(struct MPContext *mpctx, void *data, int len, int flags, +static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags, double pts) { if (mpctx->paused) 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); + double real_samplerate = ao->samplerate / mpctx->opts->playback_speed; + int played = ao_play(mpctx->ao, data->planes, data->samples, flags); + assert(played <= data->samples); if (played > 0) { - mpctx->shown_aframes += played / unitsize; - mpctx->delay += played / bps; + mpctx->shown_aframes += played; + mpctx->delay += played / real_samplerate; // Keep correct pts for remaining data - could be used to flush // remaining buffer when closing ao. - ao->pts += played / bps; + ao->pts += played / real_samplerate; return played; } return 0; } +static int write_silence_to_ao(struct MPContext *mpctx, int samples, int flags, + double pts) +{ + struct mp_audio tmp = {0}; + mp_audio_buffer_get_format(mpctx->ao->buffer, &tmp); + tmp.samples = samples; + char *p = talloc_size(NULL, tmp.samples * tmp.sstride); + for (int n = 0; n < tmp.num_planes; n++) + tmp.planes[n] = p; + mp_audio_fill_silence(&tmp, 0, tmp.samples); + int r = write_to_ao(mpctx, &tmp, 0, pts); + talloc_free(p); + return r; +} + #define ASYNC_PLAY_DONE -3 static int audio_start_sync(struct MPContext *mpctx, int playsize) { @@ -251,14 +270,14 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize) int res; // Timing info may not be set without - res = decode_audio(sh_audio, &ao->buffer, 1); + res = decode_audio(sh_audio, ao->buffer, 1); if (res < 0) return res; - int bytes; + int samples; bool did_retry = false; double written_pts; - double bps = ao->bps / opts->playback_speed; + double real_samplerate = ao->samplerate / opts->playback_speed; bool hrseek = mpctx->hrseek_active; // audio only hrseek mpctx->hrseek_active = false; while (1) { @@ -269,64 +288,56 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize) else ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay - mpctx->audio_delay; - bytes = ptsdiff * bps; - bytes -= bytes % (ao->channels.num * af_fmt2bits(ao->format) / 8); + samples = ptsdiff * real_samplerate; // ogg demuxers give packets without timing if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) { if (!did_retry) { // Try to read more data to see packets that have pts - res = decode_audio(sh_audio, &ao->buffer, ao->bps); + res = decode_audio(sh_audio, ao->buffer, ao->samplerate); if (res < 0) return res; did_retry = true; continue; } - bytes = 0; + samples = 0; } if (fabs(ptsdiff) > 300 || isnan(ptsdiff)) // pts reset or just broken? - bytes = 0; + samples = 0; - if (bytes > 0) + if (samples > 0) break; mpctx->syncing_audio = false; - int a = MPMIN(-bytes, MPMAX(playsize, 20000)); - res = decode_audio(sh_audio, &ao->buffer, a); - bytes += ao->buffer.len; - if (bytes >= 0) { - memmove(ao->buffer.start, - ao->buffer.start + ao->buffer.len - bytes, bytes); - ao->buffer.len = bytes; + int skip_samples = -samples; + int a = MPMIN(skip_samples, MPMAX(playsize, 2500)); + res = decode_audio(sh_audio, ao->buffer, a); + if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) { + mp_audio_buffer_skip(ao->buffer, skip_samples); if (res < 0) return res; - return decode_audio(sh_audio, &ao->buffer, playsize); + return decode_audio(sh_audio, ao->buffer, playsize); } - ao->buffer.len = 0; + mp_audio_buffer_clear(ao->buffer); if (res < 0) return res; } if (hrseek) // Don't add silence in audio-only case even if position is too late return 0; - int fillbyte = 0; - if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) - fillbyte = 0x80; - if (bytes >= playsize) { + if (samples >= playsize) { /* This case could fall back to the one below with - * bytes = playsize, but then silence would keep accumulating - * in a_out_buffer if the AO accepts less data than it asks for + * samples = playsize, but then silence would keep accumulating + * in ao->buffer if the AO accepts less data than it asks for * in playsize. */ - char *p = malloc(playsize); - memset(p, fillbyte, playsize); - write_to_ao(mpctx, p, playsize, 0, written_pts - bytes / bps); - free(p); + write_silence_to_ao(mpctx, playsize, 0, + written_pts - samples / real_samplerate); return ASYNC_PLAY_DONE; } mpctx->syncing_audio = false; - decode_audio_prepend_bytes(&ao->buffer, bytes, fillbyte); - return decode_audio(sh_audio, &ao->buffer, playsize); + mp_audio_buffer_prepend_silence(ao->buffer, samples); + return decode_audio(sh_audio, ao->buffer, playsize); } int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) @@ -340,7 +351,6 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) 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) @@ -359,7 +369,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) if (mpctx->syncing_audio || mpctx->hrseek_active) res = audio_start_sync(mpctx, playsize); else - res = decode_audio(sh_audio, &ao->buffer, playsize); + res = decode_audio(sh_audio, ao->buffer, playsize); if (res < 0) { // EOF, error or format change if (res == -2) { @@ -378,21 +388,19 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } 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); + double samples = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay) + * ao->samplerate / opts->playback_speed; + if (playsize > samples) { + playsize = MPMAX(samples, 0); audio_eof = true; partial_fill = true; } } - assert(ao->buffer.len % unitsize == 0); - if (playsize > ao->buffer.len) { + if (playsize > mp_audio_buffer_samples(ao->buffer)) { + playsize = mp_audio_buffer_samples(ao->buffer); partial_fill = true; - playsize = ao->buffer.len; } - playsize -= playsize % unitsize; if (!playsize) return partial_fill && audio_eof ? -2 : -partial_fill; @@ -406,14 +414,16 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } } - 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; + assert(ao->buffer_playable_samples <= mp_audio_buffer_samples(ao->buffer)); + + struct mp_audio data; + mp_audio_buffer_peek(ao->buffer, &data); + data.samples = MPMIN(data.samples, playsize); + int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx)); + ao->buffer_playable_samples = playsize - played; if (played > 0) { - ao->buffer.len -= played; - memmove(ao->buffer.start, ao->buffer.start + played, ao->buffer.len); + mp_audio_buffer_skip(ao->buffer, played); } 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 @@ -428,8 +438,8 @@ void clear_audio_output_buffers(struct MPContext *mpctx) { if (mpctx->ao) { ao_reset(mpctx->ao); - mpctx->ao->buffer.len = 0; - mpctx->ao->buffer_playable_size = 0; + mp_audio_buffer_clear(mpctx->ao->buffer); + mpctx->ao->buffer_playable_samples = 0; } } diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c index a35da703ed..fffb1566c2 100644 --- a/mpvcore/player/loadfile.c +++ b/mpvcore/player/loadfile.c @@ -43,6 +43,8 @@ #include "mpvcore/input/input.h" #include "audio/mixer.h" +#include "audio/audio.h" +#include "audio/audio_buffer.h" #include "audio/decode/dec_audio.h" #include "audio/out/ao.h" #include "demux/demux.h" @@ -163,11 +165,13 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) // 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, + struct mp_audio data; + mp_audio_buffer_peek(ao->buffer, &data); + int samples = ao->buffer_playable_samples; + assert(samples <= data.samples); + int played = ao_play(ao, data.planes, samples, AOPLAY_FINAL_CHUNK); - if (played < len) + if (played < samples) MP_WARN(ao, "Audio output truncated at end.\n"); } ao_uninit(ao, drain); |