From 055c8d6b6388f85207324adb28c848eb815fef0d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 May 2020 15:20:22 +0200 Subject: [PATCH] channelmix: improve control handling We can't write to the input control buffer so keep track of the control offset ourselves ans skip what we already handled. --- spa/plugins/audioconvert/channelmix.c | 140 +++++++++----------------- 1 file changed, 49 insertions(+), 91 deletions(-) diff --git a/spa/plugins/audioconvert/channelmix.c b/spa/plugins/audioconvert/channelmix.c index 55a52d04a..8f1e743f8 100644 --- a/spa/plugins/audioconvert/channelmix.c +++ b/spa/plugins/audioconvert/channelmix.c @@ -105,6 +105,9 @@ struct port { uint32_t n_buffers; struct spa_list queue; + + struct spa_pod_sequence *ctrl; + uint32_t ctrl_offset; }; struct impl { @@ -897,106 +900,48 @@ static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t return 0; } -static int update_control_sequence(struct spa_pod_sequence *ctrl_sequence, - uint32_t ctrl_size, uint32_t curr_ctrl, uint32_t curr_offset) -{ - struct spa_pod_control *c; - struct spa_pod_builder b; - struct spa_pod_frame f[1]; - uint32_t i = 0; - - spa_return_val_if_fail(ctrl_sequence != NULL, -EINVAL); - spa_return_val_if_fail(ctrl_size > 0, -EINVAL); - spa_return_val_if_fail(curr_offset > 0, -EINVAL); - - /* copy the sequence */ - uint8_t old[ctrl_size]; - memcpy(old, ctrl_sequence, ctrl_size); - - /* reset the current sequence */ - spa_pod_builder_init(&b, ctrl_sequence, ctrl_size); - spa_pod_builder_push_sequence(&b, &f[0], 0); - - /* add the remaining controls */ - SPA_POD_SEQUENCE_FOREACH(&((struct spa_io_sequence *)old)->sequence, c) { - switch (c->type) { - case SPA_CONTROL_Properties: - { - if (i >= curr_ctrl) { - spa_pod_builder_control(&b, - i == curr_ctrl ? curr_offset : c->offset, - SPA_CONTROL_Properties); - spa_pod_builder_primitive(&b, &c->value); - } - - i++; - break; - } - default: - break; - } - } - - spa_pod_builder_pop(&b, &f[0]); - - return 0; -} - -static int channelmix_process_control(struct impl *this, struct buffer *cbuf, +static int channelmix_process_control(struct impl *this, struct port *ctrlport, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst], uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples) { - struct spa_pod_sequence *ctrl_sequence; - uint32_t ctrl_size; - struct spa_pod_control *c; + struct spa_pod_control *c, *prev = NULL; uint32_t avail_samples = n_samples; - uint32_t i, j; + uint32_t i; const float **s = (const float **)src; float **d = (float **)dst; - /* get the control sequence */ - spa_return_val_if_fail(cbuf != NULL, -EINVAL); - spa_return_val_if_fail(cbuf->outbuf->n_datas == 1, -EINVAL); - ctrl_sequence = (struct spa_pod_sequence *)cbuf->outbuf->datas[0].data; - ctrl_size = cbuf->outbuf->datas[0].maxsize; - - i = 0; - SPA_POD_SEQUENCE_FOREACH(ctrl_sequence, c) { + SPA_POD_SEQUENCE_FOREACH(ctrlport->ctrl, c) { switch (c->type) { case SPA_CONTROL_Properties: { - /* update the sequence and return if all samples were processed */ - if (avail_samples == 0) { - update_control_sequence(ctrl_sequence, ctrl_size, i, c->offset); + uint32_t chunk; + + if (avail_samples == 0) return 0; + + /* ignore old control offsets */ + if (c->offset <= ctrlport->ctrl_offset) { + prev = c; + continue; } + if (prev) + apply_props(this, &prev->value); + prev = c; - /* apply the sequence control props */ - apply_props(this, &c->value); + chunk = SPA_MIN(avail_samples, c->offset - ctrlport->ctrl_offset); - if (c->offset > 0) { - /* get the minimum offset for this buffer */ - uint32_t offset = SPA_MIN(avail_samples, c->offset); + spa_log_trace_fp(this->log, NAME " %p: process %d %d", this, + c->offset, chunk); - /* process the control sequence */ - channelmix_process(&this->mix, n_dst, dst, n_src, src, offset); - for (j = 0; j < n_src; j++) - s[j] += offset; - for (j = 0; j < n_dst; j++) - d[j] += offset; + channelmix_process(&this->mix, n_dst, dst, n_src, src, chunk); + for (i = 0; i < n_src; i++) + s[i] += chunk; + for (i = 0; i < n_dst; i++) + d[i] += chunk; - /* update the sequence with the remaining offset samples */ - if (avail_samples < c->offset) { - update_control_sequence(ctrl_sequence, ctrl_size, i, c->offset - avail_samples); - return 0; - } - - /* decrease available samples */ - avail_samples -= offset; - } - - i++; + avail_samples -= chunk; + ctrlport->ctrl_offset += chunk; break; } default: @@ -1004,10 +949,11 @@ static int channelmix_process_control(struct impl *this, struct buffer *cbuf, } } - /* process the remaining samples */ + /* when we get here we run out of control points but still have some + * remaining samples */ + spa_log_trace_fp(this->log, NAME " %p: remain %d", this, avail_samples); if (avail_samples > 0) channelmix_process(&this->mix, n_dst, dst, n_src, src, avail_samples); - return 1; } @@ -1016,7 +962,8 @@ static int impl_node_process(void *object) struct impl *this = object; struct port *outport, *inport, *ctrlport; struct spa_io_buffers *outio, *inio, *ctrlio; - struct buffer *sbuf, *dbuf, *cbuf = NULL; + struct buffer *sbuf, *dbuf; + struct spa_pod_sequence *ctrl = NULL; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -1055,8 +1002,18 @@ static int impl_node_process(void *object) if (ctrlio != NULL && ctrlio->status == SPA_STATUS_HAVE_DATA && - ctrlio->buffer_id < ctrlport->n_buffers) - cbuf = &ctrlport->buffers[ctrlio->buffer_id]; + ctrlio->buffer_id < ctrlport->n_buffers) { + struct buffer *cbuf = &ctrlport->buffers[ctrlio->buffer_id]; + struct spa_data *d = &cbuf->outbuf->datas[0]; + + ctrl = spa_pod_from_data(d->data, d->maxsize, d->chunk->offset, d->chunk->size); + if (ctrl && !spa_pod_is_sequence(&ctrl->pod)) + ctrl = NULL; + if (ctrl != ctrlport->ctrl) { + ctrlport->ctrl = ctrl; + ctrlport->ctrl_offset = 0; + } + } { uint32_t i, n_samples; @@ -1067,7 +1024,7 @@ static int impl_node_process(void *object) void *dst_datas[n_dst_datas]; bool is_passthrough; - is_passthrough = this->is_passthrough && this->mix.identity && cbuf == NULL; + is_passthrough = this->is_passthrough && this->mix.identity && ctrlport->ctrl == NULL; n_samples = sb->datas[0].chunk->size / inport->stride; @@ -1083,11 +1040,12 @@ static int impl_node_process(void *object) this, n_src_datas, n_dst_datas, n_samples, is_passthrough); if (!is_passthrough) { - if (cbuf != NULL) { + if (ctrlport->ctrl != NULL) { /* if return value is 1, the sequence has been processed */ - if (channelmix_process_control(this, cbuf, n_dst_datas, dst_datas, + if (channelmix_process_control(this, ctrlport, n_dst_datas, dst_datas, n_src_datas, src_datas, n_samples) == 1) { ctrlio->status = SPA_STATUS_OK; + ctrlport->ctrl = NULL; } } else { channelmix_process(&this->mix, n_dst_datas, dst_datas,