Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
3 | * | |
4 | * This file is part of FFmpeg. | |
5 | * | |
6 | * FFmpeg is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
10 | * | |
11 | * FFmpeg is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with FFmpeg; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | #include "libavutil/common.h" | |
22 | #include "libavutil/dict.h" | |
23 | // #include "libavutil/error.h" | |
24 | #include "libavutil/frame.h" | |
25 | #include "libavutil/log.h" | |
26 | #include "libavutil/mem.h" | |
27 | #include "libavutil/opt.h" | |
28 | ||
29 | #include "avresample.h" | |
30 | #include "internal.h" | |
31 | #include "audio_data.h" | |
32 | #include "audio_convert.h" | |
33 | #include "audio_mix.h" | |
34 | #include "resample.h" | |
35 | ||
36 | int avresample_open(AVAudioResampleContext *avr) | |
37 | { | |
38 | int ret; | |
39 | ||
40 | if (avresample_is_open(avr)) { | |
41 | av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n"); | |
42 | return AVERROR(EINVAL); | |
43 | } | |
44 | ||
45 | /* set channel mixing parameters */ | |
46 | avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
47 | if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { | |
48 | av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", | |
49 | avr->in_channel_layout); | |
50 | return AVERROR(EINVAL); | |
51 | } | |
52 | avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
53 | if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
54 | av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", | |
55 | avr->out_channel_layout); | |
56 | return AVERROR(EINVAL); | |
57 | } | |
58 | avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); | |
59 | avr->downmix_needed = avr->in_channels > avr->out_channels; | |
60 | avr->upmix_needed = avr->out_channels > avr->in_channels || | |
61 | (!avr->downmix_needed && (avr->mix_matrix || | |
62 | avr->in_channel_layout != avr->out_channel_layout)); | |
63 | avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; | |
64 | ||
65 | /* set resampling parameters */ | |
66 | avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || | |
67 | avr->force_resampling; | |
68 | ||
69 | /* select internal sample format if not specified by the user */ | |
70 | if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && | |
71 | (avr->mixing_needed || avr->resample_needed)) { | |
72 | enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); | |
73 | enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | |
74 | int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), | |
75 | av_get_bytes_per_sample(out_fmt)); | |
76 | if (max_bps <= 2) { | |
77 | avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; | |
78 | } else if (avr->mixing_needed) { | |
79 | avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | |
80 | } else { | |
81 | if (max_bps <= 4) { | |
82 | if (in_fmt == AV_SAMPLE_FMT_S32P || | |
83 | out_fmt == AV_SAMPLE_FMT_S32P) { | |
84 | if (in_fmt == AV_SAMPLE_FMT_FLTP || | |
85 | out_fmt == AV_SAMPLE_FMT_FLTP) { | |
86 | /* if one is s32 and the other is flt, use dbl */ | |
87 | avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; | |
88 | } else { | |
89 | /* if one is s32 and the other is s32, s16, or u8, use s32 */ | |
90 | avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; | |
91 | } | |
92 | } else { | |
93 | /* if one is flt and the other is flt, s16 or u8, use flt */ | |
94 | avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | |
95 | } | |
96 | } else { | |
97 | /* if either is dbl, use dbl */ | |
98 | avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; | |
99 | } | |
100 | } | |
101 | av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", | |
102 | av_get_sample_fmt_name(avr->internal_sample_fmt)); | |
103 | } | |
104 | ||
105 | /* we may need to add an extra conversion in order to remap channels if | |
106 | the output format is not planar */ | |
107 | if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed && | |
108 | !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels)) { | |
109 | avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | |
110 | } | |
111 | ||
112 | /* set sample format conversion parameters */ | |
113 | if (avr->resample_needed || avr->mixing_needed) | |
114 | avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt; | |
115 | else | |
116 | avr->in_convert_needed = avr->use_channel_map && | |
117 | !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels); | |
118 | ||
119 | if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed) | |
120 | avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; | |
121 | else | |
122 | avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; | |
123 | ||
124 | avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed || | |
125 | (avr->use_channel_map && avr->resample_needed)); | |
126 | ||
127 | if (avr->use_channel_map) { | |
128 | if (avr->in_copy_needed) { | |
129 | avr->remap_point = REMAP_IN_COPY; | |
130 | av_dlog(avr, "remap channels during in_copy\n"); | |
131 | } else if (avr->in_convert_needed) { | |
132 | avr->remap_point = REMAP_IN_CONVERT; | |
133 | av_dlog(avr, "remap channels during in_convert\n"); | |
134 | } else if (avr->out_convert_needed) { | |
135 | avr->remap_point = REMAP_OUT_CONVERT; | |
136 | av_dlog(avr, "remap channels during out_convert\n"); | |
137 | } else { | |
138 | avr->remap_point = REMAP_OUT_COPY; | |
139 | av_dlog(avr, "remap channels during out_copy\n"); | |
140 | } | |
141 | ||
142 | #ifdef DEBUG | |
143 | { | |
144 | int ch; | |
145 | av_dlog(avr, "output map: "); | |
146 | if (avr->ch_map_info.do_remap) | |
147 | for (ch = 0; ch < avr->in_channels; ch++) | |
148 | av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]); | |
149 | else | |
150 | av_dlog(avr, "n/a"); | |
151 | av_dlog(avr, "\n"); | |
152 | av_dlog(avr, "copy map: "); | |
153 | if (avr->ch_map_info.do_copy) | |
154 | for (ch = 0; ch < avr->in_channels; ch++) | |
155 | av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]); | |
156 | else | |
157 | av_dlog(avr, "n/a"); | |
158 | av_dlog(avr, "\n"); | |
159 | av_dlog(avr, "zero map: "); | |
160 | if (avr->ch_map_info.do_zero) | |
161 | for (ch = 0; ch < avr->in_channels; ch++) | |
162 | av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]); | |
163 | else | |
164 | av_dlog(avr, "n/a"); | |
165 | av_dlog(avr, "\n"); | |
166 | av_dlog(avr, "input map: "); | |
167 | for (ch = 0; ch < avr->in_channels; ch++) | |
168 | av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]); | |
169 | av_dlog(avr, "\n"); | |
170 | } | |
171 | #endif | |
172 | } else | |
173 | avr->remap_point = REMAP_NONE; | |
174 | ||
175 | /* allocate buffers */ | |
176 | if (avr->in_copy_needed || avr->in_convert_needed) { | |
177 | avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), | |
178 | 0, avr->internal_sample_fmt, | |
179 | "in_buffer"); | |
180 | if (!avr->in_buffer) { | |
181 | ret = AVERROR(EINVAL); | |
182 | goto error; | |
183 | } | |
184 | } | |
185 | if (avr->resample_needed) { | |
186 | avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, | |
187 | 1024, avr->internal_sample_fmt, | |
188 | "resample_out_buffer"); | |
189 | if (!avr->resample_out_buffer) { | |
190 | ret = AVERROR(EINVAL); | |
191 | goto error; | |
192 | } | |
193 | } | |
194 | if (avr->out_convert_needed) { | |
195 | avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, | |
196 | avr->out_sample_fmt, "out_buffer"); | |
197 | if (!avr->out_buffer) { | |
198 | ret = AVERROR(EINVAL); | |
199 | goto error; | |
200 | } | |
201 | } | |
202 | avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, | |
203 | 1024); | |
204 | if (!avr->out_fifo) { | |
205 | ret = AVERROR(ENOMEM); | |
206 | goto error; | |
207 | } | |
208 | ||
209 | /* setup contexts */ | |
210 | if (avr->in_convert_needed) { | |
211 | avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, | |
212 | avr->in_sample_fmt, avr->in_channels, | |
213 | avr->in_sample_rate, | |
214 | avr->remap_point == REMAP_IN_CONVERT); | |
215 | if (!avr->ac_in) { | |
216 | ret = AVERROR(ENOMEM); | |
217 | goto error; | |
218 | } | |
219 | } | |
220 | if (avr->out_convert_needed) { | |
221 | enum AVSampleFormat src_fmt; | |
222 | if (avr->in_convert_needed) | |
223 | src_fmt = avr->internal_sample_fmt; | |
224 | else | |
225 | src_fmt = avr->in_sample_fmt; | |
226 | avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, | |
227 | avr->out_channels, | |
228 | avr->out_sample_rate, | |
229 | avr->remap_point == REMAP_OUT_CONVERT); | |
230 | if (!avr->ac_out) { | |
231 | ret = AVERROR(ENOMEM); | |
232 | goto error; | |
233 | } | |
234 | } | |
235 | if (avr->resample_needed) { | |
236 | avr->resample = ff_audio_resample_init(avr); | |
237 | if (!avr->resample) { | |
238 | ret = AVERROR(ENOMEM); | |
239 | goto error; | |
240 | } | |
241 | } | |
242 | if (avr->mixing_needed) { | |
243 | avr->am = ff_audio_mix_alloc(avr); | |
244 | if (!avr->am) { | |
245 | ret = AVERROR(ENOMEM); | |
246 | goto error; | |
247 | } | |
248 | } | |
249 | ||
250 | return 0; | |
251 | ||
252 | error: | |
253 | avresample_close(avr); | |
254 | return ret; | |
255 | } | |
256 | ||
257 | int avresample_is_open(AVAudioResampleContext *avr) | |
258 | { | |
259 | return !!avr->out_fifo; | |
260 | } | |
261 | ||
262 | void avresample_close(AVAudioResampleContext *avr) | |
263 | { | |
264 | ff_audio_data_free(&avr->in_buffer); | |
265 | ff_audio_data_free(&avr->resample_out_buffer); | |
266 | ff_audio_data_free(&avr->out_buffer); | |
267 | av_audio_fifo_free(avr->out_fifo); | |
268 | avr->out_fifo = NULL; | |
269 | ff_audio_convert_free(&avr->ac_in); | |
270 | ff_audio_convert_free(&avr->ac_out); | |
271 | ff_audio_resample_free(&avr->resample); | |
272 | ff_audio_mix_free(&avr->am); | |
273 | av_freep(&avr->mix_matrix); | |
274 | ||
275 | avr->use_channel_map = 0; | |
276 | } | |
277 | ||
278 | void avresample_free(AVAudioResampleContext **avr) | |
279 | { | |
280 | if (!*avr) | |
281 | return; | |
282 | avresample_close(*avr); | |
283 | av_opt_free(*avr); | |
284 | av_freep(avr); | |
285 | } | |
286 | ||
287 | static int handle_buffered_output(AVAudioResampleContext *avr, | |
288 | AudioData *output, AudioData *converted) | |
289 | { | |
290 | int ret; | |
291 | ||
292 | if (!output || av_audio_fifo_size(avr->out_fifo) > 0 || | |
293 | (converted && output->allocated_samples < converted->nb_samples)) { | |
294 | if (converted) { | |
295 | /* if there are any samples in the output FIFO or if the | |
296 | user-supplied output buffer is not large enough for all samples, | |
297 | we add to the output FIFO */ | |
298 | av_dlog(avr, "[FIFO] add %s to out_fifo\n", converted->name); | |
299 | ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0, | |
300 | converted->nb_samples); | |
301 | if (ret < 0) | |
302 | return ret; | |
303 | } | |
304 | ||
305 | /* if the user specified an output buffer, read samples from the output | |
306 | FIFO to the user output */ | |
307 | if (output && output->allocated_samples > 0) { | |
308 | av_dlog(avr, "[FIFO] read from out_fifo to output\n"); | |
309 | av_dlog(avr, "[end conversion]\n"); | |
310 | return ff_audio_data_read_from_fifo(avr->out_fifo, output, | |
311 | output->allocated_samples); | |
312 | } | |
313 | } else if (converted) { | |
314 | /* copy directly to output if it is large enough or there is not any | |
315 | data in the output FIFO */ | |
316 | av_dlog(avr, "[copy] %s to output\n", converted->name); | |
317 | output->nb_samples = 0; | |
318 | ret = ff_audio_data_copy(output, converted, | |
319 | avr->remap_point == REMAP_OUT_COPY ? | |
320 | &avr->ch_map_info : NULL); | |
321 | if (ret < 0) | |
322 | return ret; | |
323 | av_dlog(avr, "[end conversion]\n"); | |
324 | return output->nb_samples; | |
325 | } | |
326 | av_dlog(avr, "[end conversion]\n"); | |
327 | return 0; | |
328 | } | |
329 | ||
330 | int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, | |
331 | uint8_t **output, int out_plane_size, | |
332 | int out_samples, uint8_t **input, | |
333 | int in_plane_size, int in_samples) | |
334 | { | |
335 | AudioData input_buffer; | |
336 | AudioData output_buffer; | |
337 | AudioData *current_buffer; | |
338 | int ret, direct_output; | |
339 | ||
340 | /* reset internal buffers */ | |
341 | if (avr->in_buffer) { | |
342 | avr->in_buffer->nb_samples = 0; | |
343 | ff_audio_data_set_channels(avr->in_buffer, | |
344 | avr->in_buffer->allocated_channels); | |
345 | } | |
346 | if (avr->resample_out_buffer) { | |
347 | avr->resample_out_buffer->nb_samples = 0; | |
348 | ff_audio_data_set_channels(avr->resample_out_buffer, | |
349 | avr->resample_out_buffer->allocated_channels); | |
350 | } | |
351 | if (avr->out_buffer) { | |
352 | avr->out_buffer->nb_samples = 0; | |
353 | ff_audio_data_set_channels(avr->out_buffer, | |
354 | avr->out_buffer->allocated_channels); | |
355 | } | |
356 | ||
357 | av_dlog(avr, "[start conversion]\n"); | |
358 | ||
359 | /* initialize output_buffer with output data */ | |
360 | direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0; | |
361 | if (output) { | |
362 | ret = ff_audio_data_init(&output_buffer, output, out_plane_size, | |
363 | avr->out_channels, out_samples, | |
364 | avr->out_sample_fmt, 0, "output"); | |
365 | if (ret < 0) | |
366 | return ret; | |
367 | output_buffer.nb_samples = 0; | |
368 | } | |
369 | ||
370 | if (input) { | |
371 | /* initialize input_buffer with input data */ | |
372 | ret = ff_audio_data_init(&input_buffer, input, in_plane_size, | |
373 | avr->in_channels, in_samples, | |
374 | avr->in_sample_fmt, 1, "input"); | |
375 | if (ret < 0) | |
376 | return ret; | |
377 | current_buffer = &input_buffer; | |
378 | ||
379 | if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed && | |
380 | !avr->out_convert_needed && direct_output && out_samples >= in_samples) { | |
381 | /* in some rare cases we can copy input to output and upmix | |
382 | directly in the output buffer */ | |
383 | av_dlog(avr, "[copy] %s to output\n", current_buffer->name); | |
384 | ret = ff_audio_data_copy(&output_buffer, current_buffer, | |
385 | avr->remap_point == REMAP_OUT_COPY ? | |
386 | &avr->ch_map_info : NULL); | |
387 | if (ret < 0) | |
388 | return ret; | |
389 | current_buffer = &output_buffer; | |
390 | } else if (avr->remap_point == REMAP_OUT_COPY && | |
391 | (!direct_output || out_samples < in_samples)) { | |
392 | /* if remapping channels during output copy, we may need to | |
393 | * use an intermediate buffer in order to remap before adding | |
394 | * samples to the output fifo */ | |
395 | av_dlog(avr, "[copy] %s to out_buffer\n", current_buffer->name); | |
396 | ret = ff_audio_data_copy(avr->out_buffer, current_buffer, | |
397 | &avr->ch_map_info); | |
398 | if (ret < 0) | |
399 | return ret; | |
400 | current_buffer = avr->out_buffer; | |
401 | } else if (avr->in_copy_needed || avr->in_convert_needed) { | |
402 | /* if needed, copy or convert input to in_buffer, and downmix if | |
403 | applicable */ | |
404 | if (avr->in_convert_needed) { | |
405 | ret = ff_audio_data_realloc(avr->in_buffer, | |
406 | current_buffer->nb_samples); | |
407 | if (ret < 0) | |
408 | return ret; | |
409 | av_dlog(avr, "[convert] %s to in_buffer\n", current_buffer->name); | |
410 | ret = ff_audio_convert(avr->ac_in, avr->in_buffer, | |
411 | current_buffer); | |
412 | if (ret < 0) | |
413 | return ret; | |
414 | } else { | |
415 | av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name); | |
416 | ret = ff_audio_data_copy(avr->in_buffer, current_buffer, | |
417 | avr->remap_point == REMAP_IN_COPY ? | |
418 | &avr->ch_map_info : NULL); | |
419 | if (ret < 0) | |
420 | return ret; | |
421 | } | |
422 | ff_audio_data_set_channels(avr->in_buffer, avr->in_channels); | |
423 | if (avr->downmix_needed) { | |
424 | av_dlog(avr, "[downmix] in_buffer\n"); | |
425 | ret = ff_audio_mix(avr->am, avr->in_buffer); | |
426 | if (ret < 0) | |
427 | return ret; | |
428 | } | |
429 | current_buffer = avr->in_buffer; | |
430 | } | |
431 | } else { | |
432 | /* flush resampling buffer and/or output FIFO if input is NULL */ | |
433 | if (!avr->resample_needed) | |
434 | return handle_buffered_output(avr, output ? &output_buffer : NULL, | |
435 | NULL); | |
436 | current_buffer = NULL; | |
437 | } | |
438 | ||
439 | if (avr->resample_needed) { | |
440 | AudioData *resample_out; | |
441 | ||
442 | if (!avr->out_convert_needed && direct_output && out_samples > 0) | |
443 | resample_out = &output_buffer; | |
444 | else | |
445 | resample_out = avr->resample_out_buffer; | |
446 | av_dlog(avr, "[resample] %s to %s\n", | |
447 | current_buffer ? current_buffer->name : "null", | |
448 | resample_out->name); | |
449 | ret = ff_audio_resample(avr->resample, resample_out, | |
450 | current_buffer); | |
451 | if (ret < 0) | |
452 | return ret; | |
453 | ||
454 | /* if resampling did not produce any samples, just return 0 */ | |
455 | if (resample_out->nb_samples == 0) { | |
456 | av_dlog(avr, "[end conversion]\n"); | |
457 | return 0; | |
458 | } | |
459 | ||
460 | current_buffer = resample_out; | |
461 | } | |
462 | ||
463 | if (avr->upmix_needed) { | |
464 | av_dlog(avr, "[upmix] %s\n", current_buffer->name); | |
465 | ret = ff_audio_mix(avr->am, current_buffer); | |
466 | if (ret < 0) | |
467 | return ret; | |
468 | } | |
469 | ||
470 | /* if we resampled or upmixed directly to output, return here */ | |
471 | if (current_buffer == &output_buffer) { | |
472 | av_dlog(avr, "[end conversion]\n"); | |
473 | return current_buffer->nb_samples; | |
474 | } | |
475 | ||
476 | if (avr->out_convert_needed) { | |
477 | if (direct_output && out_samples >= current_buffer->nb_samples) { | |
478 | /* convert directly to output */ | |
479 | av_dlog(avr, "[convert] %s to output\n", current_buffer->name); | |
480 | ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer); | |
481 | if (ret < 0) | |
482 | return ret; | |
483 | ||
484 | av_dlog(avr, "[end conversion]\n"); | |
485 | return output_buffer.nb_samples; | |
486 | } else { | |
487 | ret = ff_audio_data_realloc(avr->out_buffer, | |
488 | current_buffer->nb_samples); | |
489 | if (ret < 0) | |
490 | return ret; | |
491 | av_dlog(avr, "[convert] %s to out_buffer\n", current_buffer->name); | |
492 | ret = ff_audio_convert(avr->ac_out, avr->out_buffer, | |
493 | current_buffer); | |
494 | if (ret < 0) | |
495 | return ret; | |
496 | current_buffer = avr->out_buffer; | |
497 | } | |
498 | } | |
499 | ||
500 | return handle_buffered_output(avr, output ? &output_buffer : NULL, | |
501 | current_buffer); | |
502 | } | |
503 | ||
504 | int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in) | |
505 | { | |
506 | if (avresample_is_open(avr)) { | |
507 | avresample_close(avr); | |
508 | } | |
509 | ||
510 | if (in) { | |
511 | avr->in_channel_layout = in->channel_layout; | |
512 | avr->in_sample_rate = in->sample_rate; | |
513 | avr->in_sample_fmt = in->format; | |
514 | } | |
515 | ||
516 | if (out) { | |
517 | avr->out_channel_layout = out->channel_layout; | |
518 | avr->out_sample_rate = out->sample_rate; | |
519 | avr->out_sample_fmt = out->format; | |
520 | } | |
521 | ||
522 | return 0; | |
523 | } | |
524 | ||
525 | static int config_changed(AVAudioResampleContext *avr, | |
526 | AVFrame *out, AVFrame *in) | |
527 | { | |
528 | int ret = 0; | |
529 | ||
530 | if (in) { | |
531 | if (avr->in_channel_layout != in->channel_layout || | |
532 | avr->in_sample_rate != in->sample_rate || | |
533 | avr->in_sample_fmt != in->format) { | |
534 | ret |= AVERROR_INPUT_CHANGED; | |
535 | } | |
536 | } | |
537 | ||
538 | if (out) { | |
539 | if (avr->out_channel_layout != out->channel_layout || | |
540 | avr->out_sample_rate != out->sample_rate || | |
541 | avr->out_sample_fmt != out->format) { | |
542 | ret |= AVERROR_OUTPUT_CHANGED; | |
543 | } | |
544 | } | |
545 | ||
546 | return ret; | |
547 | } | |
548 | ||
549 | static inline int convert_frame(AVAudioResampleContext *avr, | |
550 | AVFrame *out, AVFrame *in) | |
551 | { | |
552 | int ret; | |
553 | uint8_t **out_data = NULL, **in_data = NULL; | |
554 | int out_linesize = 0, in_linesize = 0; | |
555 | int out_nb_samples = 0, in_nb_samples = 0; | |
556 | ||
557 | if (out) { | |
558 | out_data = out->extended_data; | |
559 | out_linesize = out->linesize[0]; | |
560 | out_nb_samples = out->nb_samples; | |
561 | } | |
562 | ||
563 | if (in) { | |
564 | in_data = in->extended_data; | |
565 | in_linesize = in->linesize[0]; | |
566 | in_nb_samples = in->nb_samples; | |
567 | } | |
568 | ||
569 | ret = avresample_convert(avr, out_data, out_linesize, | |
570 | out_nb_samples, | |
571 | in_data, in_linesize, | |
572 | in_nb_samples); | |
573 | ||
574 | if (ret < 0) { | |
575 | if (out) | |
576 | out->nb_samples = 0; | |
577 | return ret; | |
578 | } | |
579 | ||
580 | if (out) | |
581 | out->nb_samples = ret; | |
582 | ||
583 | return 0; | |
584 | } | |
585 | ||
586 | static inline int available_samples(AVFrame *out) | |
587 | { | |
f6fa7814 | 588 | int samples; |
2ba45a60 | 589 | int bytes_per_sample = av_get_bytes_per_sample(out->format); |
f6fa7814 DM |
590 | if (!bytes_per_sample) |
591 | return AVERROR(EINVAL); | |
2ba45a60 | 592 | |
f6fa7814 | 593 | samples = out->linesize[0] / bytes_per_sample; |
2ba45a60 DM |
594 | if (av_sample_fmt_is_planar(out->format)) { |
595 | return samples; | |
596 | } else { | |
597 | int channels = av_get_channel_layout_nb_channels(out->channel_layout); | |
598 | return samples / channels; | |
599 | } | |
600 | } | |
601 | ||
602 | int avresample_convert_frame(AVAudioResampleContext *avr, | |
603 | AVFrame *out, AVFrame *in) | |
604 | { | |
605 | int ret, setup = 0; | |
606 | ||
607 | if (!avresample_is_open(avr)) { | |
608 | if ((ret = avresample_config(avr, out, in)) < 0) | |
609 | return ret; | |
610 | if ((ret = avresample_open(avr)) < 0) | |
611 | return ret; | |
612 | setup = 1; | |
613 | } else { | |
614 | // return as is or reconfigure for input changes? | |
615 | if ((ret = config_changed(avr, out, in))) | |
616 | return ret; | |
617 | } | |
618 | ||
619 | if (out) { | |
620 | if (!out->linesize[0]) { | |
621 | out->nb_samples = avresample_get_out_samples(avr, in->nb_samples); | |
622 | if ((ret = av_frame_get_buffer(out, 0)) < 0) { | |
623 | if (setup) | |
624 | avresample_close(avr); | |
625 | return ret; | |
626 | } | |
627 | } else { | |
628 | if (!out->nb_samples) | |
629 | out->nb_samples = available_samples(out); | |
630 | } | |
631 | } | |
632 | ||
633 | return convert_frame(avr, out, in); | |
634 | } | |
635 | ||
636 | int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | |
637 | int stride) | |
638 | { | |
639 | int in_channels, out_channels, i, o; | |
640 | ||
641 | if (avr->am) | |
642 | return ff_audio_mix_get_matrix(avr->am, matrix, stride); | |
643 | ||
644 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
645 | out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
646 | ||
647 | if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | |
648 | out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
649 | av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | |
650 | return AVERROR(EINVAL); | |
651 | } | |
652 | ||
653 | if (!avr->mix_matrix) { | |
654 | av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | |
655 | return AVERROR(EINVAL); | |
656 | } | |
657 | ||
658 | for (o = 0; o < out_channels; o++) | |
659 | for (i = 0; i < in_channels; i++) | |
660 | matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i]; | |
661 | ||
662 | return 0; | |
663 | } | |
664 | ||
665 | int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | |
666 | int stride) | |
667 | { | |
668 | int in_channels, out_channels, i, o; | |
669 | ||
670 | if (avr->am) | |
671 | return ff_audio_mix_set_matrix(avr->am, matrix, stride); | |
672 | ||
673 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
674 | out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
675 | ||
676 | if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | |
677 | out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
678 | av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | |
679 | return AVERROR(EINVAL); | |
680 | } | |
681 | ||
682 | if (avr->mix_matrix) | |
683 | av_freep(&avr->mix_matrix); | |
684 | avr->mix_matrix = av_malloc(in_channels * out_channels * | |
685 | sizeof(*avr->mix_matrix)); | |
686 | if (!avr->mix_matrix) | |
687 | return AVERROR(ENOMEM); | |
688 | ||
689 | for (o = 0; o < out_channels; o++) | |
690 | for (i = 0; i < in_channels; i++) | |
691 | avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i]; | |
692 | ||
693 | return 0; | |
694 | } | |
695 | ||
696 | int avresample_set_channel_mapping(AVAudioResampleContext *avr, | |
697 | const int *channel_map) | |
698 | { | |
699 | ChannelMapInfo *info = &avr->ch_map_info; | |
700 | int in_channels, ch, i; | |
701 | ||
702 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
703 | if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) { | |
704 | av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n"); | |
705 | return AVERROR(EINVAL); | |
706 | } | |
707 | ||
708 | memset(info, 0, sizeof(*info)); | |
709 | memset(info->input_map, -1, sizeof(info->input_map)); | |
710 | ||
711 | for (ch = 0; ch < in_channels; ch++) { | |
712 | if (channel_map[ch] >= in_channels) { | |
713 | av_log(avr, AV_LOG_ERROR, "Invalid channel map\n"); | |
714 | return AVERROR(EINVAL); | |
715 | } | |
716 | if (channel_map[ch] < 0) { | |
717 | info->channel_zero[ch] = 1; | |
718 | info->channel_map[ch] = -1; | |
719 | info->do_zero = 1; | |
720 | } else if (info->input_map[channel_map[ch]] >= 0) { | |
721 | info->channel_copy[ch] = info->input_map[channel_map[ch]]; | |
722 | info->channel_map[ch] = -1; | |
723 | info->do_copy = 1; | |
724 | } else { | |
725 | info->channel_map[ch] = channel_map[ch]; | |
726 | info->input_map[channel_map[ch]] = ch; | |
727 | info->do_remap = 1; | |
728 | } | |
729 | } | |
730 | /* Fill-in unmapped input channels with unmapped output channels. | |
731 | This is used when remapping during conversion from interleaved to | |
732 | planar format. */ | |
733 | for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) { | |
734 | while (ch < in_channels && info->input_map[ch] >= 0) | |
735 | ch++; | |
736 | while (i < in_channels && info->channel_map[i] >= 0) | |
737 | i++; | |
738 | if (ch >= in_channels || i >= in_channels) | |
739 | break; | |
740 | info->input_map[ch] = i; | |
741 | } | |
742 | ||
743 | avr->use_channel_map = 1; | |
744 | return 0; | |
745 | } | |
746 | ||
747 | int avresample_available(AVAudioResampleContext *avr) | |
748 | { | |
749 | return av_audio_fifo_size(avr->out_fifo); | |
750 | } | |
751 | ||
752 | int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples) | |
753 | { | |
754 | int64_t samples = avresample_get_delay(avr) + (int64_t)in_nb_samples; | |
755 | ||
756 | if (avr->resample_needed) { | |
757 | samples = av_rescale_rnd(samples, | |
758 | avr->out_sample_rate, | |
759 | avr->in_sample_rate, | |
760 | AV_ROUND_UP); | |
761 | } | |
762 | ||
763 | samples += avresample_available(avr); | |
764 | ||
765 | if (samples > INT_MAX) | |
766 | return AVERROR(EINVAL); | |
767 | ||
768 | return samples; | |
769 | } | |
770 | ||
771 | int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples) | |
772 | { | |
773 | if (!output) | |
774 | return av_audio_fifo_drain(avr->out_fifo, nb_samples); | |
775 | return av_audio_fifo_read(avr->out_fifo, (void**)output, nb_samples); | |
776 | } | |
777 | ||
778 | unsigned avresample_version(void) | |
779 | { | |
780 | return LIBAVRESAMPLE_VERSION_INT; | |
781 | } | |
782 | ||
783 | const char *avresample_license(void) | |
784 | { | |
785 | #define LICENSE_PREFIX "libavresample license: " | |
786 | return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; | |
787 | } | |
788 | ||
789 | const char *avresample_configuration(void) | |
790 | { | |
791 | return FFMPEG_CONFIGURATION; | |
792 | } |