make ffmpeg resampler actually work

git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1717 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2007-08-25 22:26:59 +00:00
parent f0dbbe966f
commit 9439e81de1

View file

@ -80,7 +80,7 @@ struct pa_resampler {
struct { /* data specific to ffmpeg */
struct AVResampleContext *state;
unsigned initial_i_rate, initial_o_rate;
pa_memchunk buf[PA_CHANNELS_MAX];
} ffmpeg;
};
@ -848,41 +848,100 @@ static int trivial_init(pa_resampler*r) {
/*** 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) {
short *src, *dst;
int consumed;
int c;
unsigned used_frames = 0, c;
pa_assert(r);
pa_assert(input);
pa_assert(output);
pa_assert(out_n_frames);
src = (short*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
dst = (short*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
for (c = 0; c < r->o_ss.channels; c++)
*out_n_frames = av_resample(r->ffmpeg.state,
dst + r->w_sz*c,
src + r->w_sz*c,
&consumed,
in_n_frames, *out_n_frames,
c >= r->o_ss.channels-1);
for (c = 0; c < r->o_ss.channels; c++) {
unsigned u;
pa_memblock *b, *w;
int16_t *p, *t, *k, *q, *s;
int consumed_frames;
unsigned in, l;
pa_assert(*out_n_frames > 0);
pa_assert(consumed == in_n_frames);
pa_memblock_release(input->memblock);
pa_memblock_release(output->memblock);
/* Allocate a new block */
b = pa_memblock_new(r->mempool, r->ffmpeg.buf[c].length + in_n_frames * sizeof(int16_t));
p = pa_memblock_acquire(b);
/* Copy the remaining data into it */
l = r->ffmpeg.buf[c].length;
if (r->ffmpeg.buf[c].memblock) {
t = (int16_t*) ((uint8_t*) pa_memblock_acquire(r->ffmpeg.buf[c].memblock) + r->ffmpeg.buf[c].index);
memcpy(p, t, l);
pa_memblock_release(r->ffmpeg.buf[c].memblock);
pa_memblock_unref(r->ffmpeg.buf[c].memblock);
pa_memchunk_reset(&r->ffmpeg.buf[c]);
}
/* Now append the new data, splitting up channels */
t = ((int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index)) + c;
k = (int16_t*) ((uint8_t*) p + l);
for (u = 0; u < in_n_frames; u++) {
*k = *t;
t += r->o_ss.channels;
k ++;
}
pa_memblock_release(input->memblock);
/* Calculate the resulting number of frames */
in = in_n_frames + l / sizeof(int16_t);
/* Allocate buffer for the result */
w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t));
q = pa_memblock_acquire(w);
/* Now, resample */
used_frames = av_resample(r->ffmpeg.state,
q, p,
&consumed_frames,
in, *out_n_frames,
c >= (unsigned) r->o_ss.channels-1);
pa_memblock_release(b);
/* Now store the remaining samples away */
pa_assert(consumed_frames <= (int) in);
if (consumed_frames < (int) in) {
r->ffmpeg.buf[c].memblock = b;
r->ffmpeg.buf[c].index = consumed_frames * sizeof(int16_t);
r->ffmpeg.buf[c].length = (in - consumed_frames) * sizeof(int16_t);
} else
pa_memblock_unref(b);
/* And place the results in the output buffer */
s = (short*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index) + c;
for (u = 0; u < used_frames; u++) {
*s = *q;
q++;
s += r->o_ss.channels;
}
pa_memblock_release(output->memblock);
pa_memblock_release(w);
pa_memblock_unref(w);
}
*out_n_frames = used_frames;
}
static void ffmpeg_free(pa_resampler *r) {
unsigned c;
pa_assert(r);
if (r->ffmpeg.state)
av_resample_close(r->ffmpeg.state);
for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
if (r->ffmpeg.buf[c].memblock)
pa_memblock_unref(r->ffmpeg.buf[c].memblock);
}
static int ffmpeg_init(pa_resampler *r) {
unsigned c;
pa_assert(r);
/* We could probably implement different quality levels by
@ -896,5 +955,8 @@ static int ffmpeg_init(pa_resampler *r) {
r->impl_free = ffmpeg_free;
r->impl_resample = ffmpeg_resample;
for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
pa_memchunk_reset(&r->ffmpeg.buf[c]);
return 0;
}