]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_aresample.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / af_aresample.c
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/eval.h"
28 #include "libavcodec/avcodec.h"
29 #include "avfilter.h"
30 #include "internal.h"
31
32 typedef struct {
33     struct AVResampleContext *resample;
34     int out_rate;
35     double ratio;
36     AVFilterBufferRef *outsamplesref;
37     int unconsumed_nb_samples,
38         max_cached_nb_samples;
39     int16_t *cached_data[8],
40             *resampled_data[8];
41 } AResampleContext;
42
43 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
44 {
45     AResampleContext *aresample = ctx->priv;
46     int ret;
47
48     if (args) {
49         if ((ret = ff_parse_sample_rate(&aresample->out_rate, args, ctx)) < 0)
50             return ret;
51     } else {
52         aresample->out_rate = -1;
53     }
54
55     return 0;
56 }
57
58 static av_cold void uninit(AVFilterContext *ctx)
59 {
60     AResampleContext *aresample = ctx->priv;
61     if (aresample->outsamplesref) {
62         int nb_channels =
63             av_get_channel_layout_nb_channels(
64                 aresample->outsamplesref->audio->channel_layout);
65         avfilter_unref_buffer(aresample->outsamplesref);
66         while (nb_channels--) {
67             av_freep(&(aresample->cached_data[nb_channels]));
68             av_freep(&(aresample->resampled_data[nb_channels]));
69         }
70     }
71
72     if (aresample->resample)
73         av_resample_close(aresample->resample);
74 }
75
76 static int config_output(AVFilterLink *outlink)
77 {
78     AVFilterContext *ctx = outlink->src;
79     AVFilterLink *inlink = ctx->inputs[0];
80     AResampleContext *aresample = ctx->priv;
81
82     if (aresample->out_rate == -1)
83         aresample->out_rate = outlink->sample_rate;
84     else
85         outlink->sample_rate = aresample->out_rate;
86
87     //TODO: make the resampling parameters configurable
88     aresample->resample = av_resample_init(aresample->out_rate, inlink->sample_rate,
89                                            16, 10, 0, 0.8);
90
91     aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
92
93     av_log(ctx, AV_LOG_INFO, "r:%"PRId64"Hz -> r:%"PRId64"Hz\n",
94            inlink->sample_rate, outlink->sample_rate);
95     return 0;
96 }
97
98 static int query_formats(AVFilterContext *ctx)
99 {
100     AVFilterFormats *formats = NULL;
101
102     avfilter_add_format(&formats, AV_SAMPLE_FMT_S16);
103     if (!formats)
104         return AVERROR(ENOMEM);
105     avfilter_set_common_sample_formats(ctx, formats);
106
107     formats = avfilter_make_all_channel_layouts();
108     if (!formats)
109         return AVERROR(ENOMEM);
110     avfilter_set_common_channel_layouts(ctx, formats);
111
112     formats = avfilter_make_all_packing_formats();
113     if (!formats)
114         return AVERROR(ENOMEM);
115     avfilter_set_common_packing_formats(ctx, formats);
116
117     return 0;
118 }
119
120 static void deinterleave(int16_t **outp, int16_t *in,
121                          int nb_channels, int nb_samples)
122 {
123     int16_t *out[8];
124     memcpy(out, outp, nb_channels * sizeof(int16_t*));
125
126     switch (nb_channels) {
127     case 2:
128         while (nb_samples--) {
129             *out[0]++ = *in++;
130             *out[1]++ = *in++;
131         }
132         break;
133     case 3:
134         while (nb_samples--) {
135             *out[0]++ = *in++;
136             *out[1]++ = *in++;
137             *out[2]++ = *in++;
138         }
139         break;
140     case 4:
141         while (nb_samples--) {
142             *out[0]++ = *in++;
143             *out[1]++ = *in++;
144             *out[2]++ = *in++;
145             *out[3]++ = *in++;
146         }
147         break;
148     case 5:
149         while (nb_samples--) {
150             *out[0]++ = *in++;
151             *out[1]++ = *in++;
152             *out[2]++ = *in++;
153             *out[3]++ = *in++;
154             *out[4]++ = *in++;
155         }
156         break;
157     case 6:
158         while (nb_samples--) {
159             *out[0]++ = *in++;
160             *out[1]++ = *in++;
161             *out[2]++ = *in++;
162             *out[3]++ = *in++;
163             *out[4]++ = *in++;
164             *out[5]++ = *in++;
165         }
166         break;
167     case 8:
168         while (nb_samples--) {
169             *out[0]++ = *in++;
170             *out[1]++ = *in++;
171             *out[2]++ = *in++;
172             *out[3]++ = *in++;
173             *out[4]++ = *in++;
174             *out[5]++ = *in++;
175             *out[6]++ = *in++;
176             *out[7]++ = *in++;
177         }
178         break;
179     }
180 }
181
182 static void interleave(int16_t *out, int16_t **inp,
183         int nb_channels, int nb_samples)
184 {
185     int16_t *in[8];
186     memcpy(in, inp, nb_channels * sizeof(int16_t*));
187
188     switch (nb_channels) {
189     case 2:
190         while (nb_samples--) {
191             *out++ = *in[0]++;
192             *out++ = *in[1]++;
193         }
194         break;
195     case 3:
196         while (nb_samples--) {
197             *out++ = *in[0]++;
198             *out++ = *in[1]++;
199             *out++ = *in[2]++;
200         }
201         break;
202     case 4:
203         while (nb_samples--) {
204             *out++ = *in[0]++;
205             *out++ = *in[1]++;
206             *out++ = *in[2]++;
207             *out++ = *in[3]++;
208         }
209         break;
210     case 5:
211         while (nb_samples--) {
212             *out++ = *in[0]++;
213             *out++ = *in[1]++;
214             *out++ = *in[2]++;
215             *out++ = *in[3]++;
216             *out++ = *in[4]++;
217         }
218         break;
219     case 6:
220         while (nb_samples--) {
221             *out++ = *in[0]++;
222             *out++ = *in[1]++;
223             *out++ = *in[2]++;
224             *out++ = *in[3]++;
225             *out++ = *in[4]++;
226             *out++ = *in[5]++;
227         }
228         break;
229     case 8:
230         while (nb_samples--) {
231             *out++ = *in[0]++;
232             *out++ = *in[1]++;
233             *out++ = *in[2]++;
234             *out++ = *in[3]++;
235             *out++ = *in[4]++;
236             *out++ = *in[5]++;
237             *out++ = *in[6]++;
238             *out++ = *in[7]++;
239         }
240         break;
241     }
242 }
243
244 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
245 {
246     AResampleContext *aresample  = inlink->dst->priv;
247     AVFilterLink * const outlink = inlink->dst->outputs[0];
248     int i,
249         in_nb_samples            = insamplesref->audio->nb_samples,
250         cached_nb_samples        = in_nb_samples + aresample->unconsumed_nb_samples,
251         requested_out_nb_samples = aresample->ratio * cached_nb_samples,
252         nb_channels              =
253             av_get_channel_layout_nb_channels(inlink->channel_layout);
254
255     if (cached_nb_samples > aresample->max_cached_nb_samples) {
256         for (i = 0; i < nb_channels; i++) {
257             aresample->cached_data[i]    =
258                 av_realloc(aresample->cached_data[i], cached_nb_samples * sizeof(int16_t));
259             aresample->resampled_data[i] =
260                 av_realloc(aresample->resampled_data[i],
261                            FFALIGN(sizeof(int16_t) * requested_out_nb_samples, 16));
262
263             if (aresample->cached_data[i] == NULL || aresample->resampled_data[i] == NULL)
264                 return;
265         }
266         aresample->max_cached_nb_samples = cached_nb_samples;
267
268         if (aresample->outsamplesref)
269             avfilter_unref_buffer(aresample->outsamplesref);
270
271         aresample->outsamplesref =
272             avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, requested_out_nb_samples);
273         avfilter_copy_buffer_ref_props(aresample->outsamplesref, insamplesref);
274         aresample->outsamplesref->pts =
275             insamplesref->pts / inlink->sample_rate * outlink->sample_rate;
276         aresample->outsamplesref->audio->sample_rate = outlink->sample_rate;
277         outlink->out_buf = aresample->outsamplesref;
278     }
279
280     /* av_resample() works with planar audio buffers */
281     if (!inlink->planar && nb_channels > 1) {
282         int16_t *out[8];
283         for (i = 0; i < nb_channels; i++)
284             out[i] = aresample->cached_data[i] + aresample->unconsumed_nb_samples;
285
286         deinterleave(out, (int16_t *)insamplesref->data[0],
287                      nb_channels, in_nb_samples);
288     } else {
289         for (i = 0; i < nb_channels; i++)
290             memcpy(aresample->cached_data[i] + aresample->unconsumed_nb_samples,
291                    insamplesref->data[i],
292                    in_nb_samples * sizeof(int16_t));
293     }
294
295     for (i = 0; i < nb_channels; i++) {
296         int consumed_nb_samples;
297         const int is_last = i+1 == nb_channels;
298
299         aresample->outsamplesref->audio->nb_samples =
300             av_resample(aresample->resample,
301                         aresample->resampled_data[i], aresample->cached_data[i],
302                         &consumed_nb_samples,
303                         cached_nb_samples,
304                         requested_out_nb_samples, is_last);
305
306         /* move unconsumed data back to the beginning of the cache */
307         aresample->unconsumed_nb_samples = cached_nb_samples - consumed_nb_samples;
308         memmove(aresample->cached_data[i],
309                 aresample->cached_data[i] + consumed_nb_samples,
310                 aresample->unconsumed_nb_samples * sizeof(int16_t));
311     }
312
313
314     /* copy resampled data to the output samplesref */
315     if (!inlink->planar && nb_channels > 1) {
316         interleave((int16_t *)aresample->outsamplesref->data[0],
317                    aresample->resampled_data,
318                    nb_channels, aresample->outsamplesref->audio->nb_samples);
319     } else {
320         for (i = 0; i < nb_channels; i++)
321             memcpy(aresample->outsamplesref->data[i], aresample->resampled_data[i],
322                    aresample->outsamplesref->audio->nb_samples * sizeof(int16_t));
323     }
324
325     avfilter_filter_samples(outlink, avfilter_ref_buffer(aresample->outsamplesref, ~0));
326     avfilter_unref_buffer(insamplesref);
327 }
328
329 AVFilter avfilter_af_aresample = {
330     .name          = "aresample",
331     .description   = NULL_IF_CONFIG_SMALL("Resample audio data."),
332     .init          = init,
333     .uninit        = uninit,
334     .query_formats = query_formats,
335     .priv_size     = sizeof(AResampleContext),
336
337     .inputs    = (AVFilterPad[]) {{ .name            = "default",
338                                     .type            = AVMEDIA_TYPE_AUDIO,
339                                     .filter_samples  = filter_samples,
340                                     .min_perms       = AV_PERM_READ, },
341                                   { .name = NULL}},
342     .outputs   = (AVFilterPad[]) {{ .name            = "default",
343                                     .config_props    = config_output,
344                                     .type            = AVMEDIA_TYPE_AUDIO, },
345                                   { .name = NULL}},
346 };