added VPATH support for multiple dir compilation
[libav.git] / libavcodec / resample.c
CommitLineData
de6d9b64
FB
1/*
2 * Sample rate convertion for both audio and video
3 * Copyright (c) 2000 Gerard Lantau.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
de6d9b64 19#include "avcodec.h"
1a565432 20#include <math.h>
de6d9b64
FB
21
22typedef struct {
23 /* fractional resampling */
24 UINT32 incr; /* fractional increment */
25 UINT32 frac;
26 int last_sample;
27 /* integer down sample */
28 int iratio; /* integer divison ratio */
29 int icount, isum;
30 int inv;
31} ReSampleChannelContext;
32
33struct ReSampleContext {
34 ReSampleChannelContext channel_ctx[2];
35 float ratio;
36 /* channel convert */
37 int input_channels, output_channels, filter_channels;
38};
39
40
41#define FRAC_BITS 16
42#define FRAC (1 << FRAC_BITS)
43
44static void init_mono_resample(ReSampleChannelContext *s, float ratio)
45{
46 ratio = 1.0 / ratio;
47 s->iratio = (int)floor(ratio);
48 if (s->iratio == 0)
49 s->iratio = 1;
50 s->incr = (int)((ratio / s->iratio) * FRAC);
8170f3dc 51 s->frac = FRAC;
de6d9b64
FB
52 s->last_sample = 0;
53 s->icount = s->iratio;
54 s->isum = 0;
55 s->inv = (FRAC / s->iratio);
56}
57
58/* fractional audio resampling */
59static int fractional_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
60{
61 unsigned int frac, incr;
62 int l0, l1;
63 short *q, *p, *pend;
64
65 l0 = s->last_sample;
66 incr = s->incr;
67 frac = s->frac;
68
69 p = input;
70 pend = input + nb_samples;
71 q = output;
72
73 l1 = *p++;
74 for(;;) {
75 /* interpolate */
76 *q++ = (l0 * (FRAC - frac) + l1 * frac) >> FRAC_BITS;
77 frac = frac + s->incr;
78 while (frac >= FRAC) {
79 if (p >= pend)
80 goto the_end;
81 frac -= FRAC;
82 l0 = l1;
83 l1 = *p++;
84 }
85 }
86 the_end:
87 s->last_sample = l1;
88 s->frac = frac;
89 return q - output;
90}
91
92static int integer_downsample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
93{
94 short *q, *p, *pend;
95 int c, sum;
96
97 p = input;
98 pend = input + nb_samples;
99 q = output;
100
101 c = s->icount;
102 sum = s->isum;
103
104 for(;;) {
105 sum += *p++;
106 if (--c == 0) {
107 *q++ = (sum * s->inv) >> FRAC_BITS;
108 c = s->iratio;
109 sum = 0;
110 }
111 if (p >= pend)
112 break;
113 }
114 s->isum = sum;
115 s->icount = c;
116 return q - output;
117}
118
119/* n1: number of samples */
120static void stereo_to_mono(short *output, short *input, int n1)
121{
122 short *p, *q;
123 int n = n1;
124
125 p = input;
126 q = output;
127 while (n >= 4) {
128 q[0] = (p[0] + p[1]) >> 1;
129 q[1] = (p[2] + p[3]) >> 1;
130 q[2] = (p[4] + p[5]) >> 1;
131 q[3] = (p[6] + p[7]) >> 1;
132 q += 4;
133 p += 8;
134 n -= 4;
135 }
136 while (n > 0) {
137 q[0] = (p[0] + p[1]) >> 1;
138 q++;
139 p += 2;
140 n--;
141 }
142}
143
144/* n1: number of samples */
145static void mono_to_stereo(short *output, short *input, int n1)
146{
147 short *p, *q;
148 int n = n1;
149 int v;
150
151 p = input;
152 q = output;
153 while (n >= 4) {
154 v = p[0]; q[0] = v; q[1] = v;
155 v = p[1]; q[2] = v; q[3] = v;
156 v = p[2]; q[4] = v; q[5] = v;
157 v = p[3]; q[6] = v; q[7] = v;
158 q += 8;
159 p += 4;
160 n -= 4;
161 }
162 while (n > 0) {
163 v = p[0]; q[0] = v; q[1] = v;
164 q += 2;
165 p += 1;
166 n--;
167 }
168}
169
170/* XXX: should use more abstract 'N' channels system */
171static void stereo_split(short *output1, short *output2, short *input, int n)
172{
173 int i;
174
175 for(i=0;i<n;i++) {
176 *output1++ = *input++;
177 *output2++ = *input++;
178 }
179}
180
181static void stereo_mux(short *output, short *input1, short *input2, int n)
182{
183 int i;
184
185 for(i=0;i<n;i++) {
186 *output++ = *input1++;
187 *output++ = *input2++;
188 }
189}
190
191static int mono_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
192{
1a565432 193 short *buf1;
de6d9b64
FB
194 short *buftmp;
195
1a565432
FB
196 buf1= (short*) malloc( nb_samples * sizeof(short) );
197
de6d9b64
FB
198 /* first downsample by an integer factor with averaging filter */
199 if (s->iratio > 1) {
200 buftmp = buf1;
201 nb_samples = integer_downsample(s, buftmp, input, nb_samples);
202 } else {
203 buftmp = input;
204 }
205
206 /* then do a fractional resampling with linear interpolation */
207 if (s->incr != FRAC) {
208 nb_samples = fractional_resample(s, output, buftmp, nb_samples);
209 } else {
210 memcpy(output, buftmp, nb_samples * sizeof(short));
211 }
1a565432 212 free(buf1);
de6d9b64
FB
213 return nb_samples;
214}
215
216ReSampleContext *audio_resample_init(int output_channels, int input_channels,
217 int output_rate, int input_rate)
218{
219 ReSampleContext *s;
220 int i;
221
222 if (output_channels > 2 || input_channels > 2)
223 return NULL;
224
225 s = av_mallocz(sizeof(ReSampleContext));
226 if (!s)
227 return NULL;
228
229 s->ratio = (float)output_rate / (float)input_rate;
230
231 s->input_channels = input_channels;
232 s->output_channels = output_channels;
233
234 s->filter_channels = s->input_channels;
235 if (s->output_channels < s->filter_channels)
236 s->filter_channels = s->output_channels;
237
238 for(i=0;i<s->filter_channels;i++) {
239 init_mono_resample(&s->channel_ctx[i], s->ratio);
240 }
241 return s;
242}
243
244/* resample audio. 'nb_samples' is the number of input samples */
245/* XXX: optimize it ! */
246/* XXX: do it with polyphase filters, since the quality here is
247 HORRIBLE. Return the number of samples available in output */
248int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples)
249{
250 int i, nb_samples1;
1a565432
FB
251 short *bufin[2];
252 short *bufout[2];
de6d9b64 253 short *buftmp2[2], *buftmp3[2];
1a565432 254 int lenout;
de6d9b64
FB
255
256 if (s->input_channels == s->output_channels && s->ratio == 1.0) {
257 /* nothing to do */
258 memcpy(output, input, nb_samples * s->input_channels * sizeof(short));
259 return nb_samples;
260 }
261
1a565432
FB
262 /* XXX: move those malloc to resample init code */
263 bufin[0]= (short*) malloc( nb_samples * sizeof(short) );
264 bufin[1]= (short*) malloc( nb_samples * sizeof(short) );
265
266 /* make some zoom to avoid round pb */
267 lenout= (int)(nb_samples * s->ratio) + 16;
268 bufout[0]= (short*) malloc( lenout * sizeof(short) );
269 bufout[1]= (short*) malloc( lenout * sizeof(short) );
270
de6d9b64
FB
271 if (s->input_channels == 2 &&
272 s->output_channels == 1) {
273 buftmp2[0] = bufin[0];
274 buftmp3[0] = output;
275 stereo_to_mono(buftmp2[0], input, nb_samples);
276 } else if (s->output_channels == 2 && s->input_channels == 1) {
277 buftmp2[0] = input;
278 buftmp3[0] = bufout[0];
279 } else if (s->output_channels == 2) {
280 buftmp2[0] = bufin[0];
281 buftmp2[1] = bufin[1];
282 buftmp3[0] = bufout[0];
283 buftmp3[1] = bufout[1];
284 stereo_split(buftmp2[0], buftmp2[1], input, nb_samples);
285 } else {
286 buftmp2[0] = input;
287 buftmp3[0] = output;
288 }
289
290 /* resample each channel */
291 nb_samples1 = 0; /* avoid warning */
292 for(i=0;i<s->filter_channels;i++) {
293 nb_samples1 = mono_resample(&s->channel_ctx[i], buftmp3[i], buftmp2[i], nb_samples);
294 }
295
296 if (s->output_channels == 2 && s->input_channels == 1) {
297 mono_to_stereo(output, buftmp3[0], nb_samples1);
298 } else if (s->output_channels == 2) {
299 stereo_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
300 }
301
1a565432
FB
302 free(bufin[0]);
303 free(bufin[1]);
304
305 free(bufout[0]);
306 free(bufout[1]);
de6d9b64
FB
307 return nb_samples1;
308}
309
310void audio_resample_close(ReSampleContext *s)
311{
312 free(s);
313}