FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_aresample.c
Date: 2025-03-08 20:38:41
Exec Total Coverage
Lines: 173 203 85.2%
Functions: 9 10 90.0%
Branches: 65 93 69.9%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2011 Stefano Sabatini
3 * Copyright (c) 2011 Mina Nagy Zaki
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * resampling audio filter
25 */
26
27 #include "libavutil/avstring.h"
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/downmix_info.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/samplefmt.h"
32 #include "libavutil/avassert.h"
33 #include "libswresample/swresample.h"
34 #include "avfilter.h"
35 #include "audio.h"
36 #include "filters.h"
37 #include "formats.h"
38
39 typedef struct AResampleContext {
40 const AVClass *class;
41 int sample_rate_arg;
42 double ratio;
43 struct SwrContext *swr;
44 int64_t next_pts;
45 int more_data;
46 int eof;
47 } AResampleContext;
48
49 2338 static av_cold int preinit(AVFilterContext *ctx)
50 {
51 2338 AResampleContext *aresample = ctx->priv;
52
53 2338 aresample->next_pts = AV_NOPTS_VALUE;
54 2338 aresample->swr = swr_alloc();
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2338 times.
2338 if (!aresample->swr)
56 return AVERROR(ENOMEM);
57
58 2338 return 0;
59 }
60
61 2338 static av_cold void uninit(AVFilterContext *ctx)
62 {
63 2338 AResampleContext *aresample = ctx->priv;
64 2338 swr_free(&aresample->swr);
65 2338 }
66
67 1484 static int query_formats(const AVFilterContext *ctx,
68 AVFilterFormatsConfig **cfg_in,
69 AVFilterFormatsConfig **cfg_out)
70 {
71 1484 const AResampleContext *aresample = ctx->priv;
72 enum AVSampleFormat out_format;
73 1484 AVChannelLayout out_layout = { 0 };
74 int64_t out_rate;
75
76 AVFilterFormats *in_formats, *out_formats;
77 AVFilterFormats *in_samplerates, *out_samplerates;
78 AVFilterChannelLayouts *in_layouts, *out_layouts;
79 int ret;
80
81
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 845 times.
1484 if (aresample->sample_rate_arg > 0)
82 639 av_opt_set_int(aresample->swr, "osr", aresample->sample_rate_arg, 0);
83 1484 av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
84 1484 av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
85
86 1484 in_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
87
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if ((ret = ff_formats_ref(in_formats, &cfg_in[0]->formats)) < 0)
88 return ret;
89
90 1484 in_samplerates = ff_all_samplerates();
91
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if ((ret = ff_formats_ref(in_samplerates, &cfg_in[0]->samplerates)) < 0)
92 return ret;
93
94 1484 in_layouts = ff_all_channel_counts();
95
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if ((ret = ff_channel_layouts_ref(in_layouts, &cfg_in[0]->channel_layouts)) < 0)
96 return ret;
97
98
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 845 times.
1484 if(out_rate > 0) {
99 639 int ratelist[] = { out_rate, -1 };
100 639 out_samplerates = ff_make_format_list(ratelist);
101 } else {
102 845 out_samplerates = ff_all_samplerates();
103 }
104
105
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if ((ret = ff_formats_ref(out_samplerates, &cfg_out[0]->samplerates)) < 0)
106 return ret;
107
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1484 times.
1484 if(out_format != AV_SAMPLE_FMT_NONE) {
109 int formatlist[] = { out_format, -1 };
110 out_formats = ff_make_format_list(formatlist);
111 } else
112 1484 out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if ((ret = ff_formats_ref(out_formats, &cfg_out[0]->formats)) < 0)
114 return ret;
115
116 1484 av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
117
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 if (av_channel_layout_check(&out_layout)) {
118 const AVChannelLayout layout_list[] = { out_layout, { 0 } };
119 out_layouts = ff_make_channel_layout_list(layout_list);
120 } else
121 1484 out_layouts = ff_all_channel_counts();
122 1484 av_channel_layout_uninit(&out_layout);
123
124 1484 return ff_channel_layouts_ref(out_layouts, &cfg_out[0]->channel_layouts);
125 }
126
127 #define SWR_CH_MAX 64
128
129 1484 static int config_output(AVFilterLink *outlink)
130 {
131 int ret;
132 1484 AVFilterContext *ctx = outlink->src;
133 1484 AVFilterLink *inlink = ctx->inputs[0];
134 1484 AResampleContext *aresample = ctx->priv;
135 1484 AVChannelLayout out_layout = { 0 };
136 int64_t out_rate;
137 const AVFrameSideData *sd;
138 enum AVSampleFormat out_format;
139 char inchl_buf[128], outchl_buf[128];
140
141 1484 ret = swr_alloc_set_opts2(&aresample->swr,
142 1484 &outlink->ch_layout, outlink->format, outlink->sample_rate,
143 1484 &inlink->ch_layout, inlink->format, inlink->sample_rate,
144 0, ctx);
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1484 times.
1484 if (ret < 0)
146 return ret;
147
148 1484 sd = av_frame_side_data_get(inlink->side_data, inlink->nb_side_data,
149 AV_FRAME_DATA_DOWNMIX_INFO);
150
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1479 times.
1484 if (sd) {
151 5 const AVDownmixInfo *di = (AVDownmixInfo *)sd->data;
152 5 enum AVMatrixEncoding matrix_encoding = AV_MATRIX_ENCODING_NONE;
153 double center_mix_level, surround_mix_level;
154
155
3/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
5 switch (di->preferred_downmix_type) {
156 1 case AV_DOWNMIX_TYPE_LTRT:
157 1 matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
158 1 center_mix_level = di->center_mix_level_ltrt;
159 1 surround_mix_level = di->surround_mix_level_ltrt;
160 1 break;
161 1 case AV_DOWNMIX_TYPE_DPLII:
162 1 matrix_encoding = AV_MATRIX_ENCODING_DPLII;
163 1 center_mix_level = di->center_mix_level_ltrt;
164 1 surround_mix_level = di->surround_mix_level_ltrt;
165 1 break;
166 3 default:
167 3 center_mix_level = di->center_mix_level;
168 3 surround_mix_level = di->surround_mix_level;
169 3 break;
170 }
171
172 5 av_log(ctx, AV_LOG_VERBOSE, "Mix levels: center %f - "
173 "surround %f - lfe %f.\n",
174 5 center_mix_level, surround_mix_level, di->lfe_mix_level);
175
176 5 av_opt_set_double(aresample->swr, "clev", center_mix_level, 0);
177 5 av_opt_set_double(aresample->swr, "slev", surround_mix_level, 0);
178 5 av_opt_set_double(aresample->swr, "lfe_mix_level", di->lfe_mix_level, 0);
179 5 av_opt_set_int(aresample->swr, "matrix_encoding", matrix_encoding, 0);
180
181
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (av_channel_layout_compare(&outlink->ch_layout, &out_layout))
182 5 av_frame_side_data_remove(&outlink->side_data, &outlink->nb_side_data,
183 AV_FRAME_DATA_DOWNMIX_INFO);
184 }
185
186 1484 ret = swr_init(aresample->swr);
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1484 times.
1484 if (ret < 0)
188 return ret;
189
190 1484 av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
191 1484 av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
192 1484 av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
193 1484 outlink->time_base = (AVRational) {1, out_rate};
194
195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1484 times.
1484 av_assert0(outlink->sample_rate == out_rate);
196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1484 times.
1484 av_assert0(!av_channel_layout_compare(&outlink->ch_layout, &out_layout));
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1484 times.
1484 av_assert0(outlink->format == out_format);
198
199 1484 av_channel_layout_uninit(&out_layout);
200
201 1484 aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
202
203 1484 av_channel_layout_describe(&inlink ->ch_layout, inchl_buf, sizeof(inchl_buf));
204 1484 av_channel_layout_describe(&outlink->ch_layout, outchl_buf, sizeof(outchl_buf));
205
206 1484 av_log(ctx, AV_LOG_VERBOSE, "ch:%d chl:%s fmt:%s r:%dHz -> ch:%d chl:%s fmt:%s r:%dHz\n",
207 1484 inlink ->ch_layout.nb_channels, inchl_buf, av_get_sample_fmt_name(inlink->format), inlink->sample_rate,
208 1484 outlink->ch_layout.nb_channels, outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
209 1484 return 0;
210 }
211
212 212986 static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
213 {
214 212986 AVFilterContext *ctx = inlink->dst;
215 212986 AResampleContext *aresample = ctx->priv;
216 212986 const int n_in = insamplesref->nb_samples;
217 int64_t delay;
218 212986 int n_out = n_in * aresample->ratio + 32;
219 212986 AVFilterLink *const outlink = inlink->dst->outputs[0];
220 AVFrame *outsamplesref;
221 int ret;
222
223 212986 delay = swr_get_delay(aresample->swr, outlink->sample_rate);
224
2/2
✓ Branch 0 taken 7740 times.
✓ Branch 1 taken 205246 times.
212986 if (delay > 0)
225 7740 n_out += FFMIN(delay, FFMAX(4096, n_out));
226
227 212986 outsamplesref = ff_get_audio_buffer(outlink, n_out);
228
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212986 times.
212986 if(!outsamplesref) {
230 av_frame_free(&insamplesref);
231 return AVERROR(ENOMEM);
232 }
233
234 212986 av_frame_copy_props(outsamplesref, insamplesref);
235 212986 outsamplesref->format = outlink->format;
236 212986 ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout);
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212986 times.
212986 if (ret < 0) {
238 av_frame_free(&outsamplesref);
239 av_frame_free(&insamplesref);
240 return ret;
241 }
242 212986 outsamplesref->sample_rate = outlink->sample_rate;
243
244
2/2
✓ Branch 1 taken 531 times.
✓ Branch 2 taken 212455 times.
212986 if (av_channel_layout_compare(&outsamplesref->ch_layout, &insamplesref->ch_layout))
245 531 av_frame_side_data_remove_by_props(&outsamplesref->side_data, &outsamplesref->nb_side_data,
246 AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT);
247
248
1/2
✓ Branch 0 taken 212986 times.
✗ Branch 1 not taken.
212986 if(insamplesref->pts != AV_NOPTS_VALUE) {
249 212986 int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den);
250 212986 int64_t outpts= swr_next_pts(aresample->swr, inpts);
251 212986 aresample->next_pts =
252
2/2
✓ Branch 0 taken 212984 times.
✓ Branch 1 taken 2 times.
212986 outsamplesref->pts = ROUNDED_DIV(outpts, inlink->sample_rate);
253 } else {
254 outsamplesref->pts = AV_NOPTS_VALUE;
255 }
256 212986 n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out,
257 212986 (void *)insamplesref->extended_data, n_in);
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212986 times.
212986 if (n_out <= 0) {
259 av_frame_free(&outsamplesref);
260 av_frame_free(&insamplesref);
261 ff_inlink_request_frame(inlink);
262 return 0;
263 }
264
265 212986 aresample->more_data = outsamplesref->nb_samples == n_out; // Indicate that there is probably more data in our buffers
266
267 212986 outsamplesref->nb_samples = n_out;
268
269 212986 ret = ff_filter_frame(outlink, outsamplesref);
270 212986 av_frame_free(&insamplesref);
271 212986 return ret;
272 }
273
274 2035 static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret)
275 {
276 2035 AVFilterContext *ctx = outlink->src;
277 2035 AResampleContext *aresample = ctx->priv;
278 2035 AVFilterLink *const inlink = outlink->src->inputs[0];
279 AVFrame *outsamplesref;
280 2035 int n_out = 4096;
281 int64_t pts;
282
283 2035 outsamplesref = ff_get_audio_buffer(outlink, n_out);
284 2035 *outsamplesref_ret = outsamplesref;
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2035 times.
2035 if (!outsamplesref)
286 return AVERROR(ENOMEM);
287
288 2035 pts = swr_next_pts(aresample->swr, INT64_MIN);
289
1/2
✓ Branch 0 taken 2035 times.
✗ Branch 1 not taken.
2035 pts = ROUNDED_DIV(pts, inlink->sample_rate);
290
291
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 1908 times.
2035 n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0);
292
2/2
✓ Branch 0 taken 1277 times.
✓ Branch 1 taken 758 times.
2035 if (n_out <= 0) {
293 1277 av_frame_free(&outsamplesref);
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1277 times.
1277 return (n_out == 0) ? AVERROR_EOF : n_out;
295 }
296
297 758 outsamplesref->sample_rate = outlink->sample_rate;
298 758 outsamplesref->nb_samples = n_out;
299
300 758 outsamplesref->pts = pts;
301
302 758 return 0;
303 }
304
305 213995 static int request_frame(AVFilterLink *outlink)
306 {
307 213995 AVFilterContext *ctx = outlink->src;
308 213995 AVFilterLink *inlink = ctx->inputs[0];
309 213995 AResampleContext *aresample = ctx->priv;
310 213995 int ret = 0, status;
311 int64_t pts;
312
313 // First try to get data from the internal buffers
314
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 213868 times.
213995 if (aresample->more_data) {
315 AVFrame *outsamplesref;
316
317
2/2
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 4 times.
127 if (flush_frame(outlink, 0, &outsamplesref) >= 0) {
318 123 return ff_filter_frame(outlink, outsamplesref);
319 }
320 }
321 213872 aresample->more_data = 0;
322
323
4/4
✓ Branch 0 taken 213237 times.
✓ Branch 1 taken 635 times.
✓ Branch 3 taken 1273 times.
✓ Branch 4 taken 211964 times.
213872 if (!aresample->eof && ff_inlink_acknowledge_status(inlink, &status, &pts))
324 1273 aresample->eof = 1;
325
326 // Second request more data from the input
327
2/2
✓ Branch 0 taken 211964 times.
✓ Branch 1 taken 1908 times.
213872 if (!aresample->eof)
328
1/2
✓ Branch 1 taken 211964 times.
✗ Branch 2 not taken.
211964 FF_FILTER_FORWARD_WANTED(outlink, inlink);
329
330 // Third if we hit the end flush
331
1/2
✓ Branch 0 taken 1908 times.
✗ Branch 1 not taken.
1908 if (aresample->eof) {
332 AVFrame *outsamplesref;
333
334
2/2
✓ Branch 1 taken 1273 times.
✓ Branch 2 taken 635 times.
1908 if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0) {
335
1/2
✓ Branch 0 taken 1273 times.
✗ Branch 1 not taken.
1273 if (ret == AVERROR_EOF) {
336 1273 ff_outlink_set_status(outlink, AVERROR_EOF, aresample->next_pts);
337 1273 return 0;
338 }
339 return ret;
340 }
341
342 635 return ff_filter_frame(outlink, outsamplesref);
343 }
344
345 ff_filter_set_ready(ctx, 100);
346 return 0;
347 }
348
349 428079 static int activate(AVFilterContext *ctx)
350 {
351 428079 AResampleContext *aresample = ctx->priv;
352 428079 AVFilterLink *inlink = ctx->inputs[0];
353 428079 AVFilterLink *outlink = ctx->outputs[0];
354
355
2/2
✓ Branch 1 taken 1098 times.
✓ Branch 2 taken 426981 times.
428079 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
356
357
4/4
✓ Branch 0 taken 426346 times.
✓ Branch 1 taken 635 times.
✓ Branch 3 taken 212986 times.
✓ Branch 4 taken 213360 times.
426981 if (!aresample->eof && ff_inlink_queued_frames(inlink)) {
358 212986 AVFrame *frame = NULL;
359 int ret;
360
361 212986 ret = ff_inlink_consume_frame(inlink, &frame);
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212986 times.
212986 if (ret < 0)
363 212986 return ret;
364
1/2
✓ Branch 0 taken 212986 times.
✗ Branch 1 not taken.
212986 if (ret > 0)
365 212986 return filter_frame(inlink, frame);
366 }
367
368 213995 return request_frame(outlink);
369 }
370
371 static const AVClass *resample_child_class_iterate(void **iter)
372 {
373 const AVClass *c = *iter ? NULL : swr_get_class();
374 *iter = (void*)(uintptr_t)c;
375 return c;
376 }
377
378 6685 static void *resample_child_next(void *obj, void *prev)
379 {
380 6685 AResampleContext *s = obj;
381
2/2
✓ Branch 0 taken 5407 times.
✓ Branch 1 taken 1278 times.
6685 return prev ? NULL : s->swr;
382 }
383
384 #define OFFSET(x) offsetof(AResampleContext, x)
385 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
386
387 static const AVOption options[] = {
388 {"sample_rate", NULL, OFFSET(sample_rate_arg), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
389 {NULL}
390 };
391
392 static const AVClass aresample_class = {
393 .class_name = "aresample",
394 .item_name = av_default_item_name,
395 .option = options,
396 .version = LIBAVUTIL_VERSION_INT,
397 .child_class_iterate = resample_child_class_iterate,
398 .child_next = resample_child_next,
399 };
400
401 static const AVFilterPad aresample_outputs[] = {
402 {
403 .name = "default",
404 .config_props = config_output,
405 .type = AVMEDIA_TYPE_AUDIO,
406 },
407 };
408
409 const FFFilter ff_af_aresample = {
410 .p.name = "aresample",
411 .p.description = NULL_IF_CONFIG_SMALL("Resample audio data."),
412 .p.priv_class = &aresample_class,
413 .preinit = preinit,
414 .activate = activate,
415 .uninit = uninit,
416 .priv_size = sizeof(AResampleContext),
417 FILTER_INPUTS(ff_audio_default_filterpad),
418 FILTER_OUTPUTS(aresample_outputs),
419 FILTER_QUERY_FUNC2(query_formats),
420 };
421