merge glitch-free branch back into trunk

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2445 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2008-05-15 23:34:41 +00:00
parent 91f092eadc
commit 045c1d602d
189 changed files with 12559 additions and 4959 deletions

View file

@ -47,7 +47,7 @@
#include "resampler.h"
/* Number of samples of extra space we allow the resamplers to return */
#define EXTRA_SAMPLES 128
#define EXTRA_FRAMES 128
struct pa_resampler {
pa_resample_method_t method;
@ -79,6 +79,15 @@ struct pa_resampler {
unsigned i_counter;
} trivial;
struct { /* data specific to the peak finder pseudo resampler */
unsigned o_counter;
unsigned i_counter;
float max_f[PA_CHANNELS_MAX];
int16_t max_i[PA_CHANNELS_MAX];
} peaks;
#ifdef HAVE_LIBSAMPLERATE
struct { /* data specific to libsamplerate */
SRC_STATE *state;
@ -99,6 +108,7 @@ static int copy_init(pa_resampler *r);
static int trivial_init(pa_resampler*r);
static int speex_init(pa_resampler*r);
static int ffmpeg_init(pa_resampler*r);
static int peaks_init(pa_resampler*r);
#ifdef HAVE_LIBSAMPLERATE
static int libsamplerate_init(pa_resampler*r);
#endif
@ -144,7 +154,8 @@ static int (* const init_table[])(pa_resampler*r) = {
[PA_RESAMPLER_SPEEX_FIXED_BASE+10] = speex_init,
[PA_RESAMPLER_FFMPEG] = ffmpeg_init,
[PA_RESAMPLER_AUTO] = NULL,
[PA_RESAMPLER_COPY] = copy_init
[PA_RESAMPLER_COPY] = copy_init,
[PA_RESAMPLER_PEAKS] = peaks_init,
};
static inline size_t sample_size(pa_sample_format_t f) {
@ -242,9 +253,9 @@ pa_resampler* pa_resampler_new(
if ((method >= PA_RESAMPLER_SPEEX_FIXED_BASE && method <= PA_RESAMPLER_SPEEX_FIXED_MAX) ||
(method == PA_RESAMPLER_FFMPEG))
r->work_format = PA_SAMPLE_S16NE;
else if (method == PA_RESAMPLER_TRIVIAL || method == PA_RESAMPLER_COPY) {
else if (method == PA_RESAMPLER_TRIVIAL || method == PA_RESAMPLER_COPY || method == PA_RESAMPLER_PEAKS) {
if (r->map_required || a->format != b->format) {
if (r->map_required || a->format != b->format || method == PA_RESAMPLER_PEAKS) {
if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE ||
a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE ||
@ -347,6 +358,12 @@ size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
}
size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
pa_assert(r);
return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz;
}
size_t pa_resampler_max_block_size(pa_resampler *r) {
size_t block_size_max;
pa_sample_spec ss;
@ -358,22 +375,17 @@ size_t pa_resampler_max_block_size(pa_resampler *r) {
/* We deduce the "largest" sample spec we're using during the
* conversion */
ss = r->i_ss;
if (r->o_ss.channels > ss.channels)
ss.channels = r->o_ss.channels;
ss.channels = PA_MAX(r->i_ss.channels, r->o_ss.channels);
/* We silently assume that the format enum is ordered by size */
if (r->o_ss.format > ss.format)
ss.format = r->o_ss.format;
if (r->work_format > ss.format)
ss.format = r->work_format;
ss.format = PA_MAX(r->i_ss.format, r->o_ss.format);
ss.format = PA_MAX(ss.format, r->work_format);
if (r->o_ss.rate > ss.rate)
ss.rate = r->o_ss.rate;
ss.rate = PA_MAX(r->i_ss.rate, r->o_ss.rate);
fs = pa_frame_size(&ss);
return (((block_size_max/fs + EXTRA_SAMPLES)*r->i_ss.rate)/ss.rate)*r->i_fz;
return (((block_size_max/fs - EXTRA_FRAMES)*r->i_ss.rate)/ss.rate)*r->i_fz;
}
void pa_resampler_reset(pa_resampler *r) {
@ -420,7 +432,8 @@ static const char * const resample_methods[] = {
"speex-fixed-10",
"ffmpeg",
"auto",
"copy"
"copy",
"peaks"
};
const char *pa_resample_method_to_string(pa_resample_method_t m) {
@ -1069,7 +1082,7 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
in_n_samples = input->length / r->w_sz;
in_n_frames = in_n_samples / r->o_ss.channels;
out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_SAMPLES;
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;
r->buf3.index = 0;
@ -1400,6 +1413,113 @@ static int trivial_init(pa_resampler*r) {
return 0;
}
/* Peak finder implementation */
static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
size_t fz;
unsigned o_index;
void *src, *dst;
unsigned start = 0;
pa_assert(r);
pa_assert(input);
pa_assert(output);
pa_assert(out_n_frames);
fz = r->w_sz * r->o_ss.channels;
src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
for (o_index = 0;; o_index++, r->peaks.o_counter++) {
unsigned j;
j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate);
j = j > r->peaks.i_counter ? j - r->peaks.i_counter : 0;
if (j >= in_n_frames)
break;
pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
if (r->work_format == PA_SAMPLE_S16NE) {
unsigned i, c;
int16_t *s = (int16_t*) ((uint8_t*) src + fz * j);
int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index);
for (i = start; i <= j; i++)
for (c = 0; c < r->o_ss.channels; c++, s++) {
int16_t n;
n = *s < 0 ? -*s : *s;
if (n > r->peaks.max_i[c])
r->peaks.max_i[c] = n;
}
for (c = 0; c < r->o_ss.channels; c++, d++)
*d = r->peaks.max_i[c];
memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i));
} else {
unsigned i, c;
float *s = (float*) ((uint8_t*) src + fz * j);
float *d = (float*) ((uint8_t*) dst + fz * o_index);
pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE);
for (i = start; i <= j; i++)
for (c = 0; c < r->o_ss.channels; c++, s++) {
float n = fabsf(*s);
if (n > r->peaks.max_f[c])
r->peaks.max_f[c] = n;
}
for (c = 0; c < r->o_ss.channels; c++, d++)
*d = r->peaks.max_f[c];
memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f));
}
}
pa_memblock_release(input->memblock);
pa_memblock_release(output->memblock);
*out_n_frames = o_index;
r->peaks.i_counter += in_n_frames;
/* Normalize counters */
while (r->peaks.i_counter >= r->i_ss.rate) {
pa_assert(r->peaks.o_counter >= r->o_ss.rate);
r->peaks.i_counter -= r->i_ss.rate;
r->peaks.o_counter -= r->o_ss.rate;
}
}
static void peaks_update_rates_or_reset(pa_resampler *r) {
pa_assert(r);
r->peaks.i_counter = 0;
r->peaks.o_counter = 0;
}
static int peaks_init(pa_resampler*r) {
pa_assert(r);
r->peaks.o_counter = r->peaks.i_counter = 0;
memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i));
memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f));
r->impl_resample = peaks_resample;
r->impl_update_rates = peaks_update_rates_or_reset;
r->impl_reset = peaks_update_rates_or_reset;
return 0;
}
/*** ffmpeg based implementation ***/
static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {