Commit | Line | Data |
---|---|---|
fe2147e9 AK |
1 | /* |
2 | * avconv filter configuration | |
3 | * | |
4 | * This file is part of Libav. | |
5 | * | |
6 | * Libav 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 | * Libav 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 Libav; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
8f8bc923 DB |
21 | #include <stdint.h> |
22 | ||
fe2147e9 AK |
23 | #include "avconv.h" |
24 | ||
25 | #include "libavfilter/avfilter.h" | |
1bf34134 | 26 | #include "libavfilter/buffersrc.h" |
fe2147e9 | 27 | |
5c7db097 JR |
28 | #include "libavresample/avresample.h" |
29 | ||
fe2147e9 | 30 | #include "libavutil/avassert.h" |
5c7db097 | 31 | #include "libavutil/avstring.h" |
a903f8f0 | 32 | #include "libavutil/channel_layout.h" |
16302246 | 33 | #include "libavutil/display.h" |
5c7db097 | 34 | #include "libavutil/opt.h" |
fe2147e9 AK |
35 | #include "libavutil/pixdesc.h" |
36 | #include "libavutil/pixfmt.h" | |
37 | #include "libavutil/samplefmt.h" | |
38 | ||
c1ef30a6 DB |
39 | /* Define a function for building a string containing a list of |
40 | * allowed formats. */ | |
50722b4f AK |
41 | #define DEF_CHOOSE_FORMAT(suffix, type, var, supported_list, none, get_name) \ |
42 | static char *choose_ ## suffix (OutputFilter *ofilter) \ | |
fe2147e9 | 43 | { \ |
50722b4f AK |
44 | if (ofilter->var != none) { \ |
45 | get_name(ofilter->var); \ | |
fe2147e9 | 46 | return av_strdup(name); \ |
50722b4f | 47 | } else if (ofilter->supported_list) { \ |
fe2147e9 AK |
48 | const type *p; \ |
49 | AVIOContext *s = NULL; \ | |
50 | uint8_t *ret; \ | |
51 | int len; \ | |
52 | \ | |
53 | if (avio_open_dyn_buf(&s) < 0) \ | |
5e3f9979 | 54 | exit(1); \ |
fe2147e9 | 55 | \ |
50722b4f | 56 | for (p = ofilter->supported_list; *p != none; p++) { \ |
fe2147e9 | 57 | get_name(*p); \ |
bee2d75b | 58 | avio_printf(s, "%s|", name); \ |
fe2147e9 AK |
59 | } \ |
60 | len = avio_close_dyn_buf(s, &ret); \ | |
61 | ret[len - 1] = 0; \ | |
62 | return ret; \ | |
63 | } else \ | |
64 | return NULL; \ | |
65 | } | |
66 | ||
50722b4f | 67 | DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE, |
bee2d75b | 68 | GET_PIX_FMT_NAME) |
fe2147e9 | 69 | |
50722b4f | 70 | DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, |
bee2d75b | 71 | AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME) |
fe2147e9 | 72 | |
50722b4f | 73 | DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, |
bee2d75b | 74 | GET_SAMPLE_RATE_NAME) |
fe2147e9 | 75 | |
50722b4f | 76 | DEF_CHOOSE_FORMAT(channel_layouts, uint64_t, channel_layout, channel_layouts, 0, |
bee2d75b | 77 | GET_CH_LAYOUT_NAME) |
fe2147e9 | 78 | |
73c6ec6d | 79 | int init_simple_filtergraph(InputStream *ist, OutputStream *ost) |
fe2147e9 AK |
80 | { |
81 | FilterGraph *fg = av_mallocz(sizeof(*fg)); | |
82 | ||
83 | if (!fg) | |
5e3f9979 | 84 | exit(1); |
fe2147e9 AK |
85 | fg->index = nb_filtergraphs; |
86 | ||
10bca661 | 87 | GROW_ARRAY(fg->outputs, fg->nb_outputs); |
fe2147e9 | 88 | if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0])))) |
5e3f9979 | 89 | exit(1); |
fe2147e9 AK |
90 | fg->outputs[0]->ost = ost; |
91 | fg->outputs[0]->graph = fg; | |
50722b4f | 92 | fg->outputs[0]->format = -1; |
fe2147e9 AK |
93 | |
94 | ost->filter = fg->outputs[0]; | |
95 | ||
10bca661 | 96 | GROW_ARRAY(fg->inputs, fg->nb_inputs); |
fe2147e9 | 97 | if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0])))) |
5e3f9979 | 98 | exit(1); |
fe2147e9 AK |
99 | fg->inputs[0]->ist = ist; |
100 | fg->inputs[0]->graph = fg; | |
722ec3eb | 101 | fg->inputs[0]->format = -1; |
fe2147e9 | 102 | |
a3a0230a AK |
103 | fg->inputs[0]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*)); |
104 | if (!fg->inputs[0]) | |
105 | exit_program(1); | |
106 | ||
10bca661 | 107 | GROW_ARRAY(ist->filters, ist->nb_filters); |
fe2147e9 AK |
108 | ist->filters[ist->nb_filters - 1] = fg->inputs[0]; |
109 | ||
10bca661 | 110 | GROW_ARRAY(filtergraphs, nb_filtergraphs); |
fe2147e9 AK |
111 | filtergraphs[nb_filtergraphs - 1] = fg; |
112 | ||
73c6ec6d | 113 | return 0; |
fe2147e9 AK |
114 | } |
115 | ||
116 | static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) | |
117 | { | |
118 | InputStream *ist = NULL; | |
119 | enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx); | |
120 | int i; | |
121 | ||
122 | // TODO: support other filter types | |
123 | if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) { | |
124 | av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported " | |
125 | "currently.\n"); | |
5e3f9979 | 126 | exit(1); |
fe2147e9 AK |
127 | } |
128 | ||
129 | if (in->name) { | |
130 | AVFormatContext *s; | |
131 | AVStream *st = NULL; | |
132 | char *p; | |
133 | int file_idx = strtol(in->name, &p, 0); | |
134 | ||
135 | if (file_idx < 0 || file_idx >= nb_input_files) { | |
136 | av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n", | |
137 | file_idx, fg->graph_desc); | |
5e3f9979 | 138 | exit(1); |
fe2147e9 AK |
139 | } |
140 | s = input_files[file_idx]->ctx; | |
141 | ||
142 | for (i = 0; i < s->nb_streams; i++) { | |
15e84ed3 | 143 | if (s->streams[i]->codecpar->codec_type != type) |
fe2147e9 AK |
144 | continue; |
145 | if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) { | |
146 | st = s->streams[i]; | |
147 | break; | |
148 | } | |
149 | } | |
150 | if (!st) { | |
151 | av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s " | |
152 | "matches no streams.\n", p, fg->graph_desc); | |
5e3f9979 | 153 | exit(1); |
fe2147e9 AK |
154 | } |
155 | ist = input_streams[input_files[file_idx]->ist_index + st->index]; | |
156 | } else { | |
157 | /* find the first unused stream of corresponding type */ | |
158 | for (i = 0; i < nb_input_streams; i++) { | |
159 | ist = input_streams[i]; | |
41776ba9 | 160 | if (ist->dec_ctx->codec_type == type && ist->discard) |
fe2147e9 AK |
161 | break; |
162 | } | |
163 | if (i == nb_input_streams) { | |
164 | av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for " | |
d28fc7b2 | 165 | "unlabeled input pad %d on filter %s\n", in->pad_idx, |
fe2147e9 | 166 | in->filter_ctx->name); |
5e3f9979 | 167 | exit(1); |
fe2147e9 AK |
168 | } |
169 | } | |
170 | av_assert0(ist); | |
171 | ||
172 | ist->discard = 0; | |
173 | ist->decoding_needed = 1; | |
174 | ist->st->discard = AVDISCARD_NONE; | |
175 | ||
10bca661 | 176 | GROW_ARRAY(fg->inputs, fg->nb_inputs); |
fe2147e9 | 177 | if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0])))) |
5e3f9979 | 178 | exit(1); |
fe2147e9 AK |
179 | fg->inputs[fg->nb_inputs - 1]->ist = ist; |
180 | fg->inputs[fg->nb_inputs - 1]->graph = fg; | |
722ec3eb | 181 | fg->inputs[fg->nb_inputs - 1]->format = -1; |
fe2147e9 | 182 | |
a3a0230a AK |
183 | fg->inputs[fg->nb_inputs - 1]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*)); |
184 | if (!fg->inputs[fg->nb_inputs - 1]) | |
185 | exit_program(1); | |
186 | ||
10bca661 | 187 | GROW_ARRAY(ist->filters, ist->nb_filters); |
fe2147e9 AK |
188 | ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1]; |
189 | } | |
190 | ||
6d592fbd AK |
191 | int init_complex_filtergraph(FilterGraph *fg) |
192 | { | |
193 | AVFilterInOut *inputs, *outputs, *cur; | |
194 | AVFilterGraph *graph; | |
195 | int ret = 0; | |
196 | ||
197 | /* this graph is only used for determining the kinds of inputs | |
198 | * and outputs we have, and is discarded on exit from this function */ | |
199 | graph = avfilter_graph_alloc(); | |
200 | if (!graph) | |
201 | return AVERROR(ENOMEM); | |
202 | ||
203 | ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs); | |
204 | if (ret < 0) | |
205 | goto fail; | |
206 | ||
207 | for (cur = inputs; cur; cur = cur->next) | |
208 | init_input_filter(fg, cur); | |
209 | ||
210 | for (cur = outputs; cur;) { | |
211 | GROW_ARRAY(fg->outputs, fg->nb_outputs); | |
212 | fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0])); | |
213 | if (!fg->outputs[fg->nb_outputs - 1]) | |
214 | exit(1); | |
215 | ||
216 | fg->outputs[fg->nb_outputs - 1]->graph = fg; | |
217 | fg->outputs[fg->nb_outputs - 1]->out_tmp = cur; | |
218 | fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads, | |
219 | cur->pad_idx); | |
220 | cur = cur->next; | |
221 | fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL; | |
222 | } | |
223 | ||
224 | fail: | |
225 | avfilter_inout_free(&inputs); | |
226 | avfilter_graph_free(&graph); | |
227 | return ret; | |
228 | } | |
229 | ||
811bd078 AK |
230 | static int insert_trim(int64_t start_time, int64_t duration, |
231 | AVFilterContext **last_filter, int *pad_idx, | |
232 | const char *filter_name) | |
a83c0da5 | 233 | { |
a83c0da5 AK |
234 | AVFilterGraph *graph = (*last_filter)->graph; |
235 | AVFilterContext *ctx; | |
236 | const AVFilter *trim; | |
811bd078 AK |
237 | enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx); |
238 | const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim"; | |
a83c0da5 AK |
239 | int ret = 0; |
240 | ||
811bd078 | 241 | if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE) |
a83c0da5 AK |
242 | return 0; |
243 | ||
244 | trim = avfilter_get_by_name(name); | |
245 | if (!trim) { | |
246 | av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit " | |
247 | "recording time.\n", name); | |
248 | return AVERROR_FILTER_NOT_FOUND; | |
249 | } | |
250 | ||
a83c0da5 AK |
251 | ctx = avfilter_graph_alloc_filter(graph, trim, filter_name); |
252 | if (!ctx) | |
253 | return AVERROR(ENOMEM); | |
254 | ||
811bd078 AK |
255 | if (duration != INT64_MAX) { |
256 | ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6, | |
8cd472d3 AK |
257 | AV_OPT_SEARCH_CHILDREN); |
258 | } | |
811bd078 AK |
259 | if (ret >= 0 && start_time != AV_NOPTS_VALUE) { |
260 | ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6, | |
8cd472d3 AK |
261 | AV_OPT_SEARCH_CHILDREN); |
262 | } | |
a83c0da5 AK |
263 | if (ret < 0) { |
264 | av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name); | |
265 | return ret; | |
266 | } | |
267 | ||
268 | ret = avfilter_init_str(ctx, NULL); | |
269 | if (ret < 0) | |
270 | return ret; | |
271 | ||
272 | ret = avfilter_link(*last_filter, *pad_idx, ctx, 0); | |
273 | if (ret < 0) | |
274 | return ret; | |
275 | ||
276 | *last_filter = ctx; | |
277 | *pad_idx = 0; | |
278 | return 0; | |
279 | } | |
280 | ||
16302246 MS |
281 | static int insert_filter(AVFilterContext **last_filter, int *pad_idx, |
282 | const char *filter_name, const char *args) | |
283 | { | |
284 | AVFilterGraph *graph = (*last_filter)->graph; | |
285 | AVFilterContext *ctx; | |
286 | int ret; | |
287 | ||
288 | ret = avfilter_graph_create_filter(&ctx, | |
289 | avfilter_get_by_name(filter_name), | |
290 | filter_name, args, NULL, graph); | |
291 | if (ret < 0) | |
292 | return ret; | |
293 | ||
294 | ret = avfilter_link(*last_filter, *pad_idx, ctx, 0); | |
295 | if (ret < 0) | |
296 | return ret; | |
297 | ||
298 | *last_filter = ctx; | |
299 | *pad_idx = 0; | |
300 | return 0; | |
301 | } | |
302 | ||
fe2147e9 AK |
303 | static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) |
304 | { | |
305 | char *pix_fmts; | |
306 | OutputStream *ost = ofilter->ost; | |
811bd078 | 307 | OutputFile *of = output_files[ost->file_index]; |
fe2147e9 AK |
308 | AVFilterContext *last_filter = out->filter_ctx; |
309 | int pad_idx = out->pad_idx; | |
310 | int ret; | |
311 | char name[255]; | |
312 | ||
313 | snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); | |
314 | ret = avfilter_graph_create_filter(&ofilter->filter, | |
315 | avfilter_get_by_name("buffersink"), | |
58dee6e6 | 316 | name, NULL, NULL, fg->graph); |
fe2147e9 AK |
317 | if (ret < 0) |
318 | return ret; | |
319 | ||
bd31c61c | 320 | if (ofilter->width || ofilter->height) { |
fe2147e9 AK |
321 | char args[255]; |
322 | AVFilterContext *filter; | |
323 | ||
72fbc968 | 324 | snprintf(args, sizeof(args), "%d:%d:0x%X", |
50722b4f | 325 | ofilter->width, ofilter->height, |
fe2147e9 AK |
326 | (unsigned)ost->sws_flags); |
327 | snprintf(name, sizeof(name), "scaler for output stream %d:%d", | |
328 | ost->file_index, ost->index); | |
329 | if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), | |
330 | name, args, NULL, fg->graph)) < 0) | |
331 | return ret; | |
332 | if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) | |
333 | return ret; | |
334 | ||
335 | last_filter = filter; | |
336 | pad_idx = 0; | |
337 | } | |
338 | ||
50722b4f | 339 | if ((pix_fmts = choose_pix_fmts(ofilter))) { |
fe2147e9 AK |
340 | AVFilterContext *filter; |
341 | snprintf(name, sizeof(name), "pixel format for output stream %d:%d", | |
342 | ost->file_index, ost->index); | |
c802a2e7 VG |
343 | ret = avfilter_graph_create_filter(&filter, |
344 | avfilter_get_by_name("format"), | |
345 | "format", pix_fmts, NULL, fg->graph); | |
346 | av_freep(&pix_fmts); | |
347 | if (ret < 0) | |
fe2147e9 AK |
348 | return ret; |
349 | if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) | |
350 | return ret; | |
351 | ||
352 | last_filter = filter; | |
353 | pad_idx = 0; | |
fe2147e9 AK |
354 | } |
355 | ||
356 | if (ost->frame_rate.num) { | |
357 | AVFilterContext *fps; | |
358 | char args[255]; | |
359 | ||
360 | snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num, | |
361 | ost->frame_rate.den); | |
362 | snprintf(name, sizeof(name), "fps for output stream %d:%d", | |
363 | ost->file_index, ost->index); | |
364 | ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"), | |
365 | name, args, NULL, fg->graph); | |
366 | if (ret < 0) | |
367 | return ret; | |
368 | ||
369 | ret = avfilter_link(last_filter, pad_idx, fps, 0); | |
370 | if (ret < 0) | |
371 | return ret; | |
372 | last_filter = fps; | |
373 | pad_idx = 0; | |
374 | } | |
375 | ||
811bd078 AK |
376 | snprintf(name, sizeof(name), "trim for output stream %d:%d", |
377 | ost->file_index, ost->index); | |
378 | ret = insert_trim(of->start_time, of->recording_time, | |
379 | &last_filter, &pad_idx, name); | |
a83c0da5 AK |
380 | if (ret < 0) |
381 | return ret; | |
382 | ||
383 | ||
fe2147e9 AK |
384 | if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) |
385 | return ret; | |
386 | ||
387 | return 0; | |
388 | } | |
389 | ||
390 | static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) | |
391 | { | |
392 | OutputStream *ost = ofilter->ost; | |
811bd078 | 393 | OutputFile *of = output_files[ost->file_index]; |
38313626 | 394 | AVCodecContext *codec = ost->enc_ctx; |
fe2147e9 AK |
395 | AVFilterContext *last_filter = out->filter_ctx; |
396 | int pad_idx = out->pad_idx; | |
397 | char *sample_fmts, *sample_rates, *channel_layouts; | |
398 | char name[255]; | |
399 | int ret; | |
400 | ||
401 | ||
402 | snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); | |
403 | ret = avfilter_graph_create_filter(&ofilter->filter, | |
404 | avfilter_get_by_name("abuffersink"), | |
405 | name, NULL, NULL, fg->graph); | |
406 | if (ret < 0) | |
407 | return ret; | |
408 | ||
409 | if (codec->channels && !codec->channel_layout) | |
410 | codec->channel_layout = av_get_default_channel_layout(codec->channels); | |
411 | ||
50722b4f AK |
412 | sample_fmts = choose_sample_fmts(ofilter); |
413 | sample_rates = choose_sample_rates(ofilter); | |
414 | channel_layouts = choose_channel_layouts(ofilter); | |
fe2147e9 AK |
415 | if (sample_fmts || sample_rates || channel_layouts) { |
416 | AVFilterContext *format; | |
417 | char args[256]; | |
418 | int len = 0; | |
419 | ||
420 | if (sample_fmts) | |
421 | len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:", | |
422 | sample_fmts); | |
423 | if (sample_rates) | |
424 | len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:", | |
425 | sample_rates); | |
426 | if (channel_layouts) | |
427 | len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:", | |
428 | channel_layouts); | |
429 | args[len - 1] = 0; | |
430 | ||
431 | av_freep(&sample_fmts); | |
432 | av_freep(&sample_rates); | |
433 | av_freep(&channel_layouts); | |
434 | ||
435 | snprintf(name, sizeof(name), "audio format for output stream %d:%d", | |
436 | ost->file_index, ost->index); | |
437 | ret = avfilter_graph_create_filter(&format, | |
438 | avfilter_get_by_name("aformat"), | |
439 | name, args, NULL, fg->graph); | |
440 | if (ret < 0) | |
441 | return ret; | |
442 | ||
443 | ret = avfilter_link(last_filter, pad_idx, format, 0); | |
444 | if (ret < 0) | |
445 | return ret; | |
446 | ||
447 | last_filter = format; | |
448 | pad_idx = 0; | |
449 | } | |
450 | ||
811bd078 AK |
451 | snprintf(name, sizeof(name), "trim for output stream %d:%d", |
452 | ost->file_index, ost->index); | |
453 | ret = insert_trim(of->start_time, of->recording_time, | |
454 | &last_filter, &pad_idx, name); | |
a83c0da5 AK |
455 | if (ret < 0) |
456 | return ret; | |
457 | ||
fe2147e9 AK |
458 | if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) |
459 | return ret; | |
460 | ||
461 | return 0; | |
462 | } | |
463 | ||
464 | #define DESCRIBE_FILTER_LINK(f, inout, in) \ | |
465 | { \ | |
466 | AVFilterContext *ctx = inout->filter_ctx; \ | |
467 | AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \ | |
06cd4c5a | 468 | int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \ |
fe2147e9 AK |
469 | AVIOContext *pb; \ |
470 | \ | |
471 | if (avio_open_dyn_buf(&pb) < 0) \ | |
5e3f9979 | 472 | exit(1); \ |
fe2147e9 AK |
473 | \ |
474 | avio_printf(pb, "%s", ctx->filter->name); \ | |
475 | if (nb_pads > 1) \ | |
476 | avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\ | |
477 | avio_w8(pb, 0); \ | |
478 | avio_close_dyn_buf(pb, &f->name); \ | |
479 | } | |
480 | ||
481 | int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) | |
482 | { | |
483 | av_freep(&ofilter->name); | |
484 | DESCRIBE_FILTER_LINK(ofilter, out, 0); | |
485 | ||
486 | switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) { | |
487 | case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out); | |
488 | case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out); | |
489 | default: av_assert0(0); | |
490 | } | |
491 | } | |
492 | ||
493 | static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, | |
494 | AVFilterInOut *in) | |
495 | { | |
2e661f26 | 496 | AVFilterContext *last_filter; |
51fc88e7 | 497 | const AVFilter *buffer_filt = avfilter_get_by_name("buffer"); |
fe2147e9 | 498 | InputStream *ist = ifilter->ist; |
811bd078 | 499 | InputFile *f = input_files[ist->file_index]; |
fe2147e9 AK |
500 | AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) : |
501 | ist->st->time_base; | |
1bf34134 AK |
502 | AVBufferSrcParameters *par; |
503 | char name[255]; | |
811bd078 | 504 | int ret, pad_idx = 0; |
fe2147e9 | 505 | |
fe2147e9 AK |
506 | snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, |
507 | ist->file_index, ist->st->index); | |
508 | ||
1bf34134 AK |
509 | ifilter->filter = avfilter_graph_alloc_filter(fg->graph, buffer_filt, name); |
510 | if (!ifilter->filter) | |
511 | return AVERROR(ENOMEM); | |
512 | ||
513 | par = av_buffersrc_parameters_alloc(); | |
514 | if (!par) | |
515 | return AVERROR(ENOMEM); | |
516 | ||
722ec3eb AK |
517 | par->sample_aspect_ratio = ifilter->sample_aspect_ratio; |
518 | par->width = ifilter->width; | |
519 | par->height = ifilter->height; | |
520 | par->format = ifilter->format; | |
1bf34134 | 521 | par->time_base = tb; |
722ec3eb | 522 | par->hw_frames_ctx = ifilter->hw_frames_ctx; |
1bf34134 AK |
523 | |
524 | ret = av_buffersrc_parameters_set(ifilter->filter, par); | |
525 | av_freep(&par); | |
526 | if (ret < 0) | |
527 | return ret; | |
528 | ||
529 | ret = avfilter_init_str(ifilter->filter, NULL); | |
530 | if (ret < 0) | |
fe2147e9 | 531 | return ret; |
1bf34134 | 532 | |
2e661f26 | 533 | last_filter = ifilter->filter; |
fe2147e9 | 534 | |
16302246 MS |
535 | if (ist->autorotate) { |
536 | uint8_t* displaymatrix = av_stream_get_side_data(ist->st, | |
537 | AV_PKT_DATA_DISPLAYMATRIX, NULL); | |
538 | if (displaymatrix) { | |
539 | double rot = av_display_rotation_get((int32_t*) displaymatrix); | |
540 | if (rot < -135 || rot > 135) { | |
541 | ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL); | |
542 | if (ret < 0) | |
543 | return ret; | |
544 | ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL); | |
545 | } else if (rot < -45) { | |
546 | ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=clock"); | |
547 | } else if (rot > 45) { | |
548 | ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=cclock"); | |
549 | } | |
550 | if (ret < 0) | |
551 | return ret; | |
552 | } | |
553 | } | |
554 | ||
fe2147e9 AK |
555 | if (ist->framerate.num) { |
556 | AVFilterContext *setpts; | |
557 | ||
558 | snprintf(name, sizeof(name), "force CFR for input from stream %d:%d", | |
559 | ist->file_index, ist->st->index); | |
560 | if ((ret = avfilter_graph_create_filter(&setpts, | |
561 | avfilter_get_by_name("setpts"), | |
562 | name, "N", NULL, | |
563 | fg->graph)) < 0) | |
564 | return ret; | |
565 | ||
2e661f26 | 566 | if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0) |
fe2147e9 AK |
567 | return ret; |
568 | ||
2e661f26 | 569 | last_filter = setpts; |
fe2147e9 AK |
570 | } |
571 | ||
811bd078 AK |
572 | snprintf(name, sizeof(name), "trim for input stream %d:%d", |
573 | ist->file_index, ist->st->index); | |
574 | ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? | |
488a0fa6 | 575 | AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name); |
811bd078 AK |
576 | if (ret < 0) |
577 | return ret; | |
578 | ||
2e661f26 | 579 | if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) |
fe2147e9 AK |
580 | return ret; |
581 | return 0; | |
582 | } | |
583 | ||
584 | static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, | |
585 | AVFilterInOut *in) | |
586 | { | |
2e661f26 | 587 | AVFilterContext *last_filter; |
51fc88e7 | 588 | const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer"); |
fe2147e9 | 589 | InputStream *ist = ifilter->ist; |
811bd078 | 590 | InputFile *f = input_files[ist->file_index]; |
1bf34134 | 591 | AVBufferSrcParameters *par; |
fe2147e9 | 592 | char args[255], name[255]; |
811bd078 | 593 | int ret, pad_idx = 0; |
fe2147e9 | 594 | |
fe2147e9 AK |
595 | snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, |
596 | ist->file_index, ist->st->index); | |
597 | ||
1bf34134 AK |
598 | ifilter->filter = avfilter_graph_alloc_filter(fg->graph, abuffer_filt, name); |
599 | if (!ifilter->filter) | |
600 | return AVERROR(ENOMEM); | |
601 | ||
602 | par = av_buffersrc_parameters_alloc(); | |
603 | if (!par) | |
604 | return AVERROR(ENOMEM); | |
605 | ||
722ec3eb AK |
606 | par->time_base = (AVRational){ 1, ifilter->sample_rate }; |
607 | par->sample_rate = ifilter->sample_rate; | |
608 | par->format = ifilter->format; | |
609 | par->channel_layout = ifilter->channel_layout; | |
1bf34134 AK |
610 | |
611 | ret = av_buffersrc_parameters_set(ifilter->filter, par); | |
612 | av_freep(&par); | |
613 | if (ret < 0) | |
614 | return ret; | |
615 | ||
616 | ret = avfilter_init_str(ifilter->filter, NULL); | |
617 | if (ret < 0) | |
fe2147e9 | 618 | return ret; |
2e661f26 | 619 | last_filter = ifilter->filter; |
fe2147e9 AK |
620 | |
621 | if (audio_sync_method > 0) { | |
622 | AVFilterContext *async; | |
fe2147e9 AK |
623 | int len = 0; |
624 | ||
625 | av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the " | |
626 | "asyncts audio filter instead.\n"); | |
627 | ||
628 | if (audio_sync_method > 1) | |
629 | len += snprintf(args + len, sizeof(args) - len, "compensate=1:" | |
630 | "max_comp=%d:", audio_sync_method); | |
631 | snprintf(args + len, sizeof(args) - len, "min_delta=%f", | |
632 | audio_drift_threshold); | |
633 | ||
634 | snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d", | |
635 | fg->index, ist->file_index, ist->st->index); | |
636 | ret = avfilter_graph_create_filter(&async, | |
637 | avfilter_get_by_name("asyncts"), | |
638 | name, args, NULL, fg->graph); | |
639 | if (ret < 0) | |
640 | return ret; | |
641 | ||
2e661f26 | 642 | ret = avfilter_link(last_filter, 0, async, 0); |
fe2147e9 AK |
643 | if (ret < 0) |
644 | return ret; | |
645 | ||
2e661f26 | 646 | last_filter = async; |
fe2147e9 | 647 | } |
9a71d362 JR |
648 | if (audio_volume != 256) { |
649 | AVFilterContext *volume; | |
650 | ||
651 | av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume " | |
652 | "audio filter instead.\n"); | |
653 | ||
654 | snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0); | |
655 | ||
656 | snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d", | |
657 | fg->index, ist->file_index, ist->st->index); | |
658 | ret = avfilter_graph_create_filter(&volume, | |
659 | avfilter_get_by_name("volume"), | |
660 | name, args, NULL, fg->graph); | |
661 | if (ret < 0) | |
662 | return ret; | |
663 | ||
2e661f26 | 664 | ret = avfilter_link(last_filter, 0, volume, 0); |
9a71d362 JR |
665 | if (ret < 0) |
666 | return ret; | |
667 | ||
2e661f26 | 668 | last_filter = volume; |
9a71d362 | 669 | } |
811bd078 AK |
670 | |
671 | snprintf(name, sizeof(name), "trim for input stream %d:%d", | |
672 | ist->file_index, ist->st->index); | |
673 | ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? | |
488a0fa6 | 674 | AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name); |
811bd078 AK |
675 | if (ret < 0) |
676 | return ret; | |
677 | ||
2e661f26 | 678 | if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) |
fe2147e9 AK |
679 | return ret; |
680 | ||
681 | return 0; | |
682 | } | |
683 | ||
684 | static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter, | |
685 | AVFilterInOut *in) | |
686 | { | |
687 | av_freep(&ifilter->name); | |
688 | DESCRIBE_FILTER_LINK(ifilter, in, 1); | |
689 | ||
690 | switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) { | |
691 | case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in); | |
692 | case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in); | |
693 | default: av_assert0(0); | |
694 | } | |
695 | } | |
696 | ||
697 | int configure_filtergraph(FilterGraph *fg) | |
698 | { | |
699 | AVFilterInOut *inputs, *outputs, *cur; | |
49670e42 | 700 | int ret, i, simple = filtergraph_is_simple(fg); |
fe2147e9 AK |
701 | const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter : |
702 | fg->graph_desc; | |
703 | ||
704 | avfilter_graph_free(&fg->graph); | |
705 | if (!(fg->graph = avfilter_graph_alloc())) | |
706 | return AVERROR(ENOMEM); | |
707 | ||
708 | if (simple) { | |
709 | OutputStream *ost = fg->outputs[0]->ost; | |
5c7db097 JR |
710 | char args[512]; |
711 | AVDictionaryEntry *e = NULL; | |
5c7db097 | 712 | |
fe2147e9 AK |
713 | snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); |
714 | fg->graph->scale_sws_opts = av_strdup(args); | |
5c7db097 JR |
715 | |
716 | args[0] = '\0'; | |
717 | while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e, | |
718 | AV_DICT_IGNORE_SUFFIX))) { | |
719 | av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value); | |
720 | } | |
721 | if (strlen(args)) | |
722 | args[strlen(args) - 1] = '\0'; | |
723 | fg->graph->resample_lavr_opts = av_strdup(args); | |
fe2147e9 AK |
724 | } |
725 | ||
726 | if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) | |
727 | return ret; | |
728 | ||
5d273d3e MT |
729 | if (hw_device_ctx) { |
730 | for (i = 0; i < fg->graph->nb_filters; i++) { | |
731 | fg->graph->filters[i]->hw_device_ctx = av_buffer_ref(hw_device_ctx); | |
732 | } | |
733 | } | |
734 | ||
fe2147e9 AK |
735 | if (simple && (!inputs || inputs->next || !outputs || outputs->next)) { |
736 | av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have " | |
737 | "exactly one input and output.\n", graph_desc); | |
738 | return AVERROR(EINVAL); | |
739 | } | |
740 | ||
fe2147e9 AK |
741 | for (cur = inputs, i = 0; cur; cur = cur->next, i++) |
742 | if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) | |
743 | return ret; | |
744 | avfilter_inout_free(&inputs); | |
745 | ||
8b830ee9 LB |
746 | for (cur = outputs, i = 0; cur; cur = cur->next, i++) { |
747 | OutputFilter *ofilter = fg->outputs[i]; | |
748 | if (ofilter->ost) | |
749 | configure_output_filter(fg, ofilter, cur); | |
750 | } | |
751 | ||
6d592fbd | 752 | avfilter_inout_free(&outputs); |
fe2147e9 | 753 | |
6d592fbd AK |
754 | if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) |
755 | return ret; | |
fe2147e9 | 756 | |
50722b4f AK |
757 | /* limit the lists of allowed formats to the ones selected, to |
758 | * make sure they stay the same if the filtergraph is reconfigured later */ | |
759 | for (i = 0; i < fg->nb_outputs; i++) { | |
760 | OutputFilter *ofilter = fg->outputs[i]; | |
761 | AVFilterLink *link = ofilter->filter->inputs[0]; | |
762 | ||
763 | ofilter->format = link->format; | |
764 | ||
765 | ofilter->width = link->w; | |
766 | ofilter->height = link->h; | |
767 | ||
768 | ofilter->sample_rate = link->sample_rate; | |
769 | ofilter->channel_layout = link->channel_layout; | |
770 | } | |
771 | ||
fe2147e9 AK |
772 | return 0; |
773 | } | |
774 | ||
722ec3eb AK |
775 | int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame) |
776 | { | |
777 | av_buffer_unref(&ifilter->hw_frames_ctx); | |
778 | ||
779 | ifilter->format = frame->format; | |
780 | ||
781 | ifilter->width = frame->width; | |
782 | ifilter->height = frame->height; | |
783 | ifilter->sample_aspect_ratio = frame->sample_aspect_ratio; | |
784 | ||
785 | ifilter->sample_rate = frame->sample_rate; | |
786 | ifilter->channel_layout = frame->channel_layout; | |
787 | ||
788 | if (frame->hw_frames_ctx) { | |
789 | ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx); | |
790 | if (!ifilter->hw_frames_ctx) | |
791 | return AVERROR(ENOMEM); | |
792 | } | |
793 | ||
794 | return 0; | |
795 | } | |
796 | ||
fe2147e9 AK |
797 | int ist_in_filtergraph(FilterGraph *fg, InputStream *ist) |
798 | { | |
799 | int i; | |
800 | for (i = 0; i < fg->nb_inputs; i++) | |
801 | if (fg->inputs[i]->ist == ist) | |
802 | return 1; | |
803 | return 0; | |
804 | } | |
805 | ||
49670e42 AK |
806 | int filtergraph_is_simple(FilterGraph *fg) |
807 | { | |
808 | return !fg->graph_desc; | |
809 | } |