Commit | Line | Data |
---|---|---|
d371e7b9 AK |
1 | /* |
2 | * | |
3 | * This file is part of Libav. | |
4 | * | |
5 | * Libav is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2.1 of the License, or (at your option) any later version. | |
9 | * | |
10 | * Libav is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with Libav; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | /** | |
21 | * @file | |
22 | * sample format and channel layout conversion audio filter | |
23 | */ | |
24 | ||
25 | #include "libavutil/avassert.h" | |
26 | #include "libavutil/avstring.h" | |
27 | #include "libavutil/mathematics.h" | |
28 | #include "libavutil/opt.h" | |
29 | ||
30 | #include "libavresample/avresample.h" | |
31 | ||
32 | #include "audio.h" | |
33 | #include "avfilter.h" | |
34 | #include "internal.h" | |
35 | ||
36 | typedef struct ResampleContext { | |
37 | AVAudioResampleContext *avr; | |
38 | ||
39 | int64_t next_pts; | |
40 | } ResampleContext; | |
41 | ||
42 | static av_cold void uninit(AVFilterContext *ctx) | |
43 | { | |
44 | ResampleContext *s = ctx->priv; | |
45 | ||
46 | if (s->avr) { | |
47 | avresample_close(s->avr); | |
48 | avresample_free(&s->avr); | |
49 | } | |
50 | } | |
51 | ||
52 | static int query_formats(AVFilterContext *ctx) | |
53 | { | |
54 | AVFilterLink *inlink = ctx->inputs[0]; | |
55 | AVFilterLink *outlink = ctx->outputs[0]; | |
56 | ||
57 | AVFilterFormats *in_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); | |
58 | AVFilterFormats *out_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); | |
59 | ||
60 | avfilter_formats_ref(in_formats, &inlink->out_formats); | |
61 | avfilter_formats_ref(out_formats, &outlink->in_formats); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static int config_output(AVFilterLink *outlink) | |
67 | { | |
68 | AVFilterContext *ctx = outlink->src; | |
69 | AVFilterLink *inlink = ctx->inputs[0]; | |
70 | ResampleContext *s = ctx->priv; | |
71 | char buf1[64], buf2[64]; | |
72 | int ret; | |
73 | ||
74 | if (s->avr) { | |
75 | avresample_close(s->avr); | |
76 | avresample_free(&s->avr); | |
77 | } | |
78 | ||
79 | if (inlink->channel_layout == outlink->channel_layout && | |
80 | inlink->sample_rate == outlink->sample_rate && | |
81 | inlink->format == outlink->format) | |
82 | return 0; | |
83 | ||
84 | if (!(s->avr = avresample_alloc_context())) | |
85 | return AVERROR(ENOMEM); | |
86 | ||
87 | av_opt_set_int(s->avr, "in_channel_layout", inlink ->channel_layout, 0); | |
88 | av_opt_set_int(s->avr, "out_channel_layout", outlink->channel_layout, 0); | |
89 | av_opt_set_int(s->avr, "in_sample_fmt", inlink ->format, 0); | |
90 | av_opt_set_int(s->avr, "out_sample_fmt", outlink->format, 0); | |
91 | av_opt_set_int(s->avr, "in_sample_rate", inlink ->sample_rate, 0); | |
92 | av_opt_set_int(s->avr, "out_sample_rate", outlink->sample_rate, 0); | |
93 | ||
94 | /* if both the input and output formats are s16 or u8, use s16 as | |
95 | the internal sample format */ | |
96 | if (av_get_bytes_per_sample(inlink->format) <= 2 && | |
97 | av_get_bytes_per_sample(outlink->format) <= 2) | |
98 | av_opt_set_int(s->avr, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0); | |
99 | ||
100 | if ((ret = avresample_open(s->avr)) < 0) | |
101 | return ret; | |
102 | ||
103 | outlink->time_base = (AVRational){ 1, outlink->sample_rate }; | |
104 | s->next_pts = AV_NOPTS_VALUE; | |
105 | ||
106 | av_get_channel_layout_string(buf1, sizeof(buf1), | |
107 | -1, inlink ->channel_layout); | |
108 | av_get_channel_layout_string(buf2, sizeof(buf2), | |
109 | -1, outlink->channel_layout); | |
110 | av_log(ctx, AV_LOG_VERBOSE, | |
111 | "fmt:%s srate: %d cl:%s -> fmt:%s srate: %d cl:%s\n", | |
112 | av_get_sample_fmt_name(inlink ->format), inlink ->sample_rate, buf1, | |
113 | av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf2); | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
118 | static int request_frame(AVFilterLink *outlink) | |
119 | { | |
120 | AVFilterContext *ctx = outlink->src; | |
121 | ResampleContext *s = ctx->priv; | |
122 | int ret = avfilter_request_frame(ctx->inputs[0]); | |
123 | ||
124 | /* flush the lavr delay buffer */ | |
125 | if (ret == AVERROR_EOF && s->avr) { | |
126 | AVFilterBufferRef *buf; | |
127 | int nb_samples = av_rescale_rnd(avresample_get_delay(s->avr), | |
128 | outlink->sample_rate, | |
129 | ctx->inputs[0]->sample_rate, | |
130 | AV_ROUND_UP); | |
131 | ||
132 | if (!nb_samples) | |
133 | return ret; | |
134 | ||
135 | buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); | |
136 | if (!buf) | |
137 | return AVERROR(ENOMEM); | |
138 | ||
139 | ret = avresample_convert(s->avr, (void**)buf->extended_data, | |
140 | buf->linesize[0], nb_samples, | |
141 | NULL, 0, 0); | |
142 | if (ret <= 0) { | |
143 | avfilter_unref_buffer(buf); | |
144 | return (ret == 0) ? AVERROR_EOF : ret; | |
145 | } | |
146 | ||
147 | buf->pts = s->next_pts; | |
148 | ff_filter_samples(outlink, buf); | |
149 | return 0; | |
150 | } | |
151 | return ret; | |
152 | } | |
153 | ||
154 | static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |
155 | { | |
156 | AVFilterContext *ctx = inlink->dst; | |
157 | ResampleContext *s = ctx->priv; | |
158 | AVFilterLink *outlink = ctx->outputs[0]; | |
159 | ||
160 | if (s->avr) { | |
161 | AVFilterBufferRef *buf_out; | |
162 | int delay, nb_samples, ret; | |
163 | ||
164 | /* maximum possible samples lavr can output */ | |
165 | delay = avresample_get_delay(s->avr); | |
166 | nb_samples = av_rescale_rnd(buf->audio->nb_samples + delay, | |
167 | outlink->sample_rate, inlink->sample_rate, | |
168 | AV_ROUND_UP); | |
169 | ||
170 | buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); | |
171 | ret = avresample_convert(s->avr, (void**)buf_out->extended_data, | |
172 | buf_out->linesize[0], nb_samples, | |
173 | (void**)buf->extended_data, buf->linesize[0], | |
174 | buf->audio->nb_samples); | |
175 | ||
176 | av_assert0(!avresample_available(s->avr)); | |
177 | ||
178 | if (s->next_pts == AV_NOPTS_VALUE) { | |
179 | if (buf->pts == AV_NOPTS_VALUE) { | |
180 | av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, " | |
181 | "assuming 0.\n"); | |
182 | s->next_pts = 0; | |
183 | } else | |
184 | s->next_pts = av_rescale_q(buf->pts, inlink->time_base, | |
185 | outlink->time_base); | |
186 | } | |
187 | ||
188 | if (ret > 0) { | |
189 | buf_out->audio->nb_samples = ret; | |
190 | if (buf->pts != AV_NOPTS_VALUE) { | |
191 | buf_out->pts = av_rescale_q(buf->pts, inlink->time_base, | |
192 | outlink->time_base) - | |
193 | av_rescale(delay, outlink->sample_rate, | |
194 | inlink->sample_rate); | |
195 | } else | |
196 | buf_out->pts = s->next_pts; | |
197 | ||
198 | s->next_pts = buf_out->pts + buf_out->audio->nb_samples; | |
199 | ||
200 | ff_filter_samples(outlink, buf_out); | |
201 | } | |
202 | avfilter_unref_buffer(buf); | |
203 | } else | |
204 | ff_filter_samples(outlink, buf); | |
205 | } | |
206 | ||
207 | AVFilter avfilter_af_resample = { | |
208 | .name = "resample", | |
209 | .description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."), | |
210 | .priv_size = sizeof(ResampleContext), | |
211 | ||
212 | .uninit = uninit, | |
213 | .query_formats = query_formats, | |
214 | ||
215 | .inputs = (const AVFilterPad[]) {{ .name = "default", | |
216 | .type = AVMEDIA_TYPE_AUDIO, | |
217 | .filter_samples = filter_samples, | |
218 | .min_perms = AV_PERM_READ }, | |
219 | { .name = NULL}}, | |
220 | .outputs = (const AVFilterPad[]) {{ .name = "default", | |
221 | .type = AVMEDIA_TYPE_AUDIO, | |
222 | .config_props = config_output, | |
223 | .request_frame = request_frame }, | |
224 | { .name = NULL}}, | |
225 | }; |