FFmpegKit iOS / macOS / tvOS API 4.5
fftools_ffmpeg_filter.c
Go to the documentation of this file.
1/*
2 * ffmpeg filter configuration
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 * CHANGES 08.2018
23 * --------------------------------------------------------
24 * - fftools_ prefix added to file name and parent header
25 *
26 * CHANGES 07.2018
27 * --------------------------------------------------------
28 * - Unused headers removed
29 */
30
31#include <stdint.h>
32
33#include "fftools_ffmpeg.h"
34
35#include "libavfilter/avfilter.h"
36#include "libavfilter/buffersink.h"
37#include "libavfilter/buffersrc.h"
38
39#include "libavutil/avassert.h"
40#include "libavutil/avstring.h"
41#include "libavutil/bprint.h"
42#include "libavutil/channel_layout.h"
43#include "libavutil/display.h"
44#include "libavutil/opt.h"
45#include "libavutil/pixdesc.h"
46#include "libavutil/pixfmt.h"
47#include "libavutil/imgutils.h"
48#include "libavutil/samplefmt.h"
49
50// FIXME: YUV420P etc. are actually supported with full color range,
51// yet the latter information isn't available here.
52static const enum AVPixelFormat *get_compliance_normal_pix_fmts(const AVCodec *codec, const enum AVPixelFormat default_formats[])
53{
54 static const enum AVPixelFormat mjpeg_formats[] =
55 { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
56 AV_PIX_FMT_NONE};
57
58 if (!strcmp(codec->name, "mjpeg")) {
59 return mjpeg_formats;
60 } else {
61 return default_formats;
62 }
63}
64
65enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, const AVCodec *codec, enum AVPixelFormat target)
66{
67 if (codec && codec->pix_fmts) {
68 const enum AVPixelFormat *p = codec->pix_fmts;
69 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);
70 //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented
71 int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;
72 enum AVPixelFormat best= AV_PIX_FMT_NONE;
73
74 if (enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
76 }
77 for (; *p != AV_PIX_FMT_NONE; p++) {
78 best = av_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);
79 if (*p == target)
80 break;
81 }
82 if (*p == AV_PIX_FMT_NONE) {
83 if (target != AV_PIX_FMT_NONE)
84 av_log(NULL, AV_LOG_WARNING,
85 "Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\n",
86 av_get_pix_fmt_name(target),
87 codec->name,
88 av_get_pix_fmt_name(best));
89 return best;
90 }
91 }
92 return target;
93}
94
95static char *choose_pix_fmts(OutputFilter *ofilter)
96{
97 OutputStream *ost = ofilter->ost;
98 AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
99 if (strict_dict)
100 // used by choose_pixel_fmt() and below
101 av_opt_set(ost->enc_ctx, "strict", strict_dict->value, 0);
102
103 if (ost->keep_pix_fmt) {
104 avfilter_graph_set_auto_convert(ofilter->graph->graph,
105 AVFILTER_AUTO_CONVERT_NONE);
106 if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE)
107 return NULL;
108 return av_strdup(av_get_pix_fmt_name(ost->enc_ctx->pix_fmt));
109 }
110 if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
111 return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt)));
112 } else if (ost->enc && ost->enc->pix_fmts) {
113 const enum AVPixelFormat *p;
114 AVIOContext *s = NULL;
115 uint8_t *ret;
116 int len;
117
118 if (avio_open_dyn_buf(&s) < 0)
119 exit_program(1);
120
121 p = ost->enc->pix_fmts;
122 if (ost->enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
124 }
125
126 for (; *p != AV_PIX_FMT_NONE; p++) {
127 const char *name = av_get_pix_fmt_name(*p);
128 avio_printf(s, "%s|", name);
129 }
130 len = avio_close_dyn_buf(s, &ret);
131 ret[len - 1] = 0;
132 return ret;
133 } else
134 return NULL;
135}
136
137/* Define a function for appending a list of allowed formats
138 * to an AVBPrint. If nonempty, the list will have a header. */
139#define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \
140static void choose_ ## name (OutputFilter *ofilter, AVBPrint *bprint) \
141{ \
142 if (ofilter->var == none && !ofilter->supported_list) \
143 return; \
144 av_bprintf(bprint, #name "="); \
145 if (ofilter->var != none) { \
146 av_bprintf(bprint, printf_format, get_name(ofilter->var)); \
147 } else { \
148 const type *p; \
149 \
150 for (p = ofilter->supported_list; *p != none; p++) { \
151 av_bprintf(bprint, printf_format "|", get_name(*p)); \
152 } \
153 if (bprint->len > 0) \
154 bprint->str[--bprint->len] = '\0'; \
155 } \
156 av_bprint_chars(bprint, ':', 1); \
157}
158
159//DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE,
160// GET_PIX_FMT_NAME)
161
162DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats,
163 AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name)
164
166 "%d", )
167
168DEF_CHOOSE_FORMAT(channel_layouts, uint64_t, channel_layout, channel_layouts, 0,
169 "0x%"PRIx64, )
170
172{
173 FilterGraph *fg = av_mallocz(sizeof(*fg));
174
175 if (!fg)
176 exit_program(1);
178
180 if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
181 exit_program(1);
182 fg->outputs[0]->ost = ost;
183 fg->outputs[0]->graph = fg;
184 fg->outputs[0]->format = -1;
185
186 ost->filter = fg->outputs[0];
187
188 GROW_ARRAY(fg->inputs, fg->nb_inputs);
189 if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
190 exit_program(1);
191 fg->inputs[0]->ist = ist;
192 fg->inputs[0]->graph = fg;
193 fg->inputs[0]->format = -1;
194
195 fg->inputs[0]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
196 if (!fg->inputs[0]->frame_queue)
197 exit_program(1);
198
199 GROW_ARRAY(ist->filters, ist->nb_filters);
200 ist->filters[ist->nb_filters - 1] = fg->inputs[0];
201
204
205 return 0;
206}
207
208static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
209{
210 AVFilterContext *ctx = inout->filter_ctx;
211 AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
212 int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
213 AVIOContext *pb;
214 uint8_t *res = NULL;
215
216 if (avio_open_dyn_buf(&pb) < 0)
217 exit_program(1);
218
219 avio_printf(pb, "%s", ctx->filter->name);
220 if (nb_pads > 1)
221 avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));
222 avio_w8(pb, 0);
223 avio_close_dyn_buf(pb, &res);
224 return res;
225}
226
227static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
228{
229 InputStream *ist = NULL;
230 enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
231 int i;
232
233 // TODO: support other filter types
234 if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
235 av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
236 "currently.\n");
237 exit_program(1);
238 }
239
240 if (in->name) {
241 AVFormatContext *s;
242 AVStream *st = NULL;
243 char *p;
244 int file_idx = strtol(in->name, &p, 0);
245
246 if (file_idx < 0 || file_idx >= nb_input_files) {
247 av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
248 file_idx, fg->graph_desc);
249 exit_program(1);
250 }
251 s = input_files[file_idx]->ctx;
252
253 for (i = 0; i < s->nb_streams; i++) {
254 enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
255 if (stream_type != type &&
256 !(stream_type == AVMEDIA_TYPE_SUBTITLE &&
257 type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
258 continue;
259 if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
260 st = s->streams[i];
261 break;
262 }
263 }
264 if (!st) {
265 av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
266 "matches no streams.\n", p, fg->graph_desc);
267 exit_program(1);
268 }
269 ist = input_streams[input_files[file_idx]->ist_index + st->index];
270 if (ist->user_set_discard == AVDISCARD_ALL) {
271 av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
272 "matches a disabled input stream.\n", p, fg->graph_desc);
273 exit_program(1);
274 }
275 } else {
276 /* find the first unused stream of corresponding type */
277 for (i = 0; i < nb_input_streams; i++) {
278 ist = input_streams[i];
279 if (ist->user_set_discard == AVDISCARD_ALL)
280 continue;
281 if (ist->dec_ctx->codec_type == type && ist->discard)
282 break;
283 }
284 if (i == nb_input_streams) {
285 av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
286 "unlabeled input pad %d on filter %s\n", in->pad_idx,
287 in->filter_ctx->name);
288 exit_program(1);
289 }
290 }
291 av_assert0(ist);
292
293 ist->discard = 0;
294 ist->decoding_needed |= DECODING_FOR_FILTER;
295 ist->st->discard = AVDISCARD_NONE;
296
297 GROW_ARRAY(fg->inputs, fg->nb_inputs);
298 if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
299 exit_program(1);
300 fg->inputs[fg->nb_inputs - 1]->ist = ist;
301 fg->inputs[fg->nb_inputs - 1]->graph = fg;
302 fg->inputs[fg->nb_inputs - 1]->format = -1;
303 fg->inputs[fg->nb_inputs - 1]->type = ist->st->codecpar->codec_type;
304 fg->inputs[fg->nb_inputs - 1]->name = describe_filter_link(fg, in, 1);
305
306 fg->inputs[fg->nb_inputs - 1]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
307 if (!fg->inputs[fg->nb_inputs - 1]->frame_queue)
308 exit_program(1);
309
310 GROW_ARRAY(ist->filters, ist->nb_filters);
311 ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
312}
313
315{
316 AVFilterInOut *inputs, *outputs, *cur;
317 AVFilterGraph *graph;
318 int ret = 0;
319
320 /* this graph is only used for determining the kinds of inputs
321 * and outputs we have, and is discarded on exit from this function */
322 graph = avfilter_graph_alloc();
323 if (!graph)
324 return AVERROR(ENOMEM);
325 graph->nb_threads = 1;
326
327 ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs);
328 if (ret < 0)
329 goto fail;
330
331 for (cur = inputs; cur; cur = cur->next)
332 init_input_filter(fg, cur);
333
334 for (cur = outputs; cur;) {
335 GROW_ARRAY(fg->outputs, fg->nb_outputs);
336 fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]));
337 if (!fg->outputs[fg->nb_outputs - 1])
338 exit_program(1);
339
340 fg->outputs[fg->nb_outputs - 1]->graph = fg;
341 fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
342 fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
343 cur->pad_idx);
344 fg->outputs[fg->nb_outputs - 1]->name = describe_filter_link(fg, cur, 0);
345 cur = cur->next;
346 fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
347 }
348
349fail:
350 avfilter_inout_free(&inputs);
351 avfilter_graph_free(&graph);
352 return ret;
353}
354
355static int insert_trim(int64_t start_time, int64_t duration,
356 AVFilterContext **last_filter, int *pad_idx,
357 const char *filter_name)
358{
359 AVFilterGraph *graph = (*last_filter)->graph;
360 AVFilterContext *ctx;
361 const AVFilter *trim;
362 enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
363 const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
364 int ret = 0;
365
366 if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
367 return 0;
368
369 trim = avfilter_get_by_name(name);
370 if (!trim) {
371 av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
372 "recording time.\n", name);
373 return AVERROR_FILTER_NOT_FOUND;
374 }
375
376 ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
377 if (!ctx)
378 return AVERROR(ENOMEM);
379
380 if (duration != INT64_MAX) {
381 ret = av_opt_set_int(ctx, "durationi", duration,
382 AV_OPT_SEARCH_CHILDREN);
383 }
384 if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
385 ret = av_opt_set_int(ctx, "starti", start_time,
386 AV_OPT_SEARCH_CHILDREN);
387 }
388 if (ret < 0) {
389 av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name);
390 return ret;
391 }
392
393 ret = avfilter_init_str(ctx, NULL);
394 if (ret < 0)
395 return ret;
396
397 ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
398 if (ret < 0)
399 return ret;
400
401 *last_filter = ctx;
402 *pad_idx = 0;
403 return 0;
404}
405
406static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
407 const char *filter_name, const char *args)
408{
409 AVFilterGraph *graph = (*last_filter)->graph;
410 AVFilterContext *ctx;
411 int ret;
412
413 ret = avfilter_graph_create_filter(&ctx,
414 avfilter_get_by_name(filter_name),
415 filter_name, args, NULL, graph);
416 if (ret < 0)
417 return ret;
418
419 ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
420 if (ret < 0)
421 return ret;
422
423 *last_filter = ctx;
424 *pad_idx = 0;
425 return 0;
426}
427
428static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
429{
430 char *pix_fmts;
431 OutputStream *ost = ofilter->ost;
433 AVFilterContext *last_filter = out->filter_ctx;
434 int pad_idx = out->pad_idx;
435 int ret;
436 char name[255];
437
438 snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
439 ret = avfilter_graph_create_filter(&ofilter->filter,
440 avfilter_get_by_name("buffersink"),
441 name, NULL, NULL, fg->graph);
442
443 if (ret < 0)
444 return ret;
445
446 if ((ofilter->width || ofilter->height) && ofilter->ost->autoscale) {
447 char args[255];
448 AVFilterContext *filter;
449 AVDictionaryEntry *e = NULL;
450
451 snprintf(args, sizeof(args), "%d:%d",
452 ofilter->width, ofilter->height);
453
454 while ((e = av_dict_get(ost->sws_dict, "", e,
455 AV_DICT_IGNORE_SUFFIX))) {
456 av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
457 }
458
459 snprintf(name, sizeof(name), "scaler_out_%d_%d",
461 if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
462 name, args, NULL, fg->graph)) < 0)
463 return ret;
464 if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
465 return ret;
466
467 last_filter = filter;
468 pad_idx = 0;
469 }
470
471 if ((pix_fmts = choose_pix_fmts(ofilter))) {
472 AVFilterContext *filter;
473
474 ret = avfilter_graph_create_filter(&filter,
475 avfilter_get_by_name("format"),
476 "format", pix_fmts, NULL, fg->graph);
477 av_freep(&pix_fmts);
478 if (ret < 0)
479 return ret;
480 if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
481 return ret;
482
483 last_filter = filter;
484 pad_idx = 0;
485 }
486
487 if (ost->frame_rate.num && 0) {
488 AVFilterContext *fps;
489 char args[255];
490
491 snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
492 ost->frame_rate.den);
493 snprintf(name, sizeof(name), "fps_out_%d_%d",
495 ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
496 name, args, NULL, fg->graph);
497 if (ret < 0)
498 return ret;
499
500 ret = avfilter_link(last_filter, pad_idx, fps, 0);
501 if (ret < 0)
502 return ret;
503 last_filter = fps;
504 pad_idx = 0;
505 }
506
507 snprintf(name, sizeof(name), "trim_out_%d_%d",
510 &last_filter, &pad_idx, name);
511 if (ret < 0)
512 return ret;
513
514
515 if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
516 return ret;
517
518 return 0;
519}
520
521static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
522{
523 OutputStream *ost = ofilter->ost;
525 AVCodecContext *codec = ost->enc_ctx;
526 AVFilterContext *last_filter = out->filter_ctx;
527 int pad_idx = out->pad_idx;
528 AVBPrint args;
529 char name[255];
530 int ret;
531
532 snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
533 ret = avfilter_graph_create_filter(&ofilter->filter,
534 avfilter_get_by_name("abuffersink"),
535 name, NULL, NULL, fg->graph);
536 if (ret < 0)
537 return ret;
538 if ((ret = av_opt_set_int(ofilter->filter, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
539 return ret;
540
541#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \
542 AVFilterContext *filt_ctx; \
543 \
544 av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
545 "similarly to -af " filter_name "=%s.\n", arg); \
546 \
547 ret = avfilter_graph_create_filter(&filt_ctx, \
548 avfilter_get_by_name(filter_name), \
549 filter_name, arg, NULL, fg->graph); \
550 if (ret < 0) \
551 goto fail; \
552 \
553 ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0); \
554 if (ret < 0) \
555 goto fail; \
556 \
557 last_filter = filt_ctx; \
558 pad_idx = 0; \
559} while (0)
560 av_bprint_init(&args, 0, AV_BPRINT_SIZE_UNLIMITED);
562 int i;
563 av_bprintf(&args, "0x%"PRIx64,
564 av_get_default_channel_layout(ost->audio_channels_mapped));
565 for (i = 0; i < ost->audio_channels_mapped; i++)
566 if (ost->audio_channels_map[i] != -1)
567 av_bprintf(&args, "|c%d=c%d", i, ost->audio_channels_map[i]);
568
569 AUTO_INSERT_FILTER("-map_channel", "pan", args.str);
570 av_bprint_clear(&args);
571 }
572
573 if (codec->channels && !codec->channel_layout)
574 codec->channel_layout = av_get_default_channel_layout(codec->channels);
575
576 choose_sample_fmts(ofilter, &args);
577 choose_sample_rates(ofilter, &args);
578 choose_channel_layouts(ofilter, &args);
579 if (!av_bprint_is_complete(&args)) {
580 ret = AVERROR(ENOMEM);
581 goto fail;
582 }
583 if (args.len) {
584 AVFilterContext *format;
585
586 snprintf(name, sizeof(name), "format_out_%d_%d",
588 ret = avfilter_graph_create_filter(&format,
589 avfilter_get_by_name("aformat"),
590 name, args.str, NULL, fg->graph);
591 if (ret < 0)
592 goto fail;
593
594 ret = avfilter_link(last_filter, pad_idx, format, 0);
595 if (ret < 0)
596 goto fail;
597
598 last_filter = format;
599 pad_idx = 0;
600 }
601
602 if (ost->apad && of->shortest) {
603 int i;
604
605 for (i=0; i<of->ctx->nb_streams; i++)
606 if (of->ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
607 break;
608
609 if (i<of->ctx->nb_streams) {
610 AUTO_INSERT_FILTER("-apad", "apad", ost->apad);
611 }
612 }
613
614 snprintf(name, sizeof(name), "trim for output stream %d:%d",
617 &last_filter, &pad_idx, name);
618 if (ret < 0)
619 goto fail;
620
621 if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
622 goto fail;
623fail:
624 av_bprint_finalize(&args, NULL);
625
626 return ret;
627}
628
629int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
630{
631 if (!ofilter->ost) {
632 av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", ofilter->name);
633 exit_program(1);
634 }
635
636 switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
637 case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
638 case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
639 default: av_assert0(0); return 0;
640 }
641}
642
644{
645 int i;
646 for (i = 0; i < nb_filtergraphs; i++) {
647 int n;
648 for (n = 0; n < filtergraphs[i]->nb_outputs; n++) {
649 OutputFilter *output = filtergraphs[i]->outputs[n];
650 if (!output->ost) {
651 av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", output->name);
652 exit_program(1);
653 }
654 }
655 }
656}
657
659{
660 AVFormatContext *avf = input_files[ist->file_index]->ctx;
661 int i, w, h;
662
663 /* Compute the size of the canvas for the subtitles stream.
664 If the subtitles codecpar has set a size, use it. Otherwise use the
665 maximum dimensions of the video streams in the same file. */
666 w = ifilter->width;
667 h = ifilter->height;
668 if (!(w && h)) {
669 for (i = 0; i < avf->nb_streams; i++) {
670 if (avf->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
671 w = FFMAX(w, avf->streams[i]->codecpar->width);
672 h = FFMAX(h, avf->streams[i]->codecpar->height);
673 }
674 }
675 if (!(w && h)) {
676 w = FFMAX(w, 720);
677 h = FFMAX(h, 576);
678 }
679 av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
680 }
681 ist->sub2video.w = ifilter->width = w;
682 ist->sub2video.h = ifilter->height = h;
683
684 ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width : ist->sub2video.w;
685 ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
686
687 /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
688 palettes for all rectangles are identical or compatible */
689 ifilter->format = AV_PIX_FMT_RGB32;
690
691 ist->sub2video.frame = av_frame_alloc();
692 if (!ist->sub2video.frame)
693 return AVERROR(ENOMEM);
694 ist->sub2video.last_pts = INT64_MIN;
695 ist->sub2video.end_pts = INT64_MIN;
696
697 /* sub2video structure has been (re-)initialized.
698 Mark it as such so that the system will be
699 initialized with the first received heartbeat. */
700 ist->sub2video.initialize = 1;
701
702 return 0;
703}
704
706 AVFilterInOut *in)
707{
708 AVFilterContext *last_filter;
709 const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
710 InputStream *ist = ifilter->ist;
711 InputFile *f = input_files[ist->file_index];
712 AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
713 ist->st->time_base;
714 AVRational fr = ist->framerate;
715 AVRational sar;
716 AVBPrint args;
717 char name[255];
718 int ret, pad_idx = 0;
719 int64_t tsoffset = 0;
720 AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
721
722 if (!par)
723 return AVERROR(ENOMEM);
724 memset(par, 0, sizeof(*par));
725 par->format = AV_PIX_FMT_NONE;
726
727 if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
728 av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n");
729 ret = AVERROR(EINVAL);
730 goto fail;
731 }
732
733 if (!fr.num)
734 fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
735
736 if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
737 ret = sub2video_prepare(ist, ifilter);
738 if (ret < 0)
739 goto fail;
740 }
741
742 sar = ifilter->sample_aspect_ratio;
743 if(!sar.den)
744 sar = (AVRational){0,1};
745 av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
746 av_bprintf(&args,
747 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
748 "pixel_aspect=%d/%d",
749 ifilter->width, ifilter->height, ifilter->format,
750 tb.num, tb.den, sar.num, sar.den);
751 if (fr.num && fr.den)
752 av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
753 snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
754 ist->file_index, ist->st->index);
755
756
757 if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
758 args.str, NULL, fg->graph)) < 0)
759 goto fail;
760 par->hw_frames_ctx = ifilter->hw_frames_ctx;
761 ret = av_buffersrc_parameters_set(ifilter->filter, par);
762 if (ret < 0)
763 goto fail;
764 av_freep(&par);
765 last_filter = ifilter->filter;
766
767 if (ist->autorotate) {
768 double theta = get_rotation(ist->st);
769
770 if (fabs(theta - 90) < 1.0) {
771 ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock");
772 } else if (fabs(theta - 180) < 1.0) {
773 ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
774 if (ret < 0)
775 return ret;
776 ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
777 } else if (fabs(theta - 270) < 1.0) {
778 ret = insert_filter(&last_filter, &pad_idx, "transpose", "cclock");
779 } else if (fabs(theta) > 1.0) {
780 char rotate_buf[64];
781 snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
782 ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
783 }
784 if (ret < 0)
785 return ret;
786 }
787
788 if (do_deinterlace) {
789 AVFilterContext *yadif;
790
791 snprintf(name, sizeof(name), "deinterlace_in_%d_%d",
792 ist->file_index, ist->st->index);
793 if ((ret = avfilter_graph_create_filter(&yadif,
794 avfilter_get_by_name("yadif"),
795 name, "", NULL,
796 fg->graph)) < 0)
797 return ret;
798
799 if ((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0)
800 return ret;
801
802 last_filter = yadif;
803 }
804
805 snprintf(name, sizeof(name), "trim_in_%d_%d",
806 ist->file_index, ist->st->index);
807 if (copy_ts) {
808 tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
809 if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
810 tsoffset += f->ctx->start_time;
811 }
812 ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
813 AV_NOPTS_VALUE : tsoffset, f->recording_time,
814 &last_filter, &pad_idx, name);
815 if (ret < 0)
816 return ret;
817
818 if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
819 return ret;
820 return 0;
821fail:
822 av_freep(&par);
823
824 return ret;
825}
826
828 AVFilterInOut *in)
829{
830 AVFilterContext *last_filter;
831 const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
832 InputStream *ist = ifilter->ist;
833 InputFile *f = input_files[ist->file_index];
834 AVBPrint args;
835 char name[255];
836 int ret, pad_idx = 0;
837 int64_t tsoffset = 0;
838
839 if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO) {
840 av_log(NULL, AV_LOG_ERROR, "Cannot connect audio filter to non audio input\n");
841 return AVERROR(EINVAL);
842 }
843
844 av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
845 av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
846 1, ifilter->sample_rate,
847 ifilter->sample_rate,
848 av_get_sample_fmt_name(ifilter->format));
849 if (ifilter->channel_layout)
850 av_bprintf(&args, ":channel_layout=0x%"PRIx64,
851 ifilter->channel_layout);
852 else
853 av_bprintf(&args, ":channels=%d", ifilter->channels);
854 snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index,
855 ist->file_index, ist->st->index);
856
857 if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
858 name, args.str, NULL,
859 fg->graph)) < 0)
860 return ret;
861 last_filter = ifilter->filter;
862
863#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do { \
864 AVFilterContext *filt_ctx; \
865 \
866 av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
867 "similarly to -af " filter_name "=%s.\n", arg); \
868 \
869 snprintf(name, sizeof(name), "graph_%d_%s_in_%d_%d", \
870 fg->index, filter_name, ist->file_index, ist->st->index); \
871 ret = avfilter_graph_create_filter(&filt_ctx, \
872 avfilter_get_by_name(filter_name), \
873 name, arg, NULL, fg->graph); \
874 if (ret < 0) \
875 return ret; \
876 \
877 ret = avfilter_link(last_filter, 0, filt_ctx, 0); \
878 if (ret < 0) \
879 return ret; \
880 \
881 last_filter = filt_ctx; \
882} while (0)
883
884 if (audio_sync_method > 0) {
885 char args[256] = {0};
886
887 av_strlcatf(args, sizeof(args), "async=%d", audio_sync_method);
888 if (audio_drift_threshold != 0.1)
889 av_strlcatf(args, sizeof(args), ":min_hard_comp=%f", audio_drift_threshold);
890 if (!fg->reconfiguration)
891 av_strlcatf(args, sizeof(args), ":first_pts=0");
892 AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
893 }
894
895// if (ost->audio_channels_mapped) {
896// int i;
897// AVBPrint pan_buf;
898// av_bprint_init(&pan_buf, 256, 8192);
899// av_bprintf(&pan_buf, "0x%"PRIx64,
900// av_get_default_channel_layout(ost->audio_channels_mapped));
901// for (i = 0; i < ost->audio_channels_mapped; i++)
902// if (ost->audio_channels_map[i] != -1)
903// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
904// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
905// av_bprint_finalize(&pan_buf, NULL);
906// }
907
908 if (audio_volume != 256) {
909 char args[256];
910
911 av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
912 "audio filter instead.\n");
913
914 snprintf(args, sizeof(args), "%f", audio_volume / 256.);
915 AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
916 }
917
918 snprintf(name, sizeof(name), "trim for input stream %d:%d",
919 ist->file_index, ist->st->index);
920 if (copy_ts) {
921 tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
922 if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
923 tsoffset += f->ctx->start_time;
924 }
925 ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
926 AV_NOPTS_VALUE : tsoffset, f->recording_time,
927 &last_filter, &pad_idx, name);
928 if (ret < 0)
929 return ret;
930
931 if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
932 return ret;
933
934 return 0;
935}
936
938 AVFilterInOut *in)
939{
940 if (!ifilter->ist->dec) {
941 av_log(NULL, AV_LOG_ERROR,
942 "No decoder for stream #%d:%d, filtering impossible\n",
943 ifilter->ist->file_index, ifilter->ist->st->index);
944 return AVERROR_DECODER_NOT_FOUND;
945 }
946 switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
947 case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
948 case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
949 default: av_assert0(0); return 0;
950 }
951}
952
954{
955 int i;
956 for (i = 0; i < fg->nb_outputs; i++)
957 fg->outputs[i]->filter = (AVFilterContext *)NULL;
958 for (i = 0; i < fg->nb_inputs; i++)
959 fg->inputs[i]->filter = (AVFilterContext *)NULL;
960 avfilter_graph_free(&fg->graph);
961}
962
964{
965 AVFilterInOut *inputs, *outputs, *cur;
966 int ret, i, simple = filtergraph_is_simple(fg);
967 const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
968 fg->graph_desc;
969
971 if (!(fg->graph = avfilter_graph_alloc()))
972 return AVERROR(ENOMEM);
973
974 if (simple) {
975 OutputStream *ost = fg->outputs[0]->ost;
976 char args[512];
977 AVDictionaryEntry *e = NULL;
978
979 fg->graph->nb_threads = filter_nbthreads;
980
981 args[0] = 0;
982 while ((e = av_dict_get(ost->sws_dict, "", e,
983 AV_DICT_IGNORE_SUFFIX))) {
984 av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
985 }
986 if (strlen(args))
987 args[strlen(args)-1] = 0;
988
989 if (!strncmp(args, "sws_flags=", 10)) {
990 // keep the 'flags=' part
991 fg->graph->scale_sws_opts = av_strdup(args+4);
992 }
993
994 args[0] = 0;
995 while ((e = av_dict_get(ost->swr_opts, "", e,
996 AV_DICT_IGNORE_SUFFIX))) {
997 av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
998 }
999 if (strlen(args))
1000 args[strlen(args)-1] = 0;
1001 av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
1002
1003 args[0] = '\0';
1004 while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
1005 AV_DICT_IGNORE_SUFFIX))) {
1006 av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
1007 }
1008 if (strlen(args))
1009 args[strlen(args) - 1] = '\0';
1010
1011 e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
1012 if (e)
1013 av_opt_set(fg->graph, "threads", e->value, 0);
1014 } else {
1015 fg->graph->nb_threads = filter_complex_nbthreads;
1016 }
1017
1018 if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
1019 goto fail;
1020
1022 if (ret < 0)
1023 goto fail;
1024
1025 if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
1026 const char *num_inputs;
1027 const char *num_outputs;
1028 if (!outputs) {
1029 num_outputs = "0";
1030 } else if (outputs->next) {
1031 num_outputs = ">1";
1032 } else {
1033 num_outputs = "1";
1034 }
1035 if (!inputs) {
1036 num_inputs = "0";
1037 } else if (inputs->next) {
1038 num_inputs = ">1";
1039 } else {
1040 num_inputs = "1";
1041 }
1042 av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' was expected "
1043 "to have exactly 1 input and 1 output."
1044 " However, it had %s input(s) and %s output(s)."
1045 " Please adjust, or use a complex filtergraph (-filter_complex) instead.\n",
1046 graph_desc, num_inputs, num_outputs);
1047 ret = AVERROR(EINVAL);
1048 goto fail;
1049 }
1050
1051 for (cur = inputs, i = 0; cur; cur = cur->next, i++)
1052 if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
1053 avfilter_inout_free(&inputs);
1054 avfilter_inout_free(&outputs);
1055 goto fail;
1056 }
1057 avfilter_inout_free(&inputs);
1058
1059 for (cur = outputs, i = 0; cur; cur = cur->next, i++)
1060 configure_output_filter(fg, fg->outputs[i], cur);
1061 avfilter_inout_free(&outputs);
1062
1064 avfilter_graph_set_auto_convert(fg->graph, AVFILTER_AUTO_CONVERT_NONE);
1065 if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
1066 goto fail;
1067
1068 /* limit the lists of allowed formats to the ones selected, to
1069 * make sure they stay the same if the filtergraph is reconfigured later */
1070 for (i = 0; i < fg->nb_outputs; i++) {
1071 OutputFilter *ofilter = fg->outputs[i];
1072 AVFilterContext *sink = ofilter->filter;
1073
1074 ofilter->format = av_buffersink_get_format(sink);
1075
1076 ofilter->width = av_buffersink_get_w(sink);
1077 ofilter->height = av_buffersink_get_h(sink);
1078
1079 ofilter->sample_rate = av_buffersink_get_sample_rate(sink);
1080 ofilter->channel_layout = av_buffersink_get_channel_layout(sink);
1081 }
1082
1083 fg->reconfiguration = 1;
1084
1085 for (i = 0; i < fg->nb_outputs; i++) {
1086 OutputStream *ost = fg->outputs[i]->ost;
1087 if (!ost->enc) {
1088 /* identical to the same check in ffmpeg.c, needed because
1089 complex filter graphs are initialized earlier */
1090 av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n",
1091 avcodec_get_name(ost->st->codecpar->codec_id), ost->file_index, ost->index);
1092 ret = AVERROR(EINVAL);
1093 goto fail;
1094 }
1095 if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
1096 !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
1097 av_buffersink_set_frame_size(ost->filter->filter,
1098 ost->enc_ctx->frame_size);
1099 }
1100
1101 for (i = 0; i < fg->nb_inputs; i++) {
1102 while (av_fifo_size(fg->inputs[i]->frame_queue)) {
1103 AVFrame *tmp;
1104 av_fifo_generic_read(fg->inputs[i]->frame_queue, &tmp, sizeof(tmp), NULL);
1105 ret = av_buffersrc_add_frame(fg->inputs[i]->filter, tmp);
1106 av_frame_free(&tmp);
1107 if (ret < 0)
1108 goto fail;
1109 }
1110 }
1111
1112 /* send the EOFs for the finished inputs */
1113 for (i = 0; i < fg->nb_inputs; i++) {
1114 if (fg->inputs[i]->eof) {
1115 ret = av_buffersrc_add_frame(fg->inputs[i]->filter, NULL);
1116 if (ret < 0)
1117 goto fail;
1118 }
1119 }
1120
1121 /* process queued up subtitle packets */
1122 for (i = 0; i < fg->nb_inputs; i++) {
1123 InputStream *ist = fg->inputs[i]->ist;
1124 if (ist->sub2video.sub_queue && ist->sub2video.frame) {
1125 while (av_fifo_size(ist->sub2video.sub_queue)) {
1126 AVSubtitle tmp;
1127 av_fifo_generic_read(ist->sub2video.sub_queue, &tmp, sizeof(tmp), NULL);
1128 sub2video_update(ist, INT64_MIN, &tmp);
1129 avsubtitle_free(&tmp);
1130 }
1131 }
1132 }
1133
1134 return 0;
1135
1136fail:
1138 return ret;
1139}
1140
1141int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
1142{
1143 av_buffer_unref(&ifilter->hw_frames_ctx);
1144
1145 ifilter->format = frame->format;
1146
1147 ifilter->width = frame->width;
1148 ifilter->height = frame->height;
1149 ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
1150
1151 ifilter->sample_rate = frame->sample_rate;
1152 ifilter->channels = frame->channels;
1153 ifilter->channel_layout = frame->channel_layout;
1154
1155 if (frame->hw_frames_ctx) {
1156 ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
1157 if (!ifilter->hw_frames_ctx)
1158 return AVERROR(ENOMEM);
1159 }
1160
1161 return 0;
1162}
1163
1165{
1166 return !fg->graph_desc;
1167}
void exit_program(int ret)
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
double get_rotation(AVStream *st)
__thread InputStream ** input_streams
__thread int nb_input_streams
__thread OutputFile ** output_files
__thread int nb_input_files
__thread InputFile ** input_files
void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub)
__thread int nb_filtergraphs
__thread int filter_complex_nbthreads
__thread int audio_volume
__thread int copy_ts
__thread int filter_nbthreads
#define DECODING_FOR_FILTER
__thread int do_deinterlace
__thread int audio_sync_method
int hw_device_setup_for_filter(FilterGraph *fg)
int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
__thread float audio_drift_threshold
__thread int start_at_zero
__thread int auto_conversion_filters
static void cleanup_filtergraph(FilterGraph *fg)
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
static int sub2video_prepare(InputStream *ist, InputFilter *ifilter)
static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
static enum AVPixelFormat * get_compliance_normal_pix_fmts(const AVCodec *codec, const enum AVPixelFormat default_formats[])
fg inputs[0] ist
OutputStream * ost
enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, const AVCodec *codec, enum AVPixelFormat target)
GROW_ARRAY(fg->outputs, fg->nb_outputs)
static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
ost filter
static char * choose_pix_fmts(OutputFilter *ofilter)
filtergraphs[nb_filtergraphs - 1]
fg outputs[0] format
static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in)
static int insert_trim(int64_t start_time, int64_t duration, AVFilterContext **last_filter, int *pad_idx, const char *filter_name)
fg outputs[0] graph
#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg)
static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in)
static char * describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
#define AUTO_INSERT_FILTER(opt_name, filter_name, arg)
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in)
int filtergraph_is_simple(FilterGraph *fg)
void check_filter_outputs(void)
static int insert_filter(AVFilterContext **last_filter, int *pad_idx, const char *filter_name, const char *args)
#define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name)
int configure_filtergraph(FilterGraph *fg)
int init_complex_filtergraph(FilterGraph *fg)
OutputFilter ** outputs
const char * graph_desc
AVFilterGraph * graph
InputFilter ** inputs
AVFormatContext * ctx
int64_t recording_time
int64_t start_time
AVBufferRef * hw_frames_ctx
uint8_t * name
struct InputStream * ist
AVFilterContext * filter
enum AVMediaType type
AVFifoBuffer * frame_queue
uint64_t channel_layout
struct FilterGraph * graph
AVRational sample_aspect_ratio
AVStream * st
const AVCodec * dec
AVFormatContext * ctx
int64_t start_time
start time in microseconds == AV_TIME_BASE units
int64_t recording_time
desired length of the resulting file in microseconds == AV_TIME_BASE units
AVFilterInOut * out_tmp
struct OutputStream * ost
AVFilterContext * filter
uint8_t * name
struct FilterGraph * graph
uint64_t channel_layout
enum AVMediaType type
AVDictionary * swr_opts
int * audio_channels_map
const AVCodec * enc
int audio_channels_mapped
AVDictionary * resample_opts
AVRational frame_rate
AVCodecContext * enc_ctx
AVDictionary * encoder_opts
AVStream * st
AVDictionary * sws_dict
OutputFilter * filter