diff options
author | Lennart Poettering <lennart@poettering.net> | 2007-08-25 22:26:59 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2007-08-25 22:26:59 +0000 |
commit | 9439e81de18928ea6c373c18eebf048d51801c3a (patch) | |
tree | d21152ad5a905151b317f650631e666a93026641 | |
parent | f0dbbe966ff321997e57c5e47308b1e18d962781 (diff) |
make ffmpeg resampler actually work
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1717 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r-- | src/pulsecore/resampler.c | 100 |
1 files changed, 81 insertions, 19 deletions
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 47a5eac4..dd379b8a 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -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; + + /* 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]); + } - pa_assert(*out_n_frames > 0); - pa_assert(consumed == in_n_frames); - - pa_memblock_release(input->memblock); - pa_memblock_release(output->memblock); + /* 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; } |