audioconvert2: Improvements

Suggest 2 buffers by default.
Improve rate match flow.
monitor does not need the out_offset
Update rate match when we know the queued samples.
This commit is contained in:
Wim Taymans 2022-05-18 16:21:09 +02:00
parent 2352ae33c3
commit 58abc1ec15

View file

@ -1537,7 +1537,7 @@ impl_node_port_enum_params(void *object, int seq,
param = spa_pod_builder_add_object(&b, param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamBuffers, id, SPA_TYPE_OBJECT_ParamBuffers, id,
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks),
SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(
this->quantum_limit * port->stride, this->quantum_limit * port->stride,
@ -1937,31 +1937,31 @@ static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t
return 0; return 0;
} }
static void resample_update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) static uint32_t resample_update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued)
{ {
double rate = this->rate_scale / this->props.rate; double rate = this->rate_scale / this->props.rate;
uint32_t delay, match_size;
if (this->io_rate_match) {
uint32_t match_size;
if (passthrough) { if (passthrough) {
this->io_rate_match->delay = 0; delay = 0;
match_size = out_size; match_size = out_size;
} else { } else {
if (SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) if (this->io_rate_match &&
resample_update_rate(&this->resample, rate * this->io_rate_match->rate); SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE))
else rate *= this->io_rate_match->rate;
resample_update_rate(&this->resample, rate); resample_update_rate(&this->resample, rate);
delay = resample_delay(&this->resample);
this->io_rate_match->delay = resample_delay(&this->resample);
match_size = resample_in_len(&this->resample, out_size); match_size = resample_in_len(&this->resample, out_size);
} }
match_size -= SPA_MIN(match_size, in_queued); match_size -= SPA_MIN(match_size, in_queued);
this->io_rate_match->size = match_size;
spa_log_trace_fp(this->log, "%p: next match %u", this, match_size); spa_log_trace_fp(this->log, "%p: next match %u", this, match_size);
} else {
resample_update_rate(&this->resample, rate); if (this->io_rate_match) {
this->io_rate_match->delay = delay;
this->io_rate_match->size = match_size;
} }
return match_size;
} }
static inline bool resample_is_passthrough(struct impl *this) static inline bool resample_is_passthrough(struct impl *this)
@ -1978,20 +1978,20 @@ static int impl_node_process(void *object)
const void *src_datas[MAX_PORTS], **in_datas; const void *src_datas[MAX_PORTS], **in_datas;
void *dst_datas[MAX_PORTS], *mon_datas[MAX_PORTS], **out_datas; void *dst_datas[MAX_PORTS], *mon_datas[MAX_PORTS], **out_datas;
uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, remap; uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, remap;
uint32_t n_samples, max_in, max_mon, max_out, quant_samples, n_empty; uint32_t n_samples, max_in, max_out, max_mon, quant_samples;
struct port *port; struct port *port;
struct buffer *buf, *out_bufs[MAX_PORTS]; struct buffer *buf, *out_bufs[MAX_PORTS];
struct spa_data *bd; struct spa_data *bd;
struct dir *dir; struct dir *dir;
int tmp = 0, res; int tmp = 0, res;
bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough, end_passthrough; bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough, end_passthrough;
bool flush_in = false, flush_out = false, draining = false; bool in_avail = false, flush_in = false, flush_out = false, draining = false;
struct spa_io_buffers *io; struct spa_io_buffers *io;
dir = &this->dir[SPA_DIRECTION_INPUT]; dir = &this->dir[SPA_DIRECTION_INPUT];
in_passthrough = dir->conv.is_passthrough; in_passthrough = dir->conv.is_passthrough;
n_samples = n_empty = max_in = UINT32_MAX; max_in = UINT32_MAX;
/* collect input port data */ /* collect input port data */
for (i = 0; i < dir->n_ports; i++) { for (i = 0; i < dir->n_ports; i++) {
@ -2004,7 +2004,7 @@ static int impl_node_process(void *object)
} else if (io->status != SPA_STATUS_HAVE_DATA) { } else if (io->status != SPA_STATUS_HAVE_DATA) {
if (io->status & SPA_STATUS_DRAINED) { if (io->status & SPA_STATUS_DRAINED) {
spa_log_debug(this->log, "%p: port %d drained", this, port->id); spa_log_debug(this->log, "%p: port %d drained", this, port->id);
flush_in = draining = true; in_avail = flush_in = draining = true;
} else { } else {
spa_log_trace_fp(this->log, "%p: empty input port %d %p %d %d %d", spa_log_trace_fp(this->log, "%p: empty input port %d %p %d %d %d",
this, port->id, io, io->status, io->buffer_id, this, port->id, io, io->status, io->buffer_id,
@ -2027,10 +2027,10 @@ static int impl_node_process(void *object)
src_datas[remap] = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); src_datas[remap] = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void);
spa_log_trace_fp(this->log, "%p: empty input %d->%d", this, spa_log_trace_fp(this->log, "%p: empty input %d->%d", this,
i * port->blocks + j, remap); i * port->blocks + j, remap);
n_empty = SPA_MIN(n_empty, this->empty_size / port->stride);
max_in = SPA_MIN(max_in, this->empty_size / port->stride); max_in = SPA_MIN(max_in, this->empty_size / port->stride);
} }
} else { } else {
in_avail = true;
for (j = 0; j < port->blocks; j++) { for (j = 0; j < port->blocks; j++) {
uint32_t offs, size; uint32_t offs, size;
@ -2041,14 +2041,11 @@ static int impl_node_process(void *object)
size = SPA_MIN(bd->maxsize - offs, bd->chunk->size); size = SPA_MIN(bd->maxsize - offs, bd->chunk->size);
max_in = SPA_MIN(max_in, size / port->stride); max_in = SPA_MIN(max_in, size / port->stride);
offs = SPA_MIN(offs + this->in_offset * port->stride, bd->maxsize); offs += this->in_offset * port->stride;
size = SPA_MIN(bd->maxsize - offs, bd->chunk->size);
src_datas[remap] = SPA_PTROFF(bd->data, offs, void); src_datas[remap] = SPA_PTROFF(bd->data, offs, void);
n_samples = SPA_MIN(n_samples, size / port->stride);
spa_log_trace_fp(this->log, "%p: input %d:%d:%d %d %d %d->%d", this, spa_log_trace_fp(this->log, "%p: input %d:%d:%d %d %d %d->%d", this,
offs, size, port->stride, max_in, n_samples, offs, size, port->stride, this->in_offset, max_in,
i * port->blocks + j, remap); i * port->blocks + j, remap);
} }
} }
@ -2078,17 +2075,19 @@ static int impl_node_process(void *object)
else else
quant_samples = this->quantum_limit; quant_samples = this->quantum_limit;
if (draining)
n_samples = SPA_MIN(n_empty, this->quantum_limit);
resample_passthrough = resample_is_passthrough(this); resample_passthrough = resample_is_passthrough(this);
if (n_samples == UINT32_MAX || this->drained) { if (!in_avail || this->drained) {
spa_log_debug(this->log, "%p: %d %d", this, n_samples, this->drained); spa_log_debug(this->log, "%p: no input drained:%d", this, this->drained);
/* no input, ask for more */ /* no input, ask for more */
resample_update_rate_match(this, resample_passthrough, quant_samples, 0); resample_update_rate_match(this, resample_passthrough, quant_samples, 0);
return this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA; return this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA;
} }
if (draining)
n_samples = SPA_MIN(max_in, this->quantum_limit);
else
n_samples = max_in - this->in_offset;
dir = &this->dir[SPA_DIRECTION_OUTPUT]; dir = &this->dir[SPA_DIRECTION_OUTPUT];
out_passthrough = dir->conv.is_passthrough; out_passthrough = dir->conv.is_passthrough;
@ -2130,8 +2129,7 @@ static int impl_node_process(void *object)
bd->chunk->size = 0; bd->chunk->size = 0;
if (port->is_monitor) { if (port->is_monitor) {
remap = n_mon_datas++; remap = n_mon_datas++;
mon_datas[remap] = SPA_PTROFF(bd->data, mon_datas[remap] = bd->data;
this->out_offset * port->stride, void);
max_mon = SPA_MIN(max_mon, bd->maxsize / port->stride); max_mon = SPA_MIN(max_mon, bd->maxsize / port->stride);
} else { } else {
remap = dir->dst_remap[n_dst_datas++]; remap = dir->dst_remap[n_dst_datas++];
@ -2169,7 +2167,9 @@ static int impl_node_process(void *object)
if (this->direction == SPA_DIRECTION_INPUT) { if (this->direction == SPA_DIRECTION_INPUT) {
/* in split mode we need to output exactly the size of the /* in split mode we need to output exactly the size of the
* duration so we don't try to flush early */ * duration so we don't try to flush early */
n_samples = max_out = SPA_MIN(max_out, quant_samples); n_samples = SPA_MIN(n_samples,
resample_update_rate_match(this, resample_passthrough, quant_samples, 0));
max_out = SPA_MIN(max_out, quant_samples);
flush_out = false; flush_out = false;
} else { } else {
/* in merge mode we consume one duration of samples and /* in merge mode we consume one duration of samples and
@ -2217,7 +2217,6 @@ static int impl_node_process(void *object)
n_samples, max_out, in_len, out_len, out_passthrough); n_samples, max_out, in_len, out_len, out_passthrough);
n_samples = out_len; n_samples = out_len;
} }
resample_update_rate_match(this, resample_passthrough, max_out, 0);
this->out_offset += n_samples; this->out_offset += n_samples;
if (!out_passthrough) { if (!out_passthrough) {
@ -2226,11 +2225,13 @@ static int impl_node_process(void *object)
convert_process(&this->dir[SPA_DIRECTION_OUTPUT].conv, dst_datas, in_datas, n_samples); convert_process(&this->dir[SPA_DIRECTION_OUTPUT].conv, dst_datas, in_datas, n_samples);
} }
spa_log_trace_fp(this->log, "%d/%d %d/%d", this->in_offset, max_in, this->out_offset, max_out); spa_log_trace_fp(this->log, "%d/%d %d/%d %d", this->in_offset, max_in,
this->out_offset, max_out, n_samples);
res = 0; res = 0;
dir = &this->dir[SPA_DIRECTION_INPUT];
if (this->in_offset >= max_in || flush_in) { if (this->in_offset >= max_in || flush_in) {
/* return input buffers */ /* return input buffers */
dir = &this->dir[SPA_DIRECTION_INPUT];
for (i = 0; i < dir->n_ports; i++) { for (i = 0; i < dir->n_ports; i++) {
port = GET_IN_PORT(this, i); port = GET_IN_PORT(this, i);
if ((io = port->io) != NULL) { if ((io = port->io) != NULL) {
@ -2239,12 +2240,13 @@ static int impl_node_process(void *object)
} }
} }
this->in_offset = 0; this->in_offset = 0;
max_in = 0;
res |= SPA_STATUS_NEED_DATA; res |= SPA_STATUS_NEED_DATA;
} }
dir = &this->dir[SPA_DIRECTION_OUTPUT];
if (this->out_offset > 0 && (this->out_offset >= max_out || flush_out)) { if (this->out_offset > 0 && (this->out_offset >= max_out || flush_out)) {
/* queue output buffers */ /* queue output buffers */
dir = &this->dir[SPA_DIRECTION_OUTPUT];
for (i = 0; i < dir->n_ports; i++) { for (i = 0; i < dir->n_ports; i++) {
port = GET_OUT_PORT(this, i); port = GET_OUT_PORT(this, i);
buf = out_bufs[i]; buf = out_bufs[i];
@ -2273,6 +2275,22 @@ static int impl_node_process(void *object)
this->drained = draining; this->drained = draining;
this->out_offset = 0; this->out_offset = 0;
} }
if (n_samples == 0 && this->peaks) {
for (i = 0; i < dir->n_ports; i++) {
port = GET_OUT_PORT(this, i);
if (SPA_UNLIKELY((io = port->io) == NULL))
continue;
io->status = SPA_STATUS_HAVE_DATA;
io->buffer_id = SPA_ID_INVALID;
res |= SPA_STATUS_HAVE_DATA;
spa_log_trace_fp(this->log, "%p: no output buffer", this);
}
}
resample_update_rate_match(this, resample_passthrough,
quant_samples,
max_in - this->in_offset);
return res; return res;
} }