diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/audio_buffer.c | 136 | ||||
-rw-r--r-- | audio/audio_buffer.h | 12 | ||||
-rw-r--r-- | audio/out/push.c | 89 |
3 files changed, 112 insertions, 125 deletions
diff --git a/audio/audio_buffer.c b/audio/audio_buffer.c index a443a2185a..b54f1f41b8 100644 --- a/audio/audio_buffer.c +++ b/audio/audio_buffer.c @@ -21,141 +21,137 @@ #include "common/common.h" +#include "chmap.h" #include "audio_buffer.h" -#include "audio.h" #include "format.h" struct mp_audio_buffer { - struct mp_audio *buffer; + int format; + struct mp_chmap channels; + int srate; + int sstride; + int num_planes; + uint8_t *data[MP_NUM_CHANNELS]; + int allocated; + int num_samples; }; struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx) { - struct mp_audio_buffer *ab = talloc(talloc_ctx, struct mp_audio_buffer); - *ab = (struct mp_audio_buffer) { - .buffer = talloc_zero(ab, struct mp_audio), - }; - return ab; + return talloc_zero(talloc_ctx, struct mp_audio_buffer); } // Reinitialize the buffer, set a new format, drop old data. // The audio data in fmt is not used, only the format. -void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt) -{ - mp_audio_copy_config(ab->buffer, fmt); - mp_audio_realloc(ab->buffer, 1); - ab->buffer->samples = 0; -} - void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format, const struct mp_chmap *channels, int srate) { - struct mp_audio mpa = {0}; - mp_audio_set_format(&mpa, format); - mp_audio_set_channels(&mpa, channels); - mpa.rate = srate; - mp_audio_buffer_reinit(ab, &mpa); -} - -void mp_audio_buffer_get_format(struct mp_audio_buffer *ab, - struct mp_audio *out_fmt) -{ - *out_fmt = (struct mp_audio){0}; - mp_audio_copy_config(out_fmt, ab->buffer); + for (int n = 0; n < MP_NUM_CHANNELS; n++) + TA_FREEP(&ab->data[n]); + ab->format = format; + ab->channels = *channels; + ab->srate = srate; + ab->allocated = 0; + ab->num_samples = 0; + ab->sstride = af_fmt_to_bytes(ab->format); + ab->num_planes = 1; + if (af_fmt_is_planar(ab->format)) { + ab->num_planes = ab->channels.num; + } else { + ab->sstride *= ab->channels.num; + } } // Make the total size of the internal buffer at least this number of samples. void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples) { - mp_audio_realloc_min(ab->buffer, samples); + if (samples > ab->allocated) { + for (int n = 0; n < ab->num_planes; n++) { + ab->data[n] = talloc_realloc(ab, ab->data[n], char, + ab->sstride * samples); + } + ab->allocated = samples; + } } // Get number of samples that can be written without forcing a resize of the // internal buffer. int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab) { - return mp_audio_get_allocated_size(ab->buffer) - ab->buffer->samples; -} - -// Get a pointer to the end of the buffer (where writing would append). If the -// internal buffer is too small for the given number of samples, it's resized. -// After writing to the buffer, mp_audio_buffer_finish_write() has to be used -// to make the written data part of the readable buffer. -void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int samples, - struct mp_audio *out_buffer) -{ - assert(samples >= 0); - mp_audio_realloc_min(ab->buffer, ab->buffer->samples + samples); - *out_buffer = *ab->buffer; - out_buffer->samples = ab->buffer->samples + samples; - mp_audio_skip_samples(out_buffer, ab->buffer->samples); + return ab->allocated - ab->num_samples; } -void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples) +// All integer parameters are in samples. +// dst and src can overlap. +static void copy_planes(struct mp_audio_buffer *ab, + uint8_t **dst, int dst_offset, + uint8_t **src, int src_offset, int length) { - assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab)); - ab->buffer->samples += samples; + for (int n = 0; n < ab->num_planes; n++) { + memmove((char *)dst[n] + dst_offset * ab->sstride, + (char *)src[n] + src_offset * ab->sstride, + length * ab->sstride); + } } // Append data to the end of the buffer. // If the buffer is not large enough, it is transparently resized. -// For now always copies the data. -void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa) +void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples) { - int offset = ab->buffer->samples; - ab->buffer->samples += mpa->samples; - mp_audio_realloc_min(ab->buffer, ab->buffer->samples); - mp_audio_copy(ab->buffer, offset, mpa, 0, mpa->samples); + mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples); + copy_planes(ab, ab->data, ab->num_samples, (uint8_t **)ptr, 0, samples); + ab->num_samples += samples; } // Prepend silence to the start of the buffer. void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples) { assert(samples >= 0); - int oldlen = ab->buffer->samples; - ab->buffer->samples += samples; - mp_audio_realloc_min(ab->buffer, ab->buffer->samples); - mp_audio_copy(ab->buffer, samples, ab->buffer, 0, oldlen); - mp_audio_fill_silence(ab->buffer, 0, samples); + mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples); + copy_planes(ab, ab->data, samples, ab->data, 0, ab->num_samples); + ab->num_samples += samples; + for (int n = 0; n < ab->num_planes; n++) + af_fill_silence(ab->data[n], samples * ab->sstride, ab->format); } void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples) { - assert(samples >= 0 && samples <= ab->buffer->samples); - int oldlen = ab->buffer->samples; - ab->buffer->samples += samples; - mp_audio_realloc_min(ab->buffer, ab->buffer->samples); - mp_audio_copy(ab->buffer, oldlen, ab->buffer, oldlen - samples, samples); + assert(samples >= 0 && samples <= ab->num_samples); + mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples); + copy_planes(ab, ab->data, ab->num_samples, + ab->data, ab->num_samples - samples, samples); + ab->num_samples += samples; } // Get the start of the current readable buffer. -void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa) +void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr, + int *samples) { - *out_mpa = *ab->buffer; + *ptr = ab->data; + *samples = ab->num_samples; } // Skip leading samples. (Used with mp_audio_buffer_peek() to read data.) void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples) { - assert(samples >= 0 && samples <= ab->buffer->samples); - mp_audio_copy(ab->buffer, 0, ab->buffer, samples, - ab->buffer->samples - samples); - ab->buffer->samples -= samples; + assert(samples >= 0 && samples <= ab->num_samples); + copy_planes(ab, ab->data, 0, ab->data, samples, ab->num_samples - samples); + ab->num_samples -= samples; } void mp_audio_buffer_clear(struct mp_audio_buffer *ab) { - ab->buffer->samples = 0; + ab->num_samples = 0; } // Return number of buffered audio samples int mp_audio_buffer_samples(struct mp_audio_buffer *ab) { - return ab->buffer->samples; + return ab->num_samples; } // Return amount of buffered audio in seconds. double mp_audio_buffer_seconds(struct mp_audio_buffer *ab) { - return ab->buffer->samples / (double)ab->buffer->rate; + return ab->num_samples / (double)ab->srate; } diff --git a/audio/audio_buffer.h b/audio/audio_buffer.h index 212d187572..0d7b66a527 100644 --- a/audio/audio_buffer.h +++ b/audio/audio_buffer.h @@ -19,24 +19,18 @@ #define MP_AUDIO_BUFFER_H struct mp_audio_buffer; -struct mp_audio; struct mp_chmap; struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx); -void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt); void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format, const struct mp_chmap *channels, int srate); -void mp_audio_buffer_get_format(struct mp_audio_buffer *ab, - struct mp_audio *out_fmt); void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples); int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab); -void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples, - struct mp_audio *out_buffer); -void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples); -void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa); +void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples); void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples); void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples); -void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa); +void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr, + int *samples); void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples); void mp_audio_buffer_clear(struct mp_audio_buffer *ab); int mp_audio_buffer_samples(struct mp_audio_buffer *ab); diff --git a/audio/out/push.c b/audio/out/push.c index c4083923fd..8546ec816d 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -37,7 +37,6 @@ #include "osdep/timer.h" #include "osdep/atomic.h" -#include "audio/audio.h" #include "audio/audio_buffer.h" struct ao_push_state { @@ -49,7 +48,8 @@ struct ao_push_state { struct mp_audio_buffer *buffer; - struct mp_audio *silence; + uint8_t *silence[MP_NUM_CHANNELS]; + int silence_samples; bool terminate; bool wait_on_ao; @@ -237,12 +237,7 @@ static int play(struct ao *ao, void **data, int samples, int flags) flags = flags & ~AOPLAY_FINAL_CHUNK; bool is_final = flags & AOPLAY_FINAL_CHUNK; - struct mp_audio audio; - mp_audio_buffer_get_format(p->buffer, &audio); - for (int n = 0; n < ao->num_planes; n++) - audio.planes[n] = data[n]; - audio.samples = write_samples; - mp_audio_buffer_append(p->buffer, &audio); + mp_audio_buffer_append(p->buffer, data, samples); bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final; @@ -260,22 +255,26 @@ static int play(struct ao *ao, void **data, int samples, int flags) return write_samples; } -static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size) +static bool realloc_silence(struct ao *ao, int samples) { struct ao_push_state *p = ao->api_priv; - if (!p->silence) { - p->silence = talloc_zero(p, struct mp_audio); - mp_audio_set_format(p->silence, ao->format); - mp_audio_set_channels(p->silence, &ao->channels); - p->silence->rate = ao->samplerate; - } - if (p->silence->samples < size) { - mp_audio_realloc_min(p->silence, size); - p->silence->samples = size; - mp_audio_fill_silence(p->silence, 0, size); + + if (samples <= 0 || !af_fmt_is_pcm(ao->format)) + return false; + + if (samples > p->silence_samples) { + talloc_free(p->silence[0]); + + int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num; + p->silence[0] = talloc_size(p, bytes); + for (int n = 1; n < MP_NUM_CHANNELS; n++) + p->silence[n] = p->silence[0]; + p->silence_samples = samples; + + af_fill_silence(p->silence[0], bytes, ao->format); } - *data = *p->silence; - data->samples = size; + + return true; } // called locked @@ -287,39 +286,41 @@ static void ao_play_data(struct ao *ao) space = MPMAX(space, 0); if (space % ao->period_size) MP_ERR(ao, "Audio device reports unaligned available buffer size.\n"); - struct mp_audio data; + uint8_t **planes; + int samples; if (play_silence) { - ao_get_silence(ao, &data, space); + planes = p->silence; + samples = realloc_silence(ao, space) ? space : 0; } else { - mp_audio_buffer_peek(p->buffer, &data); + mp_audio_buffer_peek(p->buffer, &planes, &samples); } - int max = data.samples; - if (data.samples > space) - data.samples = space; + int max = samples; + if (samples > space) + samples = space; int flags = 0; - if (p->final_chunk && data.samples == max) { + if (p->final_chunk && samples == max) { flags |= AOPLAY_FINAL_CHUNK; } else { - data.samples = data.samples / ao->period_size * ao->period_size; + samples = samples / ao->period_size * ao->period_size; } MP_STATS(ao, "start ao fill"); int r = 0; - if (data.samples) - r = ao->driver->play(ao, data.planes, data.samples, flags); + if (samples) + r = ao->driver->play(ao, (void **)planes, samples, flags); MP_STATS(ao, "end ao fill"); - if (r > data.samples) { + if (r > samples) { MP_ERR(ao, "Audio device returned non-sense value.\n"); - r = data.samples; + r = samples; } else if (r < 0) { MP_ERR(ao, "Error writing audio to device.\n"); - } else if (r != data.samples) { + } else if (r != samples) { MP_ERR(ao, "Audio device returned broken buffer state (sent %d samples, " - "got %d samples, %d period%s)!\n", data.samples, r, + "got %d samples, %d period%s)!\n", samples, r, ao->period_size, flags & AOPLAY_FINAL_CHUNK ? " final" : ""); } r = MPMAX(r, 0); // Probably can't copy the rest of the buffer due to period alignment. - bool stuck_eof = r <= 0 && space >= max && data.samples > 0; + bool stuck_eof = r <= 0 && space >= max && samples > 0; if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) { MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n"); r = max; @@ -491,17 +492,13 @@ const struct ao_driver ao_api_push = { int ao_play_silence(struct ao *ao, int samples) { assert(ao->api == &ao_api_push); - if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play) + + struct ao_push_state *p = ao->api_priv; + + if (!realloc_silence(ao, samples) || !ao->driver->play) return 0; - int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num; - char *p = talloc_size(NULL, bytes); - af_fill_silence(p, bytes, ao->format); - void *tmp[MP_NUM_CHANNELS]; - for (int n = 0; n < MP_NUM_CHANNELS; n++) - tmp[n] = p; - int r = ao->driver->play(ao, tmp, samples, 0); - talloc_free(p); - return r; + + return ao->driver->play(ao, (void **)p->silence, samples, 0); } #ifndef __MINGW32__ |