lavfi/aresample: use libswresample.
[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 "libswresample/swresample.h"
28 #include "avfilter.h"
29 #include "internal.h"
30
31 typedef struct {
32     int out_rate;
33     double ratio;
34     struct SwrContext *swr;
35 } AResampleContext;
36
37 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
38 {
39     AResampleContext *aresample = ctx->priv;
40     int ret;
41
42     if (args) {
43         if ((ret = ff_parse_sample_rate(&aresample->out_rate, args, ctx)) < 0)
44             return ret;
45     } else {
46         aresample->out_rate = -1;
47     }
48
49     return 0;
50 }
51
52 static av_cold void uninit(AVFilterContext *ctx)
53 {
54     AResampleContext *aresample = ctx->priv;
55     swr_free(&aresample->swr);
56 }
57
58 static int config_output(AVFilterLink *outlink)
59 {
60     int ret;
61     AVFilterContext *ctx = outlink->src;
62     AVFilterLink *inlink = ctx->inputs[0];
63     AResampleContext *aresample = ctx->priv;
64
65     if (aresample->out_rate == -1)
66         aresample->out_rate = outlink->sample_rate;
67     else
68         outlink->sample_rate = aresample->out_rate;
69     outlink->time_base = (AVRational) {1, aresample->out_rate};
70
71     //TODO: make the resampling parameters (filter size, phrase shift, linear, cutoff) configurable
72     aresample->swr = swr_alloc_set_opts(aresample->swr,
73                                         inlink->channel_layout, inlink->format, aresample->out_rate,
74                                         inlink->channel_layout, inlink->format, inlink->sample_rate,
75                                         0, ctx);
76     if (!aresample->swr)
77         return AVERROR(ENOMEM);
78     ret = swr_init(aresample->swr);
79     if (ret < 0)
80         return ret;
81
82     aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
83
84     av_log(ctx, AV_LOG_INFO, "r:%"PRId64"Hz -> r:%"PRId64"Hz\n",
85            inlink->sample_rate, outlink->sample_rate);
86     return 0;
87 }
88
89 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
90 {
91     AResampleContext *aresample = inlink->dst->priv;
92     const int n_in  = insamplesref->audio->nb_samples;
93     int n_out       = n_in * aresample->ratio;
94     AVFilterLink *const outlink = inlink->dst->outputs[0];
95     AVFilterBufferRef *outsamplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
96
97     n_out = swr_convert(aresample->swr, outsamplesref->data, n_out,
98                                  (void *)insamplesref->data, n_in);
99
100     avfilter_copy_buffer_ref_props(outsamplesref, insamplesref);
101     outsamplesref->audio->sample_rate = outlink->sample_rate;
102     outsamplesref->audio->nb_samples  = n_out;
103     outsamplesref->pts = av_rescale(outlink->sample_rate, insamplesref->pts,
104                                     inlink ->sample_rate);
105
106     avfilter_filter_samples(outlink, outsamplesref);
107     avfilter_unref_buffer(insamplesref);
108 }
109
110 AVFilter avfilter_af_aresample = {
111     .name          = "aresample",
112     .description   = NULL_IF_CONFIG_SMALL("Resample audio data."),
113     .init          = init,
114     .uninit        = uninit,
115     .priv_size     = sizeof(AResampleContext),
116
117     .inputs    = (const AVFilterPad[]) {{ .name      = "default",
118                                     .type            = AVMEDIA_TYPE_AUDIO,
119                                     .filter_samples  = filter_samples,
120                                     .min_perms       = AV_PERM_READ, },
121                                   { .name = NULL}},
122     .outputs   = (const AVFilterPad[]) {{ .name      = "default",
123                                     .config_props    = config_output,
124                                     .type            = AVMEDIA_TYPE_AUDIO, },
125                                   { .name = NULL}},
126 };