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