From d1ee9ea261798f94fe958578d9748a69864c3058 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 10 Nov 2013 23:24:50 +0100 Subject: audio: add mp_audio_buffer Implementation wise, this could be much improved, such as using a ringbuffer that doesn't require copying data all the time. This is why we don't use mp_audio directly instead of mp_audio_buffer. --- Makefile | 1 + audio/audio_buffer.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++ audio/audio_buffer.h | 44 +++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 audio/audio_buffer.c create mode 100644 audio/audio_buffer.h diff --git a/Makefile b/Makefile index ccf845e1a1..31ee25362f 100644 --- a/Makefile +++ b/Makefile @@ -140,6 +140,7 @@ endif SOURCES-$(DLOPEN) += video/filter/vf_dlopen.c SOURCES = audio/audio.c \ + audio/audio_buffer.c \ audio/chmap.c \ audio/chmap_sel.c \ audio/fmt-conversion.c \ diff --git a/audio/audio_buffer.c b/audio/audio_buffer.c new file mode 100644 index 0000000000..53563f90c6 --- /dev/null +++ b/audio/audio_buffer.c @@ -0,0 +1,152 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see . + */ + +#include +#include +#include + +#include "mpvcore/mp_common.h" + +#include "audio_buffer.h" +#include "audio.h" +#include "format.h" + +struct mp_audio_buffer { + struct mp_audio *buffer; +}; + +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; +} + +// 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); +} + +// 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); +} + +// 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); +} + +void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples) +{ + assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab)); + ab->buffer->samples += samples; +} + +// 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) +{ + 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); +} + +// 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); +} + +// Get the start of the current readable buffer. +void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa) +{ + *out_mpa = *ab->buffer; +} + +// 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; +} + +void mp_audio_buffer_clear(struct mp_audio_buffer *ab) +{ + ab->buffer->samples = 0; +} + +// Return number of buffered audio samples +int mp_audio_buffer_samples(struct mp_audio_buffer *ab) +{ + return ab->buffer->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; +} diff --git a/audio/audio_buffer.h b/audio/audio_buffer.h new file mode 100644 index 0000000000..8cd0df30d0 --- /dev/null +++ b/audio/audio_buffer.h @@ -0,0 +1,44 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see . + */ + +#ifndef MP_AUDIO_BUFFER_H +#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_prepend_silence(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_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); +double mp_audio_buffer_seconds(struct mp_audio_buffer *ab); + +#endif -- cgit v1.2.3