## ffmpeg / libavcodec / resample.c @ 029911d1

History | View | Annotate | Download (9 KB)

1 | de6d9b64 | Fabrice Bellard | ```
/*
``` |
---|---|---|---|

2 | ```
* Sample rate convertion for both audio and video
``` |
||

3 | ff4ec49e | Fabrice Bellard | ```
* Copyright (c) 2000 Fabrice Bellard.
``` |

4 | de6d9b64 | Fabrice Bellard | ```
*
``` |

5 | ff4ec49e | Fabrice Bellard | ```
* This library is free software; you can redistribute it and/or
``` |

6 | ```
* modify it under the terms of the GNU Lesser General Public
``` |
||

7 | ```
* License as published by the Free Software Foundation; either
``` |
||

8 | ```
* version 2 of the License, or (at your option) any later version.
``` |
||

9 | de6d9b64 | Fabrice Bellard | ```
*
``` |

10 | ff4ec49e | Fabrice Bellard | ```
* This library is distributed in the hope that it will be useful,
``` |

11 | de6d9b64 | Fabrice Bellard | ```
* but WITHOUT ANY WARRANTY; without even the implied warranty of
``` |

12 | ff4ec49e | Fabrice Bellard | ```
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
``` |

13 | ```
* Lesser General Public License for more details.
``` |
||

14 | de6d9b64 | Fabrice Bellard | ```
*
``` |

15 | ff4ec49e | Fabrice Bellard | ```
* You should have received a copy of the GNU Lesser General Public
``` |

16 | ```
* License along with this library; if not, write to the Free Software
``` |
||

17 | ```
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
``` |
||

18 | de6d9b64 | Fabrice Bellard | ```
*/
``` |

19 | 983e3246 | Michael Niedermayer | |

20 | ```
/**
``` |
||

21 | ```
* @file resample.c
``` |
||

22 | ```
* Sample rate convertion for both audio and video.
``` |
||

23 | ```
*/
``` |
||

24 | |||

25 | de6d9b64 | Fabrice Bellard | #include "avcodec.h" |

26 | 4a899dd6 | Zdenek Kabelac | #include "os_support.h" |

27 | 69db4e10 | Slavik Gnatenko | |

28 | de6d9b64 | Fabrice Bellard | typedef struct { |

29 | ```
/* fractional resampling */
``` |
||

30 | 0c1a9eda | Zdenek Kabelac | ```
uint32_t incr; /* fractional increment */
``` |

31 | uint32_t frac; |
||

32 | de6d9b64 | Fabrice Bellard | ```
int last_sample;
``` |

33 | ```
/* integer down sample */
``` |
||

34 | int iratio; /* integer divison ratio */ |
||

35 | ```
int icount, isum;
``` |
||

36 | ```
int inv;
``` |
||

37 | } ReSampleChannelContext; |
||

38 | |||

39 | ```
struct ReSampleContext {
``` |
||

40 | ```
ReSampleChannelContext channel_ctx[2];
``` |
||

41 | ```
float ratio;
``` |
||

42 | ```
/* channel convert */
``` |
||

43 | ```
int input_channels, output_channels, filter_channels;
``` |
||

44 | }; |
||

45 | |||

46 | |||

47 | #define FRAC_BITS 16 |
||

48 | #define FRAC (1 << FRAC_BITS) |
||

49 | |||

50 | static void init_mono_resample(ReSampleChannelContext *s, float ratio) |
||

51 | { |
||

52 | ratio = 1.0 / ratio; |
||

53 | 5c91a675 | Zdenek Kabelac | ```
s->iratio = (int)floorf(ratio);
``` |

54 | de6d9b64 | Fabrice Bellard | if (s->iratio == 0) |

55 | ```
s->iratio = 1;
``` |
||

56 | ```
s->incr = (int)((ratio / s->iratio) * FRAC);
``` |
||

57 | 8170f3dc | Philip Gladstone | s->frac = FRAC; |

58 | de6d9b64 | Fabrice Bellard | ```
s->last_sample = 0;
``` |

59 | s->icount = s->iratio; |
||

60 | ```
s->isum = 0;
``` |
||

61 | s->inv = (FRAC / s->iratio); |
||

62 | } |
||

63 | |||

64 | ```
/* fractional audio resampling */
``` |
||

65 | static int fractional_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples) |
||

66 | { |
||

67 | unsigned int frac, incr; |
||

68 | ```
int l0, l1;
``` |
||

69 | ```
short *q, *p, *pend;
``` |
||

70 | |||

71 | l0 = s->last_sample; |
||

72 | incr = s->incr; |
||

73 | frac = s->frac; |
||

74 | |||

75 | p = input; |
||

76 | pend = input + nb_samples; |
||

77 | q = output; |
||

78 | |||

79 | l1 = *p++; |
||

80 | ```
for(;;) {
``` |
||

81 | ```
/* interpolate */
``` |
||

82 | *q++ = (l0 * (FRAC - frac) + l1 * frac) >> FRAC_BITS; |
||

83 | frac = frac + s->incr; |
||

84 | ```
while (frac >= FRAC) {
``` |
||

85 | 9c89585a | Fabrice Bellard | frac -= FRAC; |

86 | de6d9b64 | Fabrice Bellard | ```
if (p >= pend)
``` |

87 | ```
goto the_end;
``` |
||

88 | l0 = l1; |
||

89 | l1 = *p++; |
||

90 | } |
||

91 | } |
||

92 | ```
the_end:
``` |
||

93 | s->last_sample = l1; |
||

94 | s->frac = frac; |
||

95 | ```
return q - output;
``` |
||

96 | } |
||

97 | |||

98 | static int integer_downsample(ReSampleChannelContext *s, short *output, short *input, int nb_samples) |
||

99 | { |
||

100 | ```
short *q, *p, *pend;
``` |
||

101 | ```
int c, sum;
``` |
||

102 | |||

103 | p = input; |
||

104 | pend = input + nb_samples; |
||

105 | q = output; |
||

106 | |||

107 | c = s->icount; |
||

108 | sum = s->isum; |
||

109 | |||

110 | ```
for(;;) {
``` |
||

111 | sum += *p++; |
||

112 | if (--c == 0) { |
||

113 | *q++ = (sum * s->inv) >> FRAC_BITS; |
||

114 | c = s->iratio; |
||

115 | ```
sum = 0;
``` |
||

116 | } |
||

117 | ```
if (p >= pend)
``` |
||

118 | ```
break;
``` |
||

119 | } |
||

120 | s->isum = sum; |
||

121 | s->icount = c; |
||

122 | ```
return q - output;
``` |
||

123 | } |
||

124 | |||

125 | ```
/* n1: number of samples */
``` |
||

126 | static void stereo_to_mono(short *output, short *input, int n1) |
||

127 | { |
||

128 | ```
short *p, *q;
``` |
||

129 | ```
int n = n1;
``` |
||

130 | |||

131 | p = input; |
||

132 | q = output; |
||

133 | while (n >= 4) { |
||

134 | q[0] = (p[0] + p[1]) >> 1; |
||

135 | q[1] = (p[2] + p[3]) >> 1; |
||

136 | q[2] = (p[4] + p[5]) >> 1; |
||

137 | q[3] = (p[6] + p[7]) >> 1; |
||

138 | ```
q += 4;
``` |
||

139 | ```
p += 8;
``` |
||

140 | ```
n -= 4;
``` |
||

141 | } |
||

142 | while (n > 0) { |
||

143 | q[0] = (p[0] + p[1]) >> 1; |
||

144 | q++; |
||

145 | ```
p += 2;
``` |
||

146 | n--; |
||

147 | } |
||

148 | } |
||

149 | |||

150 | ```
/* n1: number of samples */
``` |
||

151 | static void mono_to_stereo(short *output, short *input, int n1) |
||

152 | { |
||

153 | ```
short *p, *q;
``` |
||

154 | ```
int n = n1;
``` |
||

155 | ```
int v;
``` |
||

156 | |||

157 | p = input; |
||

158 | q = output; |
||

159 | while (n >= 4) { |
||

160 | v = p[0]; q[0] = v; q[1] = v; |
||

161 | v = p[1]; q[2] = v; q[3] = v; |
||

162 | v = p[2]; q[4] = v; q[5] = v; |
||

163 | v = p[3]; q[6] = v; q[7] = v; |
||

164 | ```
q += 8;
``` |
||

165 | ```
p += 4;
``` |
||

166 | ```
n -= 4;
``` |
||

167 | } |
||

168 | while (n > 0) { |
||

169 | v = p[0]; q[0] = v; q[1] = v; |
||

170 | ```
q += 2;
``` |
||

171 | ```
p += 1;
``` |
||

172 | n--; |
||

173 | } |
||

174 | } |
||

175 | |||

176 | ```
/* XXX: should use more abstract 'N' channels system */
``` |
||

177 | static void stereo_split(short *output1, short *output2, short *input, int n) |
||

178 | { |
||

179 | ```
int i;
``` |
||

180 | |||

181 | for(i=0;i<n;i++) { |
||

182 | *output1++ = *input++; |
||

183 | *output2++ = *input++; |
||

184 | } |
||

185 | } |
||

186 | |||

187 | static void stereo_mux(short *output, short *input1, short *input2, int n) |
||

188 | { |
||

189 | ```
int i;
``` |
||

190 | |||

191 | for(i=0;i<n;i++) { |
||

192 | *output++ = *input1++; |
||

193 | *output++ = *input2++; |
||

194 | } |
||

195 | } |
||

196 | |||

197 | 743739d2 | Michael Niedermayer | static void ac3_5p1_mux(short *output, short *input1, short *input2, int n) |

198 | { |
||

199 | ```
int i;
``` |
||

200 | ```
short l,r;
``` |
||

201 | |||

202 | for(i=0;i<n;i++) { |
||

203 | l=*input1++; |
||

204 | r=*input2++; |
||

205 | ```
*output++ = l; /* left */
``` |
||

206 | *output++ = (l/2)+(r/2); /* center */ |
||

207 | ```
*output++ = r; /* right */
``` |
||

208 | *output++ = 0; /* left surround */ |
||

209 | *output++ = 0; /* right surroud */ |
||

210 | *output++ = 0; /* low freq */ |
||

211 | } |
||

212 | } |
||

213 | |||

214 | de6d9b64 | Fabrice Bellard | static int mono_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples) |

215 | { |
||

216 | 1a565432 | Fabrice Bellard | ```
short *buf1;
``` |

217 | de6d9b64 | Fabrice Bellard | ```
short *buftmp;
``` |

218 | |||

219 | 6000abfa | Fabrice Bellard | buf1= (short*)av_malloc( nb_samples * sizeof(short) ); |

220 | 1a565432 | Fabrice Bellard | |

221 | de6d9b64 | Fabrice Bellard | ```
/* first downsample by an integer factor with averaging filter */
``` |

222 | if (s->iratio > 1) { |
||

223 | buftmp = buf1; |
||

224 | nb_samples = integer_downsample(s, buftmp, input, nb_samples); |
||

225 | ```
} else {
``` |
||

226 | buftmp = input; |
||

227 | } |
||

228 | |||

229 | ```
/* then do a fractional resampling with linear interpolation */
``` |
||

230 | ```
if (s->incr != FRAC) {
``` |
||

231 | nb_samples = fractional_resample(s, output, buftmp, nb_samples); |
||

232 | ```
} else {
``` |
||

233 | memcpy(output, buftmp, nb_samples * sizeof(short)); |
||

234 | } |
||

235 | 6000abfa | Fabrice Bellard | av_free(buf1); |

236 | de6d9b64 | Fabrice Bellard | ```
return nb_samples;
``` |

237 | } |
||

238 | |||

239 | ReSampleContext *audio_resample_init(int output_channels, int input_channels, |
||

240 | int output_rate, int input_rate) |
||

241 | { |
||

242 | ReSampleContext *s; |
||

243 | ```
int i;
``` |
||

244 | |||

245 | 743739d2 | Michael Niedermayer | if ( input_channels > 2) |

246 | { |
||

247 | ```
printf("Resampling with input channels greater than 2 unsupported.");
``` |
||

248 | return NULL; |
||

249 | } |
||

250 | de6d9b64 | Fabrice Bellard | |

251 | ```
s = av_mallocz(sizeof(ReSampleContext));
``` |
||

252 | ```
if (!s)
``` |
||

253 | 743739d2 | Michael Niedermayer | { |

254 | ```
printf("Can't allocate memory for resample context.");
``` |
||

255 | return NULL; |
||

256 | } |
||

257 | de6d9b64 | Fabrice Bellard | |

258 | s->ratio = (float)output_rate / (float)input_rate; |
||

259 | |||

260 | s->input_channels = input_channels; |
||

261 | s->output_channels = output_channels; |
||

262 | |||

263 | s->filter_channels = s->input_channels; |
||

264 | ```
if (s->output_channels < s->filter_channels)
``` |
||

265 | s->filter_channels = s->output_channels; |
||

266 | |||

267 | 743739d2 | Michael Niedermayer | ```
/*
``` |

268 | ```
* ac3 output is the only case where filter_channels could be greater than 2.
``` |
||

269 | ```
* input channels can't be greater than 2, so resample the 2 channels and then
``` |
||

270 | ```
* expand to 6 channels after the resampling.
``` |
||

271 | ```
*/
``` |
||

272 | if(s->filter_channels>2) |
||

273 | ```
s->filter_channels = 2;
``` |
||

274 | |||

275 | de6d9b64 | Fabrice Bellard | for(i=0;i<s->filter_channels;i++) { |

276 | init_mono_resample(&s->channel_ctx[i], s->ratio); |
||

277 | } |
||

278 | ```
return s;
``` |
||

279 | } |
||

280 | |||

281 | ```
/* resample audio. 'nb_samples' is the number of input samples */
``` |
||

282 | ```
/* XXX: optimize it ! */
``` |
||

283 | ```
/* XXX: do it with polyphase filters, since the quality here is
``` |
||

284 | ```
HORRIBLE. Return the number of samples available in output */
``` |
||

285 | int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples) |
||

286 | { |
||

287 | ```
int i, nb_samples1;
``` |
||

288 | 1a565432 | Fabrice Bellard | short *bufin[2]; |

289 | short *bufout[2]; |
||

290 | de6d9b64 | Fabrice Bellard | short *buftmp2[2], *buftmp3[2]; |

291 | 1a565432 | Fabrice Bellard | ```
int lenout;
``` |

292 | de6d9b64 | Fabrice Bellard | |

293 | if (s->input_channels == s->output_channels && s->ratio == 1.0) { |
||

294 | ```
/* nothing to do */
``` |
||

295 | memcpy(output, input, nb_samples * s->input_channels * sizeof(short)); |
||

296 | ```
return nb_samples;
``` |
||

297 | } |
||

298 | |||

299 | 1a565432 | Fabrice Bellard | ```
/* XXX: move those malloc to resample init code */
``` |

300 | 6000abfa | Fabrice Bellard | bufin[0]= (short*) av_malloc( nb_samples * sizeof(short) ); |

301 | bufin[1]= (short*) av_malloc( nb_samples * sizeof(short) ); |
||

302 | 1a565432 | Fabrice Bellard | |

303 | ```
/* make some zoom to avoid round pb */
``` |
||

304 | lenout= (int)(nb_samples * s->ratio) + 16; |
||

305 | 6000abfa | Fabrice Bellard | bufout[0]= (short*) av_malloc( lenout * sizeof(short) ); |

306 | bufout[1]= (short*) av_malloc( lenout * sizeof(short) ); |
||

307 | 1a565432 | Fabrice Bellard | |

308 | de6d9b64 | Fabrice Bellard | if (s->input_channels == 2 && |

309 | ```
s->output_channels == 1) {
``` |
||

310 | buftmp2[0] = bufin[0]; |
||

311 | ```
buftmp3[0] = output;
``` |
||

312 | ```
stereo_to_mono(buftmp2[0], input, nb_samples);
``` |
||

313 | 743739d2 | Michael Niedermayer | } else if (s->output_channels >= 2 && s->input_channels == 1) { |

314 | de6d9b64 | Fabrice Bellard | ```
buftmp2[0] = input;
``` |

315 | buftmp3[0] = bufout[0]; |
||

316 | 743739d2 | Michael Niedermayer | } else if (s->output_channels >= 2) { |

317 | de6d9b64 | Fabrice Bellard | buftmp2[0] = bufin[0]; |

318 | buftmp2[1] = bufin[1]; |
||

319 | buftmp3[0] = bufout[0]; |
||

320 | buftmp3[1] = bufout[1]; |
||

321 | stereo_split(buftmp2[0], buftmp2[1], input, nb_samples); |
||

322 | ```
} else {
``` |
||

323 | ```
buftmp2[0] = input;
``` |
||

324 | ```
buftmp3[0] = output;
``` |
||

325 | } |
||

326 | |||

327 | ```
/* resample each channel */
``` |
||

328 | nb_samples1 = 0; /* avoid warning */ |
||

329 | for(i=0;i<s->filter_channels;i++) { |
||

330 | nb_samples1 = mono_resample(&s->channel_ctx[i], buftmp3[i], buftmp2[i], nb_samples); |
||

331 | } |
||

332 | |||

333 | if (s->output_channels == 2 && s->input_channels == 1) { |
||

334 | ```
mono_to_stereo(output, buftmp3[0], nb_samples1);
``` |
||

335 | } else if (s->output_channels == 2) { |
||

336 | stereo_mux(output, buftmp3[0], buftmp3[1], nb_samples1); |
||

337 | 743739d2 | Michael Niedermayer | } else if (s->output_channels == 6) { |

338 | ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1); |
||

339 | de6d9b64 | Fabrice Bellard | } |

340 | |||

341 | 6000abfa | Fabrice Bellard | ```
av_free(bufin[0]);
``` |

342 | ```
av_free(bufin[1]);
``` |
||

343 | 1a565432 | Fabrice Bellard | |

344 | 6000abfa | Fabrice Bellard | ```
av_free(bufout[0]);
``` |

345 | ```
av_free(bufout[1]);
``` |
||

346 | de6d9b64 | Fabrice Bellard | ```
return nb_samples1;
``` |

347 | } |
||

348 | |||

349 | ```
void audio_resample_close(ReSampleContext *s)
``` |
||

350 | { |
||

351 | 6000abfa | Fabrice Bellard | av_free(s); |

352 | de6d9b64 | Fabrice Bellard | } |