mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-16 08:56:45 -05:00
audioconvert: fix channel remapping
Do the channel remapping to the cannonical format when we deinterleave/interleave instead. Otherwise we would completely skip the remapping when we have interleaved input. Fixes #2502, #2490
This commit is contained in:
parent
ffedc2d1e8
commit
12bee0edf8
1 changed files with 51 additions and 19 deletions
|
|
@ -170,6 +170,7 @@ struct dir {
|
||||||
uint32_t dst_remap[MAX_PORTS];
|
uint32_t dst_remap[MAX_PORTS];
|
||||||
|
|
||||||
struct convert conv;
|
struct convert conv;
|
||||||
|
unsigned int need_remap:1;
|
||||||
unsigned int is_passthrough:1;
|
unsigned int is_passthrough:1;
|
||||||
unsigned int control:1;
|
unsigned int control:1;
|
||||||
};
|
};
|
||||||
|
|
@ -1102,6 +1103,7 @@ static int setup_in_convert(struct impl *this)
|
||||||
struct dir *in = &this->dir[SPA_DIRECTION_INPUT];
|
struct dir *in = &this->dir[SPA_DIRECTION_INPUT];
|
||||||
struct spa_audio_info src_info, dst_info;
|
struct spa_audio_info src_info, dst_info;
|
||||||
int res;
|
int res;
|
||||||
|
bool remap = false;
|
||||||
|
|
||||||
src_info = in->format;
|
src_info = in->format;
|
||||||
dst_info = src_info;
|
dst_info = src_info;
|
||||||
|
|
@ -1125,8 +1127,10 @@ static int setup_in_convert(struct impl *this)
|
||||||
continue;
|
continue;
|
||||||
in->src_remap[i] = j;
|
in->src_remap[i] = j;
|
||||||
in->dst_remap[j] = i;
|
in->dst_remap[j] = i;
|
||||||
spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this,
|
if (i != j)
|
||||||
i, j,
|
remap = true;
|
||||||
|
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%d) (%s -> %s)", this,
|
||||||
|
i, in->src_remap[i], j, in->dst_remap[j],
|
||||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||||
src_info.info.raw.position[i]),
|
src_info.info.raw.position[i]),
|
||||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||||
|
|
@ -1139,13 +1143,14 @@ static int setup_in_convert(struct impl *this)
|
||||||
in->conv.dst_fmt = dst_info.info.raw.format;
|
in->conv.dst_fmt = dst_info.info.raw.format;
|
||||||
in->conv.n_channels = dst_info.info.raw.channels;
|
in->conv.n_channels = dst_info.info.raw.channels;
|
||||||
in->conv.cpu_flags = this->cpu_flags;
|
in->conv.cpu_flags = this->cpu_flags;
|
||||||
|
in->need_remap = remap;
|
||||||
|
|
||||||
if ((res = convert_init(&in->conv)) < 0)
|
if ((res = convert_init(&in->conv)) < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d %s", this,
|
spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d remap:%d %s", this,
|
||||||
this->cpu_flags, in->conv.cpu_flags, in->conv.is_passthrough,
|
this->cpu_flags, in->conv.cpu_flags, in->conv.is_passthrough,
|
||||||
in->conv.func_name);
|
remap, in->conv.func_name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1394,6 +1399,7 @@ static int setup_out_convert(struct impl *this)
|
||||||
struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT];
|
struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT];
|
||||||
struct spa_audio_info src_info, dst_info;
|
struct spa_audio_info src_info, dst_info;
|
||||||
int res;
|
int res;
|
||||||
|
bool remap = false;
|
||||||
|
|
||||||
dst_info = out->format;
|
dst_info = out->format;
|
||||||
src_info = dst_info;
|
src_info = dst_info;
|
||||||
|
|
@ -1417,8 +1423,11 @@ static int setup_out_convert(struct impl *this)
|
||||||
continue;
|
continue;
|
||||||
out->src_remap[i] = j;
|
out->src_remap[i] = j;
|
||||||
out->dst_remap[j] = i;
|
out->dst_remap[j] = i;
|
||||||
spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this,
|
if (i != j)
|
||||||
i, j,
|
remap = true;
|
||||||
|
|
||||||
|
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%d) (%s -> %s)", this,
|
||||||
|
i, out->src_remap[i], j, out->dst_remap[j],
|
||||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||||
src_info.info.raw.position[i]),
|
src_info.info.raw.position[i]),
|
||||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||||
|
|
@ -1432,13 +1441,15 @@ static int setup_out_convert(struct impl *this)
|
||||||
out->conv.rate = dst_info.info.raw.rate;
|
out->conv.rate = dst_info.info.raw.rate;
|
||||||
out->conv.n_channels = dst_info.info.raw.channels;
|
out->conv.n_channels = dst_info.info.raw.channels;
|
||||||
out->conv.cpu_flags = this->cpu_flags;
|
out->conv.cpu_flags = this->cpu_flags;
|
||||||
|
out->need_remap = remap;
|
||||||
|
|
||||||
if ((res = convert_init(&out->conv)) < 0)
|
if ((res = convert_init(&out->conv)) < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d passthrough:%d %s", this,
|
spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d"
|
||||||
|
" passthrough:%d remap:%d %s", this,
|
||||||
this->cpu_flags, out->conv.cpu_flags, out->conv.method,
|
this->cpu_flags, out->conv.cpu_flags, out->conv.method,
|
||||||
out->conv.noise, out->conv.is_passthrough, out->conv.func_name);
|
out->conv.noise, out->conv.is_passthrough, remap, out->conv.func_name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -2218,7 +2229,7 @@ static int impl_node_process(void *object)
|
||||||
{
|
{
|
||||||
struct impl *this = object;
|
struct impl *this = object;
|
||||||
const void *src_datas[MAX_PORTS], **in_datas;
|
const void *src_datas[MAX_PORTS], **in_datas;
|
||||||
void *dst_datas[MAX_PORTS], **out_datas;
|
void *dst_datas[MAX_PORTS], *remap_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, n_out, max_out, quant_samples;
|
uint32_t n_samples, max_in, n_out, max_out, quant_samples;
|
||||||
struct port *port, *ctrlport = NULL;
|
struct port *port, *ctrlport = NULL;
|
||||||
|
|
@ -2232,7 +2243,7 @@ static int impl_node_process(void *object)
|
||||||
const struct spa_pod_sequence *ctrl = NULL;
|
const struct spa_pod_sequence *ctrl = NULL;
|
||||||
|
|
||||||
dir = &this->dir[SPA_DIRECTION_INPUT];
|
dir = &this->dir[SPA_DIRECTION_INPUT];
|
||||||
in_passthrough = dir->conv.is_passthrough;
|
in_passthrough = dir->conv.is_passthrough && !dir->need_remap;
|
||||||
|
|
||||||
max_in = UINT32_MAX;
|
max_in = UINT32_MAX;
|
||||||
|
|
||||||
|
|
@ -2271,7 +2282,7 @@ static int impl_node_process(void *object)
|
||||||
spa_log_trace_fp(this->log, "%p: empty control %d", this,
|
spa_log_trace_fp(this->log, "%p: empty control %d", this,
|
||||||
i * port->blocks + j);
|
i * port->blocks + j);
|
||||||
} else {
|
} else {
|
||||||
remap = dir->src_remap[n_src_datas++];
|
remap = n_src_datas++;
|
||||||
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);
|
||||||
|
|
@ -2306,7 +2317,7 @@ static int impl_node_process(void *object)
|
||||||
} else {
|
} else {
|
||||||
max_in = SPA_MIN(max_in, size / port->stride);
|
max_in = SPA_MIN(max_in, size / port->stride);
|
||||||
|
|
||||||
remap = dir->src_remap[n_src_datas++];
|
remap = n_src_datas++;
|
||||||
offs += this->in_offset * port->stride;
|
offs += this->in_offset * port->stride;
|
||||||
src_datas[remap] = SPA_PTROFF(bd->data, offs, void);
|
src_datas[remap] = SPA_PTROFF(bd->data, offs, void);
|
||||||
|
|
||||||
|
|
@ -2372,7 +2383,7 @@ static int impl_node_process(void *object)
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = &this->dir[SPA_DIRECTION_OUTPUT];
|
dir = &this->dir[SPA_DIRECTION_OUTPUT];
|
||||||
out_passthrough = dir->conv.is_passthrough;
|
out_passthrough = dir->conv.is_passthrough && !dir->need_remap;
|
||||||
|
|
||||||
/* collect output ports and monitor ports data */
|
/* collect output ports and monitor ports data */
|
||||||
for (i = 0; i < dir->n_ports; i++) {
|
for (i = 0; i < dir->n_ports; i++) {
|
||||||
|
|
@ -2399,7 +2410,7 @@ static int impl_node_process(void *object)
|
||||||
} else if (port->is_control) {
|
} else if (port->is_control) {
|
||||||
spa_log_trace_fp(this->log, "%p: empty control %d", this, j);
|
spa_log_trace_fp(this->log, "%p: empty control %d", this, j);
|
||||||
} else {
|
} else {
|
||||||
remap = dir->dst_remap[n_dst_datas++];
|
remap = n_dst_datas++;
|
||||||
dst_datas[remap] = SPA_PTR_ALIGN(this->scratch, MAX_ALIGN, void);
|
dst_datas[remap] = SPA_PTR_ALIGN(this->scratch, MAX_ALIGN, void);
|
||||||
spa_log_trace_fp(this->log, "%p: empty output %d->%d", this,
|
spa_log_trace_fp(this->log, "%p: empty output %d->%d", this,
|
||||||
i * port->blocks + j, remap);
|
i * port->blocks + j, remap);
|
||||||
|
|
@ -2438,7 +2449,7 @@ static int impl_node_process(void *object)
|
||||||
} else if (SPA_UNLIKELY(port->is_control)) {
|
} else if (SPA_UNLIKELY(port->is_control)) {
|
||||||
spa_log_trace_fp(this->log, "%p: control %d", this, j);
|
spa_log_trace_fp(this->log, "%p: control %d", this, j);
|
||||||
} else {
|
} else {
|
||||||
remap = dir->dst_remap[n_dst_datas++];
|
remap = n_dst_datas++;
|
||||||
dst_datas[remap] = SPA_PTROFF(bd->data,
|
dst_datas[remap] = SPA_PTROFF(bd->data,
|
||||||
this->out_offset * port->stride, void);
|
this->out_offset * port->stride, void);
|
||||||
max_out = SPA_MIN(max_out, bd->maxsize / port->stride);
|
max_out = SPA_MIN(max_out, bd->maxsize / port->stride);
|
||||||
|
|
@ -2458,14 +2469,26 @@ static int impl_node_process(void *object)
|
||||||
end_passthrough = mix_passthrough && resample_passthrough && out_passthrough;
|
end_passthrough = mix_passthrough && resample_passthrough && out_passthrough;
|
||||||
|
|
||||||
if (!in_passthrough || end_passthrough) {
|
if (!in_passthrough || end_passthrough) {
|
||||||
|
void **tmp_datas;
|
||||||
|
dir = &this->dir[SPA_DIRECTION_INPUT];
|
||||||
if (end_passthrough) {
|
if (end_passthrough) {
|
||||||
out_datas = (void **)dst_datas;
|
out_datas = (void **)dst_datas;
|
||||||
n_samples = SPA_MIN(n_samples, n_out);
|
n_samples = SPA_MIN(n_samples, n_out);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
out_datas = (void **)this->tmp_datas[(tmp++) & 1];
|
out_datas = (void **)this->tmp_datas[(tmp++) & 1];
|
||||||
|
}
|
||||||
|
if (dir->need_remap) {
|
||||||
|
for (i = 0; i < dir->conv.n_channels; i++) {
|
||||||
|
remap_datas[i] = out_datas[dir->src_remap[i]];
|
||||||
|
spa_log_trace_fp(this->log, "%p: %d -> %d", this, dir->src_remap[i], i);
|
||||||
|
}
|
||||||
|
tmp_datas = (void **)remap_datas;
|
||||||
|
} else {
|
||||||
|
tmp_datas = (void **)out_datas;
|
||||||
|
}
|
||||||
spa_log_trace_fp(this->log, "%p: convert %d %d", this, n_samples, end_passthrough);
|
spa_log_trace_fp(this->log, "%p: convert %d %d", this, n_samples, end_passthrough);
|
||||||
convert_process(&this->dir[SPA_DIRECTION_INPUT].conv, out_datas, src_datas, n_samples);
|
convert_process(&dir->conv, tmp_datas, src_datas, n_samples);
|
||||||
} else {
|
} else {
|
||||||
out_datas = (void **)src_datas;
|
out_datas = (void **)src_datas;
|
||||||
}
|
}
|
||||||
|
|
@ -2514,9 +2537,18 @@ static int impl_node_process(void *object)
|
||||||
this->out_offset += n_samples;
|
this->out_offset += n_samples;
|
||||||
|
|
||||||
if (!out_passthrough) {
|
if (!out_passthrough) {
|
||||||
in_datas = (const void**)out_datas;
|
dir = &this->dir[SPA_DIRECTION_OUTPUT];
|
||||||
|
if (dir->need_remap) {
|
||||||
|
for (i = 0; i < dir->conv.n_channels; i++) {
|
||||||
|
remap_datas[i] = out_datas[dir->dst_remap[i]];
|
||||||
|
spa_log_trace_fp(this->log, "%p: %d -> %d", this, i, dir->dst_remap[i]);
|
||||||
|
}
|
||||||
|
in_datas = (const void**)remap_datas;
|
||||||
|
} else {
|
||||||
|
in_datas = (const void**)out_datas;
|
||||||
|
}
|
||||||
spa_log_trace_fp(this->log, "%p: convert %d", this, n_samples);
|
spa_log_trace_fp(this->log, "%p: convert %d", this, n_samples);
|
||||||
convert_process(&this->dir[SPA_DIRECTION_OUTPUT].conv, dst_datas, in_datas, n_samples);
|
convert_process(&dir->conv, dst_datas, in_datas, n_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
spa_log_trace_fp(this->log, "%d/%d %d/%d %d->%d", this->in_offset, max_in,
|
spa_log_trace_fp(this->log, "%d/%d %d/%d %d->%d", this->in_offset, max_in,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue