1 /*
2 * Copyright (c) 2011 Mina Nagy Zaki
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * format audio filter
24 */
25
26 #include "libavutil/avstring.h"
27 #include "libavutil/channel_layout.h"
28 #include "libavutil/common.h"
29 #include "libavutil/opt.h"
30
31 #include "audio.h"
32 #include "avfilter.h"
33 #include "formats.h"
34 #include "internal.h"
35
36 typedef struct AFormatContext {
37 const AVClass *class;
38
39 AVFilterFormats *formats;
40 AVFilterFormats *sample_rates;
41 AVFilterChannelLayouts *channel_layouts;
42
43 char *formats_str;
44 char *sample_rates_str;
45 char *channel_layouts_str;
46 } AFormatContext;
47
48 #define OFFSET(x) offsetof(AFormatContext, x)
49 #define A AV_OPT_FLAG_AUDIO_PARAM
50 #define F AV_OPT_FLAG_FILTERING_PARAM
51 static const AVOption aformat_options[] = {
52 { "sample_fmts", "A '|'-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A|F },
53 { "f", "A '|'-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A|F },
54 { "sample_rates", "A '|'-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A|F },
55 { "r", "A '|'-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A|F },
56 { "channel_layouts", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A|F },
57 { "cl", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A|F },
58 { NULL }
59 };
60
61 AVFILTER_DEFINE_CLASS(aformat);
62
63 #define PARSE_FORMATS(str, type, list, add_to_list, get_fmt, none, desc) \
64 do { \
65 char *next, *cur = str; \
66 int ret; \
67 \
68 while (cur) { \
69 type fmt; \
70 next = strchr(cur, '|'); \
71 if (next) \
72 *next++ = 0; \
73 \
74 if ((fmt = get_fmt(cur)) == none) { \
75 av_log(ctx, AV_LOG_ERROR, "Error parsing " desc ": %s.\n", cur);\
76 return AVERROR(EINVAL); \
77 } \
78 if ((ret = add_to_list(&list, fmt)) < 0) { \
79 return ret; \
80 } \
81 \
82 cur = next; \
83 } \
84 } while (0)
85
get_sample_rate(const char * samplerate)86 static int get_sample_rate(const char *samplerate)
87 {
88 int ret = strtol(samplerate, NULL, 0);
89 return FFMAX(ret, 0);
90 }
91
parse_channel_layouts(AVFilterContext * ctx)92 static int parse_channel_layouts(AVFilterContext *ctx)
93 {
94 AFormatContext *s = ctx->priv;
95 char *next, *cur = s->channel_layouts_str;
96 AVChannelLayout fmt = { 0 };
97 int ret;
98
99 while (cur) {
100 next = strchr(cur, '|');
101 if (next)
102 *next++ = 0;
103
104 ret = av_channel_layout_from_string(&fmt, cur);
105 if (ret < 0) {
106 #if FF_API_OLD_CHANNEL_LAYOUT
107 uint64_t mask;
108 FF_DISABLE_DEPRECATION_WARNINGS
109 mask = av_get_channel_layout(cur);
110 if (!mask) {
111 #endif
112 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur);
113 return AVERROR(EINVAL);
114 #if FF_API_OLD_CHANNEL_LAYOUT
115 }
116 FF_ENABLE_DEPRECATION_WARNINGS
117 av_log(ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
118 cur);
119 av_channel_layout_from_mask(&fmt, mask);
120 #endif
121 }
122 ret = ff_add_channel_layout(&s->channel_layouts, &fmt);
123 av_channel_layout_uninit(&fmt);
124 if (ret < 0)
125 return ret;
126
127 cur = next;
128 }
129
130 return 0;
131 }
132
init(AVFilterContext * ctx)133 static av_cold int init(AVFilterContext *ctx)
134 {
135 AFormatContext *s = ctx->priv;
136 int ret;
137
138 PARSE_FORMATS(s->formats_str, enum AVSampleFormat, s->formats,
139 ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format");
140 PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format,
141 get_sample_rate, 0, "sample rate");
142 ret = parse_channel_layouts(ctx);
143 if (ret < 0)
144 return ret;
145
146 return 0;
147 }
148
uninit(AVFilterContext * ctx)149 static av_cold void uninit(AVFilterContext *ctx)
150 {
151 AFormatContext *s = ctx->priv;
152
153 ff_formats_unref(&s->formats);
154 ff_formats_unref(&s->sample_rates);
155 ff_channel_layouts_unref(&s->channel_layouts);
156 }
157
query_formats(AVFilterContext * ctx)158 static int query_formats(AVFilterContext *ctx)
159 {
160 AFormatContext *s = ctx->priv;
161 int ret;
162
163 ret = ff_set_common_formats(ctx, s->formats ? s->formats :
164 ff_all_formats(AVMEDIA_TYPE_AUDIO));
165 s->formats = NULL;
166 if (ret < 0)
167 return ret;
168 ret = ff_set_common_samplerates(ctx, s->sample_rates ? s->sample_rates :
169 ff_all_samplerates());
170 s->sample_rates = NULL;
171 if (ret < 0)
172 return ret;
173 ret = ff_set_common_channel_layouts(ctx, s->channel_layouts ? s->channel_layouts :
174 ff_all_channel_counts());
175 s->channel_layouts = NULL;
176 return ret;
177 }
178
179 static const AVFilterPad avfilter_af_aformat_inputs[] = {
180 {
181 .name = "default",
182 .type = AVMEDIA_TYPE_AUDIO,
183 },
184 };
185
186 static const AVFilterPad avfilter_af_aformat_outputs[] = {
187 {
188 .name = "default",
189 .type = AVMEDIA_TYPE_AUDIO
190 },
191 };
192
193 const AVFilter ff_af_aformat = {
194 .name = "aformat",
195 .description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."),
196 .init = init,
197 .uninit = uninit,
198 .priv_size = sizeof(AFormatContext),
199 .priv_class = &aformat_class,
200 .flags = AVFILTER_FLAG_METADATA_ONLY,
201 FILTER_INPUTS(avfilter_af_aformat_inputs),
202 FILTER_OUTPUTS(avfilter_af_aformat_outputs),
203 FILTER_QUERY_FUNC(query_formats),
204 };
205