2 * Copyright (c) 2011 Stefano Sabatini
3 * Copyright (c) 2011 Mina Nagy Zaki
5 * This file is part of FFmpeg.
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.
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.
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
24 * resampling audio filter
27 #include "libavutil/avstring.h"
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/samplefmt.h"
31 #include "libavutil/avassert.h"
32 #include "libswresample/swresample.h"
39 typedef struct AResampleContext {
43 struct SwrContext *swr;
49 static av_cold int preinit(AVFilterContext *ctx)
51 AResampleContext *aresample = ctx->priv;
53 aresample->next_pts = AV_NOPTS_VALUE;
54 aresample->swr = swr_alloc();
56 return AVERROR(ENOMEM);
61 static av_cold void uninit(AVFilterContext *ctx)
63 AResampleContext *aresample = ctx->priv;
64 swr_free(&aresample->swr);
67 static int query_formats(AVFilterContext *ctx)
69 AResampleContext *aresample = ctx->priv;
70 enum AVSampleFormat out_format;
71 AVChannelLayout out_layout = { 0 };
74 AVFilterLink *inlink = ctx->inputs[0];
75 AVFilterLink *outlink = ctx->outputs[0];
77 AVFilterFormats *in_formats, *out_formats;
78 AVFilterFormats *in_samplerates, *out_samplerates;
79 AVFilterChannelLayouts *in_layouts, *out_layouts;
82 if (aresample->sample_rate_arg > 0)
83 av_opt_set_int(aresample->swr, "osr", aresample->sample_rate_arg, 0);
84 av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
85 av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
87 in_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
88 if ((ret = ff_formats_ref(in_formats, &inlink->outcfg.formats)) < 0)
91 in_samplerates = ff_all_samplerates();
92 if ((ret = ff_formats_ref(in_samplerates, &inlink->outcfg.samplerates)) < 0)
95 in_layouts = ff_all_channel_counts();
96 if ((ret = ff_channel_layouts_ref(in_layouts, &inlink->outcfg.channel_layouts)) < 0)
100 int ratelist[] = { out_rate, -1 };
101 out_samplerates = ff_make_format_list(ratelist);
103 out_samplerates = ff_all_samplerates();
106 if ((ret = ff_formats_ref(out_samplerates, &outlink->incfg.samplerates)) < 0)
109 if(out_format != AV_SAMPLE_FMT_NONE) {
110 int formatlist[] = { out_format, -1 };
111 out_formats = ff_make_format_list(formatlist);
113 out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
114 if ((ret = ff_formats_ref(out_formats, &outlink->incfg.formats)) < 0)
117 av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
118 if (av_channel_layout_check(&out_layout)) {
119 const AVChannelLayout layout_list[] = { out_layout, { 0 } };
120 out_layouts = ff_make_channel_layout_list(layout_list);
122 out_layouts = ff_all_channel_counts();
123 av_channel_layout_uninit(&out_layout);
125 return ff_channel_layouts_ref(out_layouts, &outlink->incfg.channel_layouts);
129 static int config_output(AVFilterLink *outlink)
132 AVFilterContext *ctx = outlink->src;
133 AVFilterLink *inlink = ctx->inputs[0];
134 AResampleContext *aresample = ctx->priv;
135 AVChannelLayout out_layout = { 0 };
137 enum AVSampleFormat out_format;
138 char inchl_buf[128], outchl_buf[128];
140 ret = swr_alloc_set_opts2(&aresample->swr,
141 &outlink->ch_layout, outlink->format, outlink->sample_rate,
142 &inlink->ch_layout, inlink->format, inlink->sample_rate,
147 ret = swr_init(aresample->swr);
151 av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
152 av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
153 av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
154 outlink->time_base = (AVRational) {1, out_rate};
156 av_assert0(outlink->sample_rate == out_rate);
157 av_assert0(!av_channel_layout_compare(&outlink->ch_layout, &out_layout));
158 av_assert0(outlink->format == out_format);
160 av_channel_layout_uninit(&out_layout);
162 aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
164 av_channel_layout_describe(&inlink ->ch_layout, inchl_buf, sizeof(inchl_buf));
165 av_channel_layout_describe(&outlink->ch_layout, outchl_buf, sizeof(outchl_buf));
167 av_log(ctx, AV_LOG_VERBOSE, "ch:%d chl:%s fmt:%s r:%dHz -> ch:%d chl:%s fmt:%s r:%dHz\n",
168 inlink ->ch_layout.nb_channels, inchl_buf, av_get_sample_fmt_name(inlink->format), inlink->sample_rate,
169 outlink->ch_layout.nb_channels, outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
173 static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
175 AVFilterContext *ctx = inlink->dst;
176 AResampleContext *aresample = ctx->priv;
177 const int n_in = insamplesref->nb_samples;
179 int n_out = n_in * aresample->ratio + 32;
180 AVFilterLink *const outlink = inlink->dst->outputs[0];
181 AVFrame *outsamplesref;
184 delay = swr_get_delay(aresample->swr, outlink->sample_rate);
186 n_out += FFMIN(delay, FFMAX(4096, n_out));
188 outsamplesref = ff_get_audio_buffer(outlink, n_out);
191 av_frame_free(&insamplesref);
192 return AVERROR(ENOMEM);
195 av_frame_copy_props(outsamplesref, insamplesref);
196 outsamplesref->format = outlink->format;
197 #if FF_API_OLD_CHANNEL_LAYOUT
198 FF_DISABLE_DEPRECATION_WARNINGS
199 outsamplesref->channels = outlink->ch_layout.nb_channels;
200 outsamplesref->channel_layout = outlink->channel_layout;
201 FF_ENABLE_DEPRECATION_WARNINGS
203 ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout);
206 outsamplesref->sample_rate = outlink->sample_rate;
208 if(insamplesref->pts != AV_NOPTS_VALUE) {
209 int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den);
210 int64_t outpts= swr_next_pts(aresample->swr, inpts);
211 aresample->next_pts =
212 outsamplesref->pts = ROUNDED_DIV(outpts, inlink->sample_rate);
214 outsamplesref->pts = AV_NOPTS_VALUE;
216 n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out,
217 (void *)insamplesref->extended_data, n_in);
219 av_frame_free(&outsamplesref);
220 av_frame_free(&insamplesref);
221 ff_inlink_request_frame(inlink);
225 aresample->more_data = outsamplesref->nb_samples == n_out; // Indicate that there is probably more data in our buffers
227 outsamplesref->nb_samples = n_out;
229 ret = ff_filter_frame(outlink, outsamplesref);
230 av_frame_free(&insamplesref);
234 static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret)
236 AVFilterContext *ctx = outlink->src;
237 AResampleContext *aresample = ctx->priv;
238 AVFilterLink *const inlink = outlink->src->inputs[0];
239 AVFrame *outsamplesref;
243 outsamplesref = ff_get_audio_buffer(outlink, n_out);
244 *outsamplesref_ret = outsamplesref;
246 return AVERROR(ENOMEM);
248 pts = swr_next_pts(aresample->swr, INT64_MIN);
249 pts = ROUNDED_DIV(pts, inlink->sample_rate);
251 n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0);
253 av_frame_free(&outsamplesref);
254 return (n_out == 0) ? AVERROR_EOF : n_out;
257 outsamplesref->sample_rate = outlink->sample_rate;
258 outsamplesref->nb_samples = n_out;
260 outsamplesref->pts = pts;
265 static int request_frame(AVFilterLink *outlink)
267 AVFilterContext *ctx = outlink->src;
268 AVFilterLink *inlink = ctx->inputs[0];
269 AResampleContext *aresample = ctx->priv;
273 // First try to get data from the internal buffers
274 if (aresample->more_data) {
275 AVFrame *outsamplesref;
277 if (flush_frame(outlink, 0, &outsamplesref) >= 0) {
278 return ff_filter_frame(outlink, outsamplesref);
281 aresample->more_data = 0;
283 if (!aresample->eof && ff_inlink_acknowledge_status(inlink, &status, &pts))
286 // Second request more data from the input
288 FF_FILTER_FORWARD_WANTED(outlink, inlink);
290 // Third if we hit the end flush
291 if (aresample->eof) {
292 AVFrame *outsamplesref;
294 if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0) {
295 if (ret == AVERROR_EOF) {
296 ff_outlink_set_status(outlink, AVERROR_EOF, aresample->next_pts);
302 return ff_filter_frame(outlink, outsamplesref);
305 ff_filter_set_ready(ctx, 100);
309 static int activate(AVFilterContext *ctx)
311 AResampleContext *aresample = ctx->priv;
312 AVFilterLink *inlink = ctx->inputs[0];
313 AVFilterLink *outlink = ctx->outputs[0];
315 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
317 if (!aresample->eof && ff_inlink_queued_frames(inlink)) {
318 AVFrame *frame = NULL;
321 ret = ff_inlink_consume_frame(inlink, &frame);
325 return filter_frame(inlink, frame);
328 return request_frame(outlink);
331 static const AVClass *resample_child_class_iterate(void **iter)
333 const AVClass *c = *iter ? NULL : swr_get_class();
334 *iter = (void*)(uintptr_t)c;
338 static void *resample_child_next(void *obj, void *prev)
340 AResampleContext *s = obj;
341 return prev ? NULL : s->swr;
344 #define OFFSET(x) offsetof(AResampleContext, x)
345 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
347 static const AVOption options[] = {
348 {"sample_rate", NULL, OFFSET(sample_rate_arg), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
352 static const AVClass aresample_class = {
353 .class_name = "aresample",
354 .item_name = av_default_item_name,
356 .version = LIBAVUTIL_VERSION_INT,
357 .child_class_iterate = resample_child_class_iterate,
358 .child_next = resample_child_next,
361 static const AVFilterPad aresample_outputs[] = {
364 .config_props = config_output,
365 .type = AVMEDIA_TYPE_AUDIO,
369 const AVFilter ff_af_aresample = {
371 .description = NULL_IF_CONFIG_SMALL("Resample audio data."),
373 .activate = activate,
375 .priv_size = sizeof(AResampleContext),
376 .priv_class = &aresample_class,
377 FILTER_INPUTS(ff_audio_default_filterpad),
378 FILTER_OUTPUTS(aresample_outputs),
379 FILTER_QUERY_FUNC(query_formats),