mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
resampler: Resample first followed by remapping if have more out channels than in channels
The patch intends to reduce computational load when resampling AND remapping. The PA resampler performs the following steps: sample format conversion -> remapping -> resampling -> sample format conversion In case the number of output channels is higher than the number of input channels, the resampler has to be run more often than necessary. E.g. in case of mono to 4-channel remapping, the resampler runs on 4 channels separately. To ímprove this, the PA resampler pipeline is made adaptive: if out-channels <= in-channels: sample format conversion -> remapping -> resampling -> sample format conversion if out-channels > in-channels: sample format conversion -> resampling -> remapping -> sample format conversion Signed-off-by: Peter Meerwald <p.meerwald@bct-electronic.com>
This commit is contained in:
parent
505a57d32d
commit
30ce3a14e5
1 changed files with 31 additions and 13 deletions
|
|
@ -67,6 +67,7 @@ struct pa_resampler {
|
|||
bool remap_buf_contains_leftover_data;
|
||||
|
||||
pa_sample_format_t work_format;
|
||||
uint8_t work_channels;
|
||||
|
||||
pa_convert_func_t to_work_format_func;
|
||||
pa_convert_func_t from_work_format_func;
|
||||
|
|
@ -328,6 +329,16 @@ pa_resampler* pa_resampler_new(
|
|||
}
|
||||
}
|
||||
|
||||
if (r->o_ss.channels <= r->i_ss.channels)
|
||||
r->work_channels = r->o_ss.channels;
|
||||
else
|
||||
r->work_channels = r->i_ss.channels;
|
||||
|
||||
pa_log_debug("Resampler:\n rate %d -> %d (method %s),\n format %s -> %s (intermediate %s),\n channels %d -> %d (resampling %d)",
|
||||
a->rate, b->rate, pa_resample_method_to_string(r->method),
|
||||
pa_sample_format_to_string(a->format), pa_sample_format_to_string(b->format), pa_sample_format_to_string(r->work_format),
|
||||
a->channels, b->channels, r->work_channels);
|
||||
|
||||
/* initialize implementation */
|
||||
if (init_table[method](r) < 0)
|
||||
goto fail;
|
||||
|
|
@ -1140,10 +1151,10 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
|
|||
return input;
|
||||
|
||||
in_n_samples = (unsigned) (input->length / r->w_sz);
|
||||
in_n_frames = (unsigned) (in_n_samples / r->o_ss.channels);
|
||||
in_n_frames = (unsigned) (in_n_samples / r->work_channels);
|
||||
|
||||
out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_FRAMES;
|
||||
out_n_samples = out_n_frames * r->o_ss.channels;
|
||||
out_n_samples = out_n_frames * r->work_channels;
|
||||
|
||||
r->resample_buf.index = 0;
|
||||
r->resample_buf.length = r->w_sz * out_n_samples;
|
||||
|
|
@ -1157,7 +1168,7 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
|
|||
}
|
||||
|
||||
r->impl_resample(r, input, in_n_frames, &r->resample_buf, &out_n_frames);
|
||||
r->resample_buf.length = out_n_frames * r->w_sz * r->o_ss.channels;
|
||||
r->resample_buf.length = out_n_frames * r->w_sz * r->work_channels;
|
||||
|
||||
return &r->resample_buf;
|
||||
}
|
||||
|
|
@ -1210,8 +1221,15 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out)
|
|||
|
||||
buf = (pa_memchunk*) in;
|
||||
buf = convert_to_work_format(r, buf);
|
||||
buf = remap_channels(r, buf);
|
||||
buf = resample(r, buf);
|
||||
/* Try to save resampling effort: if we have more output channels than
|
||||
* input channels, do resampling first, then remapping. */
|
||||
if (r->o_ss.channels <= r->i_ss.channels) {
|
||||
buf = remap_channels(r, buf);
|
||||
buf = resample(r, buf);
|
||||
} else {
|
||||
buf = resample(r, buf);
|
||||
buf = remap_channels(r, buf);
|
||||
}
|
||||
|
||||
if (buf->length) {
|
||||
buf = convert_from_work_format(r, buf);
|
||||
|
|
@ -1276,8 +1294,8 @@ static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, un
|
|||
pa_assert_se(src_process(r->src.state, &data) == 0);
|
||||
|
||||
if (data.input_frames_used < in_n_frames) {
|
||||
void *leftover_data = data.data_in + data.input_frames_used * r->o_ss.channels;
|
||||
size_t leftover_length = (in_n_frames - data.input_frames_used) * sizeof(float) * r->o_ss.channels;
|
||||
void *leftover_data = data.data_in + data.input_frames_used * r->work_channels;
|
||||
size_t leftover_length = (in_n_frames - data.input_frames_used) * sizeof(float) * r->work_channels;
|
||||
|
||||
save_leftover(r, leftover_data, leftover_length);
|
||||
}
|
||||
|
|
@ -1413,7 +1431,7 @@ static int speex_init(pa_resampler *r) {
|
|||
|
||||
pa_log_info("Choosing speex quality setting %i.", q);
|
||||
|
||||
if (!(r->speex.state = speex_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
|
||||
if (!(r->speex.state = speex_resampler_init(r->work_channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1432,7 +1450,7 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned
|
|||
pa_assert(output);
|
||||
pa_assert(out_n_frames);
|
||||
|
||||
fz = r->w_sz * r->o_ss.channels;
|
||||
fz = r->w_sz * r->work_channels;
|
||||
|
||||
src = pa_memblock_acquire_chunk(input);
|
||||
dst = pa_memblock_acquire_chunk(output);
|
||||
|
|
@ -1616,7 +1634,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned
|
|||
pa_assert(output);
|
||||
pa_assert(out_n_frames);
|
||||
|
||||
for (c = 0; c < r->o_ss.channels; c++) {
|
||||
for (c = 0; c < r->work_channels; c++) {
|
||||
unsigned u;
|
||||
pa_memblock *b, *w;
|
||||
int16_t *p, *t, *k, *q, *s;
|
||||
|
|
@ -1631,7 +1649,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned
|
|||
k = p;
|
||||
for (u = 0; u < in_n_frames; u++) {
|
||||
*k = *t;
|
||||
t += r->o_ss.channels;
|
||||
t += r->work_channels;
|
||||
k ++;
|
||||
}
|
||||
pa_memblock_release(input->memblock);
|
||||
|
|
@ -1645,7 +1663,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned
|
|||
q, p,
|
||||
&consumed_frames,
|
||||
(int) in_n_frames, (int) *out_n_frames,
|
||||
c >= (unsigned) (r->o_ss.channels-1));
|
||||
c >= (unsigned) (r->work_channels-1));
|
||||
|
||||
pa_memblock_release(b);
|
||||
pa_memblock_unref(b);
|
||||
|
|
@ -1659,7 +1677,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned
|
|||
for (u = 0; u < used_frames; u++) {
|
||||
*s = *q;
|
||||
q++;
|
||||
s += r->o_ss.channels;
|
||||
s += r->work_channels;
|
||||
}
|
||||
pa_memblock_release(output->memblock);
|
||||
pa_memblock_release(w);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue