summaryrefslogtreecommitdiffstats
path: root/audio/audio.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-10 18:15:22 +0100
committerwm4 <wm4@nowhere>2014-11-10 18:15:22 +0100
commit5d46e44160fe9ab6a922b594d10f2e4e70242ab7 (patch)
tree80a4d8e6ddb549e1949034d727156fc4682425a0 /audio/audio.c
parentc3d446ee2eeecfe862e24ae77bc2305be1910191 (diff)
downloadmpv-5d46e44160fe9ab6a922b594d10f2e4e70242ab7.tar.bz2
mpv-5d46e44160fe9ab6a922b594d10f2e4e70242ab7.tar.xz
audio: add mp_audio_pool
A helper to allocate refcounted audio frames from a pool. This will replace the static buffer many audio filters use (af->data), because such static buffers are incompatible with refcounting.
Diffstat (limited to 'audio/audio.c')
-rw-r--r--audio/audio.c66
1 files changed, 62 insertions, 4 deletions
diff --git a/audio/audio.c b/audio/audio.c
index 161546a9a3..725658070e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -121,6 +121,15 @@ void mp_audio_set_null_data(struct mp_audio *mpa)
mpa->samples = 0;
}
+static int get_plane_size(const struct mp_audio *mpa, int samples)
+{
+ if (samples < 0 || !mpa->format)
+ return -1;
+ if (samples >= INT_MAX / mpa->sstride)
+ return -1;
+ return MPMAX(samples * mpa->sstride, 1);
+}
+
static void mp_audio_destructor(void *ptr)
{
struct mp_audio *mpa = ptr;
@@ -144,10 +153,9 @@ static void mp_audio_destructor(void *ptr)
*/
void mp_audio_realloc(struct mp_audio *mpa, int samples)
{
- assert(samples >= 0);
- if (samples >= INT_MAX / mpa->sstride)
- abort(); // oom
- int size = MPMAX(samples * mpa->sstride, 1);
+ int size = get_plane_size(mpa, samples);
+ if (size < 0)
+ abort(); // oom or invalid parameters
for (int n = 0; n < mpa->num_planes; n++) {
if (!mpa->allocated[n] || size != mpa->allocated[n]->size) {
if (av_buffer_realloc(&mpa->allocated[n], size) < 0)
@@ -230,3 +238,53 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
data->samples -= samples;
}
+
+struct mp_audio_pool {
+ AVBufferPool *avpool;
+ int element_size;
+};
+
+struct mp_audio_pool *mp_audio_pool_create(void *ta_parent)
+{
+ return talloc_zero(ta_parent, struct mp_audio_pool);
+}
+
+static void mp_audio_pool_destructor(void *p)
+{
+ struct mp_audio_pool *pool = p;
+ av_buffer_pool_uninit(&pool->avpool);
+}
+
+// Allocate data using the given format and number of samples.
+// Returns NULL on error.
+struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
+ const struct mp_audio *fmt, int samples)
+{
+ int size = get_plane_size(fmt, samples);
+ if (size < 0)
+ return NULL;
+ if (!pool->avpool || size > pool->element_size) {
+ size_t alloc = ta_calc_prealloc_elems(size);
+ if (alloc >= INT_MAX)
+ return NULL;
+ av_buffer_pool_uninit(&pool->avpool);
+ pool->avpool = av_buffer_pool_init(alloc, NULL);
+ if (!pool->avpool)
+ return NULL;
+ talloc_set_destructor(pool, mp_audio_pool_destructor);
+ }
+ struct mp_audio *new = talloc_ptrtype(NULL, new);
+ talloc_set_destructor(new, mp_audio_destructor);
+ *new = *fmt;
+ mp_audio_set_null_data(new);
+ new->samples = samples;
+ for (int n = 0; n < new->num_planes; n++) {
+ new->allocated[n] = av_buffer_pool_get(pool->avpool);
+ if (!new->allocated[n]) {
+ talloc_free(new);
+ return NULL;
+ }
+ new->planes[n] = new->allocated[n]->data;
+ }
+ return new;
+}