153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2553a5a1b3Sopenharmony_ci#include "pulsecore/ffmpeg/avcodec.h" 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulsecore/resampler.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_cistruct ffmpeg_data { /* data specific to ffmpeg */ 3053a5a1b3Sopenharmony_ci struct AVResampleContext *state; 3153a5a1b3Sopenharmony_ci}; 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_cistatic unsigned ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { 3453a5a1b3Sopenharmony_ci unsigned used_frames = 0, c; 3553a5a1b3Sopenharmony_ci int previous_consumed_frames = -1; 3653a5a1b3Sopenharmony_ci struct ffmpeg_data *ffmpeg_data; 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci pa_assert(r); 3953a5a1b3Sopenharmony_ci pa_assert(input); 4053a5a1b3Sopenharmony_ci pa_assert(output); 4153a5a1b3Sopenharmony_ci pa_assert(out_n_frames); 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci ffmpeg_data = r->impl.data; 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci for (c = 0; c < r->work_channels; c++) { 4653a5a1b3Sopenharmony_ci unsigned u; 4753a5a1b3Sopenharmony_ci pa_memblock *b, *w; 4853a5a1b3Sopenharmony_ci int16_t *p, *t, *k, *q, *s; 4953a5a1b3Sopenharmony_ci int consumed_frames; 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci /* Allocate a new block */ 5253a5a1b3Sopenharmony_ci b = pa_memblock_new(r->mempool, in_n_frames * sizeof(int16_t)); 5353a5a1b3Sopenharmony_ci p = pa_memblock_acquire(b); 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci /* Now copy the input data, splitting up channels */ 5653a5a1b3Sopenharmony_ci t = (int16_t*) pa_memblock_acquire_chunk(input) + c; 5753a5a1b3Sopenharmony_ci k = p; 5853a5a1b3Sopenharmony_ci for (u = 0; u < in_n_frames; u++) { 5953a5a1b3Sopenharmony_ci *k = *t; 6053a5a1b3Sopenharmony_ci t += r->work_channels; 6153a5a1b3Sopenharmony_ci k ++; 6253a5a1b3Sopenharmony_ci } 6353a5a1b3Sopenharmony_ci pa_memblock_release(input->memblock); 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci /* Allocate buffer for the result */ 6653a5a1b3Sopenharmony_ci w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t)); 6753a5a1b3Sopenharmony_ci q = pa_memblock_acquire(w); 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci /* Now, resample */ 7053a5a1b3Sopenharmony_ci used_frames = (unsigned) av_resample(ffmpeg_data->state, 7153a5a1b3Sopenharmony_ci q, p, 7253a5a1b3Sopenharmony_ci &consumed_frames, 7353a5a1b3Sopenharmony_ci (int) in_n_frames, (int) *out_n_frames, 7453a5a1b3Sopenharmony_ci c >= (unsigned) (r->work_channels-1)); 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci pa_memblock_release(b); 7753a5a1b3Sopenharmony_ci pa_memblock_unref(b); 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci pa_assert(consumed_frames <= (int) in_n_frames); 8053a5a1b3Sopenharmony_ci pa_assert(previous_consumed_frames == -1 || consumed_frames == previous_consumed_frames); 8153a5a1b3Sopenharmony_ci previous_consumed_frames = consumed_frames; 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci /* And place the results in the output buffer */ 8453a5a1b3Sopenharmony_ci s = (int16_t *) pa_memblock_acquire_chunk(output) + c; 8553a5a1b3Sopenharmony_ci for (u = 0; u < used_frames; u++) { 8653a5a1b3Sopenharmony_ci *s = *q; 8753a5a1b3Sopenharmony_ci q++; 8853a5a1b3Sopenharmony_ci s += r->work_channels; 8953a5a1b3Sopenharmony_ci } 9053a5a1b3Sopenharmony_ci pa_memblock_release(output->memblock); 9153a5a1b3Sopenharmony_ci pa_memblock_release(w); 9253a5a1b3Sopenharmony_ci pa_memblock_unref(w); 9353a5a1b3Sopenharmony_ci } 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci *out_n_frames = used_frames; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci return in_n_frames - previous_consumed_frames; 9853a5a1b3Sopenharmony_ci} 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_cistatic void ffmpeg_free(pa_resampler *r) { 10153a5a1b3Sopenharmony_ci struct ffmpeg_data *ffmpeg_data; 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci pa_assert(r); 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci ffmpeg_data = r->impl.data; 10653a5a1b3Sopenharmony_ci if (ffmpeg_data->state) 10753a5a1b3Sopenharmony_ci av_resample_close(ffmpeg_data->state); 10853a5a1b3Sopenharmony_ci} 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ciint pa_resampler_ffmpeg_init(pa_resampler *r) { 11153a5a1b3Sopenharmony_ci struct ffmpeg_data *ffmpeg_data; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci pa_assert(r); 11453a5a1b3Sopenharmony_ci 11553a5a1b3Sopenharmony_ci ffmpeg_data = pa_xnew(struct ffmpeg_data, 1); 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci /* We could probably implement different quality levels by 11853a5a1b3Sopenharmony_ci * adjusting the filter parameters here. However, ffmpeg 11953a5a1b3Sopenharmony_ci * internally only uses these hardcoded values, so let's use them 12053a5a1b3Sopenharmony_ci * here for now as well until ffmpeg makes this configurable. */ 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci if (!(ffmpeg_data->state = av_resample_init((int) r->o_ss.rate, (int) r->i_ss.rate, 16, 10, 0, 0.8))) { 12353a5a1b3Sopenharmony_ci pa_xfree(ffmpeg_data); 12453a5a1b3Sopenharmony_ci return -1; 12553a5a1b3Sopenharmony_ci } 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci r->impl.free = ffmpeg_free; 12853a5a1b3Sopenharmony_ci r->impl.resample = ffmpeg_resample; 12953a5a1b3Sopenharmony_ci r->impl.data = (void *) ffmpeg_data; 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci return 0; 13253a5a1b3Sopenharmony_ci} 133