From c94d5d9d349fe1a6e1aade31699c213387220067 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Oct 2023 15:07:08 +0200 Subject: [PATCH] audioconvert: improve allocation Don't try to allocate each time port buffers are set but only once before we start procesing. Also allocate enough temp buffers are there are ports. This saves us quite a bit of memory in the normal case. --- spa/plugins/audioconvert/audioconvert.c | 137 +++++++++++++----------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index f0eeff8d9..932454923 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -158,6 +158,7 @@ struct port { uint32_t blocks; uint32_t stride; + uint32_t maxsize; const struct spa_pod_sequence *ctrl; uint32_t ctrl_offset; @@ -237,7 +238,8 @@ struct impl { unsigned int rate_adjust:1; unsigned int port_ignore_latency:1; - uint32_t empty_size; + uint32_t scratch_size; + uint32_t scratch_ports; float *empty; float *scratch; float *tmp[2]; @@ -1754,10 +1756,68 @@ static int setup_out_convert(struct impl *this) return 0; } +static void free_tmp(struct impl *this) +{ + uint32_t i; + + spa_log_debug(this->log, "free tmp %d", this->scratch_size); + + free(this->empty); + this->empty = NULL; + this->scratch_size = 0; + this->scratch_ports = 0; + free(this->scratch); + this->scratch = NULL; + free(this->tmp[0]); + this->tmp[0] = NULL; + free(this->tmp[1]); + this->tmp[1] = NULL; + for (i = 0; i < MAX_PORTS; i++) { + this->tmp_datas[0][i] = NULL; + this->tmp_datas[1][i] = NULL; + } +} + +static int ensure_tmp(struct impl *this, uint32_t maxsize, uint32_t maxports) +{ + if (maxsize > this->scratch_size || maxports > this->scratch_ports) { + float *empty, *scratch, *tmp[2]; + uint32_t i; + + spa_log_debug(this->log, "resize tmp %d -> %d", this->scratch_size, maxsize); + + if ((empty = realloc(this->empty, maxsize + MAX_ALIGN)) != NULL) + this->empty = empty; + if ((scratch = realloc(this->scratch, maxsize + MAX_ALIGN)) != NULL) + this->scratch = scratch; + if ((tmp[0] = realloc(this->tmp[0], (maxsize + MAX_ALIGN) * maxports)) != NULL) + this->tmp[0] = tmp[0]; + if ((tmp[1] = realloc(this->tmp[1], (maxsize + MAX_ALIGN) * maxports)) != NULL) + this->tmp[1] = tmp[1]; + + if (empty == NULL || scratch == NULL || tmp[0] == NULL || tmp[1] == NULL) { + free_tmp(this); + return -ENOMEM; + } + memset(this->empty, 0, maxsize + MAX_ALIGN); + this->scratch_size = maxsize; + this->scratch_ports = maxports; + + for (i = 0; i < maxports; i++) { + this->tmp_datas[0][i] = SPA_PTROFF(tmp[0], maxsize * i, void); + this->tmp_datas[0][i] = SPA_PTR_ALIGN(this->tmp_datas[0][i], MAX_ALIGN, void); + this->tmp_datas[1][i] = SPA_PTROFF(tmp[1], maxsize * i, void); + this->tmp_datas[1][i] = SPA_PTR_ALIGN(this->tmp_datas[1][i], MAX_ALIGN, void); + } + } + return 0; +} + static int setup_convert(struct impl *this) { struct dir *in, *out; - uint32_t i, rate; + uint32_t i, rate, maxsize, maxports; + struct port *p; int res; in = &this->dir[SPA_DIRECTION_INPUT]; @@ -1806,12 +1866,19 @@ static int setup_convert(struct impl *this) if ((res = setup_out_convert(this)) < 0) return res; - for (i = 0; i < MAX_PORTS; i++) { - this->tmp_datas[0][i] = SPA_PTROFF(this->tmp[0], this->empty_size * i, void); - this->tmp_datas[0][i] = SPA_PTR_ALIGN(this->tmp_datas[0][i], MAX_ALIGN, void); - this->tmp_datas[1][i] = SPA_PTROFF(this->tmp[1], this->empty_size * i, void); - this->tmp_datas[1][i] = SPA_PTR_ALIGN(this->tmp_datas[1][i], MAX_ALIGN, void); + maxsize = this->quantum_limit * sizeof(float); + for (i = 0; i < in->n_ports; i++) { + p = GET_IN_PORT(this, i); + maxsize = SPA_MAX(maxsize, p->maxsize); } + for (i = 0; i < out->n_ports; i++) { + p = GET_OUT_PORT(this, i); + maxsize = SPA_MAX(maxsize, p->maxsize); + } + maxports = SPA_MAX(in->format.info.raw.channels, out->format.info.raw.channels); + if ((res = ensure_tmp(this, maxsize, maxports)) < 0) + return res; + this->setup = true; emit_node_info(this, false); @@ -2445,53 +2512,6 @@ static inline void dequeue_buffer(struct impl *this, struct port *port, struct b SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED); } -static void free_tmp(struct impl *this) -{ - uint32_t i; - - spa_log_debug(this->log, "free tmp %d", this->empty_size); - - free(this->empty); - this->empty = NULL; - this->empty_size = 0; - free(this->scratch); - this->scratch = NULL; - free(this->tmp[0]); - this->tmp[0] = NULL; - free(this->tmp[1]); - this->tmp[1] = NULL; - for (i = 0; i < MAX_PORTS; i++) { - this->tmp_datas[0][i] = NULL; - this->tmp_datas[1][i] = NULL; - } -} - -static int ensure_tmp(struct impl *this, uint32_t maxsize) -{ - if (maxsize > this->empty_size) { - float *empty, *scratch, *tmp[2]; - - spa_log_debug(this->log, "resize tmp %d -> %d", this->empty_size, maxsize); - - if ((empty = realloc(this->empty, maxsize + MAX_ALIGN)) != NULL) - this->empty = empty; - if ((scratch = realloc(this->scratch, maxsize + MAX_ALIGN)) != NULL) - this->scratch = scratch; - if ((tmp[0] = realloc(this->tmp[0], (maxsize + MAX_ALIGN) * MAX_PORTS)) != NULL) - this->tmp[0] = tmp[0]; - if ((tmp[1] = realloc(this->tmp[1], (maxsize + MAX_ALIGN) * MAX_PORTS)) != NULL) - this->tmp[1] = tmp[1]; - - if (empty == NULL || scratch == NULL || tmp[0] == NULL || tmp[1] == NULL) { - free_tmp(this); - return -ENOMEM; - } - memset(this->empty, 0, maxsize + MAX_ALIGN); - this->empty_size = maxsize; - } - return 0; -} - static int impl_node_port_use_buffers(void *object, enum spa_direction direction, @@ -2503,7 +2523,6 @@ impl_node_port_use_buffers(void *object, struct impl *this = object; struct port *port; uint32_t i, j, maxsize; - int res; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -2560,9 +2579,7 @@ impl_node_port_use_buffers(void *object, if (direction == SPA_DIRECTION_OUTPUT) queue_buffer(this, port, i); } - if ((res = ensure_tmp(this, maxsize)) < 0) - return res; - + port->maxsize = maxsize; port->n_buffers = n_buffers; return 0; @@ -2869,7 +2886,7 @@ static int impl_node_process(void *object) src_datas[remap] = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); spa_log_trace_fp(this->log, "%p: empty input %d->%d", this, i * port->blocks + j, remap); - max_in = SPA_MIN(max_in, this->empty_size / port->stride); + max_in = SPA_MIN(max_in, this->scratch_size / port->stride); } } } else { @@ -2970,7 +2987,7 @@ static int impl_node_process(void *object) dst_datas[remap] = SPA_PTR_ALIGN(this->scratch, MAX_ALIGN, void); spa_log_trace_fp(this->log, "%p: empty output %d->%d", this, i * port->blocks + j, remap); - max_out = SPA_MIN(max_out, this->empty_size / port->stride); + max_out = SPA_MIN(max_out, this->scratch_size / port->stride); } } } else {