blob: 3d428f3eea8a90dc6f753520cab7ad545d5c524b
1 | /* |
2 | * Various utilities for command line tools |
3 | * Copyright (c) 2000-2003 Fabrice Bellard |
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 | #include <string.h> |
23 | #include <stdint.h> |
24 | #include <stdlib.h> |
25 | #include <errno.h> |
26 | #include <math.h> |
27 | |
28 | /* Include only the enabled headers since some compilers (namely, Sun |
29 | Studio) will not omit unused inline functions and create undefined |
30 | references to libraries that are not being built. */ |
31 | |
32 | #include "config.h" |
33 | #include "compat/va_copy.h" |
34 | #include "libavformat/avformat.h" |
35 | #include "libavfilter/avfilter.h" |
36 | #include "libavdevice/avdevice.h" |
37 | #include "libavresample/avresample.h" |
38 | #include "libswscale/swscale.h" |
39 | #include "libswresample/swresample.h" |
40 | #include "libpostproc/postprocess.h" |
41 | #include "libavutil/avassert.h" |
42 | #include "libavutil/avstring.h" |
43 | #include "libavutil/bprint.h" |
44 | #include "libavutil/display.h" |
45 | #include "libavutil/mathematics.h" |
46 | #include "libavutil/imgutils.h" |
47 | #include "libavutil/libm.h" |
48 | #include "libavutil/parseutils.h" |
49 | #include "libavutil/pixdesc.h" |
50 | #include "libavutil/eval.h" |
51 | #include "libavutil/dict.h" |
52 | #include "libavutil/opt.h" |
53 | #include "libavutil/cpu.h" |
54 | #include "libavutil/ffversion.h" |
55 | #include "libavutil/version.h" |
56 | #include "cmdutils.h" |
57 | #if CONFIG_NETWORK |
58 | #include "libavformat/network.h" |
59 | #endif |
60 | #if HAVE_SYS_RESOURCE_H |
61 | #include <sys/time.h> |
62 | #include <sys/resource.h> |
63 | #endif |
64 | #ifdef _WIN32 |
65 | #include <windows.h> |
66 | #endif |
67 | |
68 | static int init_report(const char *env); |
69 | |
70 | AVDictionary *sws_dict; |
71 | AVDictionary *swr_opts; |
72 | AVDictionary *format_opts, *codec_opts, *resample_opts; |
73 | |
74 | static FILE *report_file; |
75 | static int report_file_level = AV_LOG_DEBUG; |
76 | int hide_banner = 0; |
77 | |
78 | enum show_muxdemuxers { |
79 | SHOW_DEFAULT, |
80 | SHOW_DEMUXERS, |
81 | SHOW_MUXERS, |
82 | }; |
83 | |
84 | void init_opts(void) |
85 | { |
86 | av_dict_set(&sws_dict, "flags", "bicubic", 0); |
87 | } |
88 | |
89 | void uninit_opts(void) |
90 | { |
91 | av_dict_free(&swr_opts); |
92 | av_dict_free(&sws_dict); |
93 | av_dict_free(&format_opts); |
94 | av_dict_free(&codec_opts); |
95 | av_dict_free(&resample_opts); |
96 | } |
97 | |
98 | void log_callback_help(void *ptr, int level, const char *fmt, va_list vl) |
99 | { |
100 | vfprintf(stdout, fmt, vl); |
101 | } |
102 | |
103 | static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl) |
104 | { |
105 | va_list vl2; |
106 | char line[1024]; |
107 | static int print_prefix = 1; |
108 | |
109 | va_copy(vl2, vl); |
110 | av_log_default_callback(ptr, level, fmt, vl); |
111 | av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); |
112 | va_end(vl2); |
113 | if (report_file_level >= level) { |
114 | fputs(line, report_file); |
115 | fflush(report_file); |
116 | } |
117 | } |
118 | |
119 | void init_dynload(void) |
120 | { |
121 | #ifdef _WIN32 |
122 | /* Calling SetDllDirectory with the empty string (but not NULL) removes the |
123 | * current working directory from the DLL search path as a security pre-caution. */ |
124 | SetDllDirectory(""); |
125 | #endif |
126 | } |
127 | |
128 | static void (*program_exit)(int ret); |
129 | |
130 | void register_exit(void (*cb)(int ret)) |
131 | { |
132 | program_exit = cb; |
133 | } |
134 | |
135 | void exit_program(int ret) |
136 | { |
137 | if (program_exit) |
138 | program_exit(ret); |
139 | |
140 | exit(ret); |
141 | } |
142 | |
143 | double parse_number_or_die(const char *context, const char *numstr, int type, |
144 | double min, double max) |
145 | { |
146 | char *tail; |
147 | const char *error; |
148 | double d = av_strtod(numstr, &tail); |
149 | if (*tail) |
150 | error = "Expected number for %s but found: %s\n"; |
151 | else if (d < min || d > max) |
152 | error = "The value for %s was %s which is not within %f - %f\n"; |
153 | else if (type == OPT_INT64 && (int64_t)d != d) |
154 | error = "Expected int64 for %s but found %s\n"; |
155 | else if (type == OPT_INT && (int)d != d) |
156 | error = "Expected int for %s but found %s\n"; |
157 | else |
158 | return d; |
159 | av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max); |
160 | exit_program(1); |
161 | return 0; |
162 | } |
163 | |
164 | int64_t parse_time_or_die(const char *context, const char *timestr, |
165 | int is_duration) |
166 | { |
167 | int64_t us; |
168 | if (av_parse_time(&us, timestr, is_duration) < 0) { |
169 | av_log(NULL, AV_LOG_FATAL, "Invalid %s specification for %s: %s\n", |
170 | is_duration ? "duration" : "date", context, timestr); |
171 | exit_program(1); |
172 | } |
173 | return us; |
174 | } |
175 | |
176 | void show_help_options(const OptionDef *options, const char *msg, int req_flags, |
177 | int rej_flags, int alt_flags) |
178 | { |
179 | const OptionDef *po; |
180 | int first; |
181 | |
182 | first = 1; |
183 | for (po = options; po->name; po++) { |
184 | char buf[64]; |
185 | |
186 | if (((po->flags & req_flags) != req_flags) || |
187 | (alt_flags && !(po->flags & alt_flags)) || |
188 | (po->flags & rej_flags)) |
189 | continue; |
190 | |
191 | if (first) { |
192 | printf("%s\n", msg); |
193 | first = 0; |
194 | } |
195 | av_strlcpy(buf, po->name, sizeof(buf)); |
196 | if (po->argname) { |
197 | av_strlcat(buf, " ", sizeof(buf)); |
198 | av_strlcat(buf, po->argname, sizeof(buf)); |
199 | } |
200 | printf("-%-17s %s\n", buf, po->help); |
201 | } |
202 | printf("\n"); |
203 | } |
204 | |
205 | void show_help_children(const AVClass *class, int flags) |
206 | { |
207 | const AVClass *child = NULL; |
208 | if (class->option) { |
209 | av_opt_show2(&class, NULL, flags, 0); |
210 | printf("\n"); |
211 | } |
212 | |
213 | while (child = av_opt_child_class_next(class, child)) |
214 | show_help_children(child, flags); |
215 | } |
216 | |
217 | static const OptionDef *find_option(const OptionDef *po, const char *name) |
218 | { |
219 | const char *p = strchr(name, ':'); |
220 | int len = p ? p - name : strlen(name); |
221 | |
222 | while (po->name) { |
223 | if (!strncmp(name, po->name, len) && strlen(po->name) == len) |
224 | break; |
225 | po++; |
226 | } |
227 | return po; |
228 | } |
229 | |
230 | /* _WIN32 means using the windows libc - cygwin doesn't define that |
231 | * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while |
232 | * it doesn't provide the actual command line via GetCommandLineW(). */ |
233 | #if HAVE_COMMANDLINETOARGVW && defined(_WIN32) |
234 | #include <shellapi.h> |
235 | /* Will be leaked on exit */ |
236 | static char** win32_argv_utf8 = NULL; |
237 | static int win32_argc = 0; |
238 | |
239 | /** |
240 | * Prepare command line arguments for executable. |
241 | * For Windows - perform wide-char to UTF-8 conversion. |
242 | * Input arguments should be main() function arguments. |
243 | * @param argc_ptr Arguments number (including executable) |
244 | * @param argv_ptr Arguments list. |
245 | */ |
246 | static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) |
247 | { |
248 | char *argstr_flat; |
249 | wchar_t **argv_w; |
250 | int i, buffsize = 0, offset = 0; |
251 | |
252 | if (win32_argv_utf8) { |
253 | *argc_ptr = win32_argc; |
254 | *argv_ptr = win32_argv_utf8; |
255 | return; |
256 | } |
257 | |
258 | win32_argc = 0; |
259 | argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc); |
260 | if (win32_argc <= 0 || !argv_w) |
261 | return; |
262 | |
263 | /* determine the UTF-8 buffer size (including NULL-termination symbols) */ |
264 | for (i = 0; i < win32_argc; i++) |
265 | buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, |
266 | NULL, 0, NULL, NULL); |
267 | |
268 | win32_argv_utf8 = av_mallocz(sizeof(char *) * (win32_argc + 1) + buffsize); |
269 | argstr_flat = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1); |
270 | if (!win32_argv_utf8) { |
271 | LocalFree(argv_w); |
272 | return; |
273 | } |
274 | |
275 | for (i = 0; i < win32_argc; i++) { |
276 | win32_argv_utf8[i] = &argstr_flat[offset]; |
277 | offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, |
278 | &argstr_flat[offset], |
279 | buffsize - offset, NULL, NULL); |
280 | } |
281 | win32_argv_utf8[i] = NULL; |
282 | LocalFree(argv_w); |
283 | |
284 | *argc_ptr = win32_argc; |
285 | *argv_ptr = win32_argv_utf8; |
286 | } |
287 | #else |
288 | static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) |
289 | { |
290 | /* nothing to do */ |
291 | } |
292 | #endif /* HAVE_COMMANDLINETOARGVW */ |
293 | |
294 | static int write_option(void *optctx, const OptionDef *po, const char *opt, |
295 | const char *arg) |
296 | { |
297 | /* new-style options contain an offset into optctx, old-style address of |
298 | * a global var*/ |
299 | void *dst = po->flags & (OPT_OFFSET | OPT_SPEC) ? |
300 | (uint8_t *)optctx + po->u.off : po->u.dst_ptr; |
301 | int *dstcount; |
302 | |
303 | if (po->flags & OPT_SPEC) { |
304 | SpecifierOpt **so = dst; |
305 | char *p = strchr(opt, ':'); |
306 | char *str; |
307 | |
308 | dstcount = (int *)(so + 1); |
309 | *so = grow_array(*so, sizeof(**so), dstcount, *dstcount + 1); |
310 | str = av_strdup(p ? p + 1 : ""); |
311 | if (!str) |
312 | return AVERROR(ENOMEM); |
313 | (*so)[*dstcount - 1].specifier = str; |
314 | dst = &(*so)[*dstcount - 1].u; |
315 | } |
316 | |
317 | if (po->flags & OPT_STRING) { |
318 | char *str; |
319 | str = av_strdup(arg); |
320 | av_freep(dst); |
321 | if (!str) |
322 | return AVERROR(ENOMEM); |
323 | *(char **)dst = str; |
324 | } else if (po->flags & OPT_BOOL || po->flags & OPT_INT) { |
325 | *(int *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX); |
326 | } else if (po->flags & OPT_INT64) { |
327 | *(int64_t *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT64_MIN, INT64_MAX); |
328 | } else if (po->flags & OPT_TIME) { |
329 | *(int64_t *)dst = parse_time_or_die(opt, arg, 1); |
330 | } else if (po->flags & OPT_FLOAT) { |
331 | *(float *)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY); |
332 | } else if (po->flags & OPT_DOUBLE) { |
333 | *(double *)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY); |
334 | } else if (po->u.func_arg) { |
335 | int ret = po->u.func_arg(optctx, opt, arg); |
336 | if (ret < 0) { |
337 | av_log(NULL, AV_LOG_ERROR, |
338 | "Failed to set value '%s' for option '%s': %s\n", |
339 | arg, opt, av_err2str(ret)); |
340 | return ret; |
341 | } |
342 | } |
343 | if (po->flags & OPT_EXIT) |
344 | exit_program(0); |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | int parse_option(void *optctx, const char *opt, const char *arg, |
350 | const OptionDef *options) |
351 | { |
352 | const OptionDef *po; |
353 | int ret; |
354 | |
355 | po = find_option(options, opt); |
356 | if (!po->name && opt[0] == 'n' && opt[1] == 'o') { |
357 | /* handle 'no' bool option */ |
358 | po = find_option(options, opt + 2); |
359 | if ((po->name && (po->flags & OPT_BOOL))) |
360 | arg = "0"; |
361 | } else if (po->flags & OPT_BOOL) |
362 | arg = "1"; |
363 | |
364 | if (!po->name) |
365 | po = find_option(options, "default"); |
366 | if (!po->name) { |
367 | av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt); |
368 | return AVERROR(EINVAL); |
369 | } |
370 | if (po->flags & HAS_ARG && !arg) { |
371 | av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'\n", opt); |
372 | return AVERROR(EINVAL); |
373 | } |
374 | |
375 | ret = write_option(optctx, po, opt, arg); |
376 | if (ret < 0) |
377 | return ret; |
378 | |
379 | return !!(po->flags & HAS_ARG); |
380 | } |
381 | |
382 | void parse_options(void *optctx, int argc, char **argv, const OptionDef *options, |
383 | void (*parse_arg_function)(void *, const char*)) |
384 | { |
385 | const char *opt; |
386 | int optindex, handleoptions = 1, ret; |
387 | |
388 | /* perform system-dependent conversions for arguments list */ |
389 | prepare_app_arguments(&argc, &argv); |
390 | |
391 | /* parse options */ |
392 | optindex = 1; |
393 | while (optindex < argc) { |
394 | opt = argv[optindex++]; |
395 | |
396 | if (handleoptions && opt[0] == '-' && opt[1] != '\0') { |
397 | if (opt[1] == '-' && opt[2] == '\0') { |
398 | handleoptions = 0; |
399 | continue; |
400 | } |
401 | opt++; |
402 | |
403 | if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0) |
404 | exit_program(1); |
405 | optindex += ret; |
406 | } else { |
407 | if (parse_arg_function) |
408 | parse_arg_function(optctx, opt); |
409 | } |
410 | } |
411 | } |
412 | |
413 | int parse_optgroup(void *optctx, OptionGroup *g) |
414 | { |
415 | int i, ret; |
416 | |
417 | av_log(NULL, AV_LOG_DEBUG, "Parsing a group of options: %s %s.\n", |
418 | g->group_def->name, g->arg); |
419 | |
420 | for (i = 0; i < g->nb_opts; i++) { |
421 | Option *o = &g->opts[i]; |
422 | |
423 | if (g->group_def->flags && |
424 | !(g->group_def->flags & o->opt->flags)) { |
425 | av_log(NULL, AV_LOG_ERROR, "Option %s (%s) cannot be applied to " |
426 | "%s %s -- you are trying to apply an input option to an " |
427 | "output file or vice versa. Move this option before the " |
428 | "file it belongs to.\n", o->key, o->opt->help, |
429 | g->group_def->name, g->arg); |
430 | return AVERROR(EINVAL); |
431 | } |
432 | |
433 | av_log(NULL, AV_LOG_DEBUG, "Applying option %s (%s) with argument %s.\n", |
434 | o->key, o->opt->help, o->val); |
435 | |
436 | ret = write_option(optctx, o->opt, o->key, o->val); |
437 | if (ret < 0) |
438 | return ret; |
439 | } |
440 | |
441 | av_log(NULL, AV_LOG_DEBUG, "Successfully parsed a group of options.\n"); |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | int locate_option(int argc, char **argv, const OptionDef *options, |
447 | const char *optname) |
448 | { |
449 | const OptionDef *po; |
450 | int i; |
451 | |
452 | for (i = 1; i < argc; i++) { |
453 | const char *cur_opt = argv[i]; |
454 | |
455 | if (*cur_opt++ != '-') |
456 | continue; |
457 | |
458 | po = find_option(options, cur_opt); |
459 | if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o') |
460 | po = find_option(options, cur_opt + 2); |
461 | |
462 | if ((!po->name && !strcmp(cur_opt, optname)) || |
463 | (po->name && !strcmp(optname, po->name))) |
464 | return i; |
465 | |
466 | if (!po->name || po->flags & HAS_ARG) |
467 | i++; |
468 | } |
469 | return 0; |
470 | } |
471 | |
472 | static void dump_argument(const char *a) |
473 | { |
474 | const unsigned char *p; |
475 | |
476 | for (p = a; *p; p++) |
477 | if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') || |
478 | *p == '_' || (*p >= 'a' && *p <= 'z'))) |
479 | break; |
480 | if (!*p) { |
481 | fputs(a, report_file); |
482 | return; |
483 | } |
484 | fputc('"', report_file); |
485 | for (p = a; *p; p++) { |
486 | if (*p == '\\' || *p == '"' || *p == '$' || *p == '`') |
487 | fprintf(report_file, "\\%c", *p); |
488 | else if (*p < ' ' || *p > '~') |
489 | fprintf(report_file, "\\x%02x", *p); |
490 | else |
491 | fputc(*p, report_file); |
492 | } |
493 | fputc('"', report_file); |
494 | } |
495 | |
496 | static void check_options(const OptionDef *po) |
497 | { |
498 | while (po->name) { |
499 | if (po->flags & OPT_PERFILE) |
500 | av_assert0(po->flags & (OPT_INPUT | OPT_OUTPUT)); |
501 | po++; |
502 | } |
503 | } |
504 | |
505 | void parse_loglevel(int argc, char **argv, const OptionDef *options) |
506 | { |
507 | int idx = locate_option(argc, argv, options, "loglevel"); |
508 | const char *env; |
509 | |
510 | check_options(options); |
511 | |
512 | if (!idx) |
513 | idx = locate_option(argc, argv, options, "v"); |
514 | if (idx && argv[idx + 1]) |
515 | opt_loglevel(NULL, "loglevel", argv[idx + 1]); |
516 | idx = locate_option(argc, argv, options, "report"); |
517 | if ((env = getenv("FFREPORT")) || idx) { |
518 | init_report(env); |
519 | if (report_file) { |
520 | int i; |
521 | fprintf(report_file, "Command line:\n"); |
522 | for (i = 0; i < argc; i++) { |
523 | dump_argument(argv[i]); |
524 | fputc(i < argc - 1 ? ' ' : '\n', report_file); |
525 | } |
526 | fflush(report_file); |
527 | } |
528 | } |
529 | idx = locate_option(argc, argv, options, "hide_banner"); |
530 | if (idx) |
531 | hide_banner = 1; |
532 | } |
533 | |
534 | static const AVOption *opt_find(void *obj, const char *name, const char *unit, |
535 | int opt_flags, int search_flags) |
536 | { |
537 | const AVOption *o = av_opt_find(obj, name, unit, opt_flags, search_flags); |
538 | if(o && !o->flags) |
539 | return NULL; |
540 | return o; |
541 | } |
542 | |
543 | #define FLAGS (o->type == AV_OPT_TYPE_FLAGS && (arg[0]=='-' || arg[0]=='+')) ? AV_DICT_APPEND : 0 |
544 | int opt_default(void *optctx, const char *opt, const char *arg) |
545 | { |
546 | const AVOption *o; |
547 | int consumed = 0; |
548 | char opt_stripped[128]; |
549 | const char *p; |
550 | const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(); |
551 | #if CONFIG_AVRESAMPLE |
552 | const AVClass *rc = avresample_get_class(); |
553 | #endif |
554 | #if CONFIG_SWSCALE |
555 | const AVClass *sc = sws_get_class(); |
556 | #endif |
557 | #if CONFIG_SWRESAMPLE |
558 | const AVClass *swr_class = swr_get_class(); |
559 | #endif |
560 | |
561 | if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug")) |
562 | av_log_set_level(AV_LOG_DEBUG); |
563 | |
564 | if (!(p = strchr(opt, ':'))) |
565 | p = opt + strlen(opt); |
566 | av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1)); |
567 | |
568 | if ((o = opt_find(&cc, opt_stripped, NULL, 0, |
569 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) || |
570 | ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') && |
571 | (o = opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) { |
572 | av_dict_set(&codec_opts, opt, arg, FLAGS); |
573 | consumed = 1; |
574 | } |
575 | if ((o = opt_find(&fc, opt, NULL, 0, |
576 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { |
577 | av_dict_set(&format_opts, opt, arg, FLAGS); |
578 | if (consumed) |
579 | av_log(NULL, AV_LOG_VERBOSE, "Routing option %s to both codec and muxer layer\n", opt); |
580 | consumed = 1; |
581 | } |
582 | #if CONFIG_SWSCALE |
583 | if (!consumed && (o = opt_find(&sc, opt, NULL, 0, |
584 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { |
585 | struct SwsContext *sws = sws_alloc_context(); |
586 | int ret = av_opt_set(sws, opt, arg, 0); |
587 | sws_freeContext(sws); |
588 | if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") || |
589 | !strcmp(opt, "dstw") || !strcmp(opt, "dsth") || |
590 | !strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) { |
591 | av_log(NULL, AV_LOG_ERROR, "Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n"); |
592 | return AVERROR(EINVAL); |
593 | } |
594 | if (ret < 0) { |
595 | av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); |
596 | return ret; |
597 | } |
598 | |
599 | av_dict_set(&sws_dict, opt, arg, FLAGS); |
600 | |
601 | consumed = 1; |
602 | } |
603 | #else |
604 | if (!consumed && !strcmp(opt, "sws_flags")) { |
605 | av_log(NULL, AV_LOG_WARNING, "Ignoring %s %s, due to disabled swscale\n", opt, arg); |
606 | consumed = 1; |
607 | } |
608 | #endif |
609 | #if CONFIG_SWRESAMPLE |
610 | if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0, |
611 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { |
612 | struct SwrContext *swr = swr_alloc(); |
613 | int ret = av_opt_set(swr, opt, arg, 0); |
614 | swr_free(&swr); |
615 | if (ret < 0) { |
616 | av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); |
617 | return ret; |
618 | } |
619 | av_dict_set(&swr_opts, opt, arg, FLAGS); |
620 | consumed = 1; |
621 | } |
622 | #endif |
623 | #if CONFIG_AVRESAMPLE |
624 | if ((o=opt_find(&rc, opt, NULL, 0, |
625 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { |
626 | av_dict_set(&resample_opts, opt, arg, FLAGS); |
627 | consumed = 1; |
628 | } |
629 | #endif |
630 | |
631 | if (consumed) |
632 | return 0; |
633 | return AVERROR_OPTION_NOT_FOUND; |
634 | } |
635 | |
636 | /* |
637 | * Check whether given option is a group separator. |
638 | * |
639 | * @return index of the group definition that matched or -1 if none |
640 | */ |
641 | static int match_group_separator(const OptionGroupDef *groups, int nb_groups, |
642 | const char *opt) |
643 | { |
644 | int i; |
645 | |
646 | for (i = 0; i < nb_groups; i++) { |
647 | const OptionGroupDef *p = &groups[i]; |
648 | if (p->sep && !strcmp(p->sep, opt)) |
649 | return i; |
650 | } |
651 | |
652 | return -1; |
653 | } |
654 | |
655 | /* |
656 | * Finish parsing an option group. |
657 | * |
658 | * @param group_idx which group definition should this group belong to |
659 | * @param arg argument of the group delimiting option |
660 | */ |
661 | static void finish_group(OptionParseContext *octx, int group_idx, |
662 | const char *arg) |
663 | { |
664 | OptionGroupList *l = &octx->groups[group_idx]; |
665 | OptionGroup *g; |
666 | |
667 | GROW_ARRAY(l->groups, l->nb_groups); |
668 | g = &l->groups[l->nb_groups - 1]; |
669 | |
670 | *g = octx->cur_group; |
671 | g->arg = arg; |
672 | g->group_def = l->group_def; |
673 | g->sws_dict = sws_dict; |
674 | g->swr_opts = swr_opts; |
675 | g->codec_opts = codec_opts; |
676 | g->format_opts = format_opts; |
677 | g->resample_opts = resample_opts; |
678 | |
679 | codec_opts = NULL; |
680 | format_opts = NULL; |
681 | resample_opts = NULL; |
682 | sws_dict = NULL; |
683 | swr_opts = NULL; |
684 | init_opts(); |
685 | |
686 | memset(&octx->cur_group, 0, sizeof(octx->cur_group)); |
687 | } |
688 | |
689 | /* |
690 | * Add an option instance to currently parsed group. |
691 | */ |
692 | static void add_opt(OptionParseContext *octx, const OptionDef *opt, |
693 | const char *key, const char *val) |
694 | { |
695 | int global = !(opt->flags & (OPT_PERFILE | OPT_SPEC | OPT_OFFSET)); |
696 | OptionGroup *g = global ? &octx->global_opts : &octx->cur_group; |
697 | |
698 | GROW_ARRAY(g->opts, g->nb_opts); |
699 | g->opts[g->nb_opts - 1].opt = opt; |
700 | g->opts[g->nb_opts - 1].key = key; |
701 | g->opts[g->nb_opts - 1].val = val; |
702 | } |
703 | |
704 | static void init_parse_context(OptionParseContext *octx, |
705 | const OptionGroupDef *groups, int nb_groups) |
706 | { |
707 | static const OptionGroupDef global_group = { "global" }; |
708 | int i; |
709 | |
710 | memset(octx, 0, sizeof(*octx)); |
711 | |
712 | octx->nb_groups = nb_groups; |
713 | octx->groups = av_mallocz_array(octx->nb_groups, sizeof(*octx->groups)); |
714 | if (!octx->groups) |
715 | exit_program(1); |
716 | |
717 | for (i = 0; i < octx->nb_groups; i++) |
718 | octx->groups[i].group_def = &groups[i]; |
719 | |
720 | octx->global_opts.group_def = &global_group; |
721 | octx->global_opts.arg = ""; |
722 | |
723 | init_opts(); |
724 | } |
725 | |
726 | void uninit_parse_context(OptionParseContext *octx) |
727 | { |
728 | int i, j; |
729 | |
730 | for (i = 0; i < octx->nb_groups; i++) { |
731 | OptionGroupList *l = &octx->groups[i]; |
732 | |
733 | for (j = 0; j < l->nb_groups; j++) { |
734 | av_freep(&l->groups[j].opts); |
735 | av_dict_free(&l->groups[j].codec_opts); |
736 | av_dict_free(&l->groups[j].format_opts); |
737 | av_dict_free(&l->groups[j].resample_opts); |
738 | |
739 | av_dict_free(&l->groups[j].sws_dict); |
740 | av_dict_free(&l->groups[j].swr_opts); |
741 | } |
742 | av_freep(&l->groups); |
743 | } |
744 | av_freep(&octx->groups); |
745 | |
746 | av_freep(&octx->cur_group.opts); |
747 | av_freep(&octx->global_opts.opts); |
748 | |
749 | uninit_opts(); |
750 | } |
751 | |
752 | int split_commandline(OptionParseContext *octx, int argc, char *argv[], |
753 | const OptionDef *options, |
754 | const OptionGroupDef *groups, int nb_groups) |
755 | { |
756 | int optindex = 1; |
757 | int dashdash = -2; |
758 | |
759 | /* perform system-dependent conversions for arguments list */ |
760 | prepare_app_arguments(&argc, &argv); |
761 | |
762 | init_parse_context(octx, groups, nb_groups); |
763 | av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n"); |
764 | |
765 | while (optindex < argc) { |
766 | const char *opt = argv[optindex++], *arg; |
767 | const OptionDef *po; |
768 | int ret; |
769 | |
770 | av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt); |
771 | |
772 | if (opt[0] == '-' && opt[1] == '-' && !opt[2]) { |
773 | dashdash = optindex; |
774 | continue; |
775 | } |
776 | /* unnamed group separators, e.g. output filename */ |
777 | if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) { |
778 | finish_group(octx, 0, opt); |
779 | av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name); |
780 | continue; |
781 | } |
782 | opt++; |
783 | |
784 | #define GET_ARG(arg) \ |
785 | do { \ |
786 | arg = argv[optindex++]; \ |
787 | if (!arg) { \ |
788 | av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\ |
789 | return AVERROR(EINVAL); \ |
790 | } \ |
791 | } while (0) |
792 | |
793 | /* named group separators, e.g. -i */ |
794 | if ((ret = match_group_separator(groups, nb_groups, opt)) >= 0) { |
795 | GET_ARG(arg); |
796 | finish_group(octx, ret, arg); |
797 | av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument '%s'.\n", |
798 | groups[ret].name, arg); |
799 | continue; |
800 | } |
801 | |
802 | /* normal options */ |
803 | po = find_option(options, opt); |
804 | if (po->name) { |
805 | if (po->flags & OPT_EXIT) { |
806 | /* optional argument, e.g. -h */ |
807 | arg = argv[optindex++]; |
808 | } else if (po->flags & HAS_ARG) { |
809 | GET_ARG(arg); |
810 | } else { |
811 | arg = "1"; |
812 | } |
813 | |
814 | add_opt(octx, po, opt, arg); |
815 | av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " |
816 | "argument '%s'.\n", po->name, po->help, arg); |
817 | continue; |
818 | } |
819 | |
820 | /* AVOptions */ |
821 | if (argv[optindex]) { |
822 | ret = opt_default(NULL, opt, argv[optindex]); |
823 | if (ret >= 0) { |
824 | av_log(NULL, AV_LOG_DEBUG, " matched as AVOption '%s' with " |
825 | "argument '%s'.\n", opt, argv[optindex]); |
826 | optindex++; |
827 | continue; |
828 | } else if (ret != AVERROR_OPTION_NOT_FOUND) { |
829 | av_log(NULL, AV_LOG_ERROR, "Error parsing option '%s' " |
830 | "with argument '%s'.\n", opt, argv[optindex]); |
831 | return ret; |
832 | } |
833 | } |
834 | |
835 | /* boolean -nofoo options */ |
836 | if (opt[0] == 'n' && opt[1] == 'o' && |
837 | (po = find_option(options, opt + 2)) && |
838 | po->name && po->flags & OPT_BOOL) { |
839 | add_opt(octx, po, opt, "0"); |
840 | av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " |
841 | "argument 0.\n", po->name, po->help); |
842 | continue; |
843 | } |
844 | |
845 | av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'.\n", opt); |
846 | return AVERROR_OPTION_NOT_FOUND; |
847 | } |
848 | |
849 | if (octx->cur_group.nb_opts || codec_opts || format_opts || resample_opts) |
850 | av_log(NULL, AV_LOG_WARNING, "Trailing options were found on the " |
851 | "commandline.\n"); |
852 | |
853 | av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n"); |
854 | |
855 | return 0; |
856 | } |
857 | |
858 | int opt_cpuflags(void *optctx, const char *opt, const char *arg) |
859 | { |
860 | int ret; |
861 | unsigned flags = av_get_cpu_flags(); |
862 | |
863 | if ((ret = av_parse_cpu_caps(&flags, arg)) < 0) |
864 | return ret; |
865 | |
866 | av_force_cpu_flags(flags); |
867 | return 0; |
868 | } |
869 | |
870 | int opt_loglevel(void *optctx, const char *opt, const char *arg) |
871 | { |
872 | const struct { const char *name; int level; } log_levels[] = { |
873 | { "quiet" , AV_LOG_QUIET }, |
874 | { "panic" , AV_LOG_PANIC }, |
875 | { "fatal" , AV_LOG_FATAL }, |
876 | { "error" , AV_LOG_ERROR }, |
877 | { "warning", AV_LOG_WARNING }, |
878 | { "info" , AV_LOG_INFO }, |
879 | { "verbose", AV_LOG_VERBOSE }, |
880 | { "debug" , AV_LOG_DEBUG }, |
881 | { "trace" , AV_LOG_TRACE }, |
882 | }; |
883 | char *tail; |
884 | int level; |
885 | int flags; |
886 | int i; |
887 | |
888 | flags = av_log_get_flags(); |
889 | tail = strstr(arg, "repeat"); |
890 | if (tail) |
891 | flags &= ~AV_LOG_SKIP_REPEATED; |
892 | else |
893 | flags |= AV_LOG_SKIP_REPEATED; |
894 | |
895 | av_log_set_flags(flags); |
896 | if (tail == arg) |
897 | arg += 6 + (arg[6]=='+'); |
898 | if(tail && !*arg) |
899 | return 0; |
900 | |
901 | for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) { |
902 | if (!strcmp(log_levels[i].name, arg)) { |
903 | av_log_set_level(log_levels[i].level); |
904 | return 0; |
905 | } |
906 | } |
907 | |
908 | level = strtol(arg, &tail, 10); |
909 | if (*tail) { |
910 | av_log(NULL, AV_LOG_FATAL, "Invalid loglevel \"%s\". " |
911 | "Possible levels are numbers or:\n", arg); |
912 | for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) |
913 | av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); |
914 | exit_program(1); |
915 | } |
916 | av_log_set_level(level); |
917 | return 0; |
918 | } |
919 | |
920 | static void expand_filename_template(AVBPrint *bp, const char *template, |
921 | struct tm *tm) |
922 | { |
923 | int c; |
924 | |
925 | while ((c = *(template++))) { |
926 | if (c == '%') { |
927 | if (!(c = *(template++))) |
928 | break; |
929 | switch (c) { |
930 | case 'p': |
931 | av_bprintf(bp, "%s", program_name); |
932 | break; |
933 | case 't': |
934 | av_bprintf(bp, "%04d%02d%02d-%02d%02d%02d", |
935 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
936 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
937 | break; |
938 | case '%': |
939 | av_bprint_chars(bp, c, 1); |
940 | break; |
941 | } |
942 | } else { |
943 | av_bprint_chars(bp, c, 1); |
944 | } |
945 | } |
946 | } |
947 | |
948 | static int init_report(const char *env) |
949 | { |
950 | char *filename_template = NULL; |
951 | char *key, *val; |
952 | int ret, count = 0; |
953 | time_t now; |
954 | struct tm *tm; |
955 | AVBPrint filename; |
956 | |
957 | if (report_file) /* already opened */ |
958 | return 0; |
959 | time(&now); |
960 | tm = localtime(&now); |
961 | |
962 | while (env && *env) { |
963 | if ((ret = av_opt_get_key_value(&env, "=", ":", 0, &key, &val)) < 0) { |
964 | if (count) |
965 | av_log(NULL, AV_LOG_ERROR, |
966 | "Failed to parse FFREPORT environment variable: %s\n", |
967 | av_err2str(ret)); |
968 | break; |
969 | } |
970 | if (*env) |
971 | env++; |
972 | count++; |
973 | if (!strcmp(key, "file")) { |
974 | av_free(filename_template); |
975 | filename_template = val; |
976 | val = NULL; |
977 | } else if (!strcmp(key, "level")) { |
978 | char *tail; |
979 | report_file_level = strtol(val, &tail, 10); |
980 | if (*tail) { |
981 | av_log(NULL, AV_LOG_FATAL, "Invalid report file level\n"); |
982 | exit_program(1); |
983 | } |
984 | } else { |
985 | av_log(NULL, AV_LOG_ERROR, "Unknown key '%s' in FFREPORT\n", key); |
986 | } |
987 | av_free(val); |
988 | av_free(key); |
989 | } |
990 | |
991 | av_bprint_init(&filename, 0, 1); |
992 | expand_filename_template(&filename, |
993 | av_x_if_null(filename_template, "%p-%t.log"), tm); |
994 | av_free(filename_template); |
995 | if (!av_bprint_is_complete(&filename)) { |
996 | av_log(NULL, AV_LOG_ERROR, "Out of memory building report file name\n"); |
997 | return AVERROR(ENOMEM); |
998 | } |
999 | |
1000 | report_file = fopen(filename.str, "w"); |
1001 | if (!report_file) { |
1002 | int ret = AVERROR(errno); |
1003 | av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n", |
1004 | filename.str, strerror(errno)); |
1005 | return ret; |
1006 | } |
1007 | av_log_set_callback(log_callback_report); |
1008 | av_log(NULL, AV_LOG_INFO, |
1009 | "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n" |
1010 | "Report written to \"%s\"\n", |
1011 | program_name, |
1012 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
1013 | tm->tm_hour, tm->tm_min, tm->tm_sec, |
1014 | filename.str); |
1015 | av_bprint_finalize(&filename, NULL); |
1016 | return 0; |
1017 | } |
1018 | |
1019 | int opt_report(const char *opt) |
1020 | { |
1021 | return init_report(NULL); |
1022 | } |
1023 | |
1024 | int opt_max_alloc(void *optctx, const char *opt, const char *arg) |
1025 | { |
1026 | char *tail; |
1027 | size_t max; |
1028 | |
1029 | max = strtol(arg, &tail, 10); |
1030 | if (*tail) { |
1031 | av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg); |
1032 | exit_program(1); |
1033 | } |
1034 | av_max_alloc(max); |
1035 | return 0; |
1036 | } |
1037 | |
1038 | int opt_timelimit(void *optctx, const char *opt, const char *arg) |
1039 | { |
1040 | #if HAVE_SETRLIMIT |
1041 | int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); |
1042 | struct rlimit rl = { lim, lim + 1 }; |
1043 | if (setrlimit(RLIMIT_CPU, &rl)) |
1044 | perror("setrlimit"); |
1045 | #else |
1046 | av_log(NULL, AV_LOG_WARNING, "-%s not implemented on this OS\n", opt); |
1047 | #endif |
1048 | return 0; |
1049 | } |
1050 | |
1051 | void print_error(const char *filename, int err) |
1052 | { |
1053 | char errbuf[128]; |
1054 | const char *errbuf_ptr = errbuf; |
1055 | |
1056 | if (av_strerror(err, errbuf, sizeof(errbuf)) < 0) |
1057 | errbuf_ptr = strerror(AVUNERROR(err)); |
1058 | av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr); |
1059 | } |
1060 | |
1061 | static int warned_cfg = 0; |
1062 | |
1063 | #define INDENT 1 |
1064 | #define SHOW_VERSION 2 |
1065 | #define SHOW_CONFIG 4 |
1066 | #define SHOW_COPYRIGHT 8 |
1067 | |
1068 | #define PRINT_LIB_INFO(libname, LIBNAME, flags, level) \ |
1069 | if (CONFIG_##LIBNAME) { \ |
1070 | const char *indent = flags & INDENT? " " : ""; \ |
1071 | if (flags & SHOW_VERSION) { \ |
1072 | unsigned int version = libname##_version(); \ |
1073 | av_log(NULL, level, \ |
1074 | "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \ |
1075 | indent, #libname, \ |
1076 | LIB##LIBNAME##_VERSION_MAJOR, \ |
1077 | LIB##LIBNAME##_VERSION_MINOR, \ |
1078 | LIB##LIBNAME##_VERSION_MICRO, \ |
1079 | AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\ |
1080 | AV_VERSION_MICRO(version)); \ |
1081 | } \ |
1082 | if (flags & SHOW_CONFIG) { \ |
1083 | const char *cfg = libname##_configuration(); \ |
1084 | if (strcmp(FFMPEG_CONFIGURATION, cfg)) { \ |
1085 | if (!warned_cfg) { \ |
1086 | av_log(NULL, level, \ |
1087 | "%sWARNING: library configuration mismatch\n", \ |
1088 | indent); \ |
1089 | warned_cfg = 1; \ |
1090 | } \ |
1091 | av_log(NULL, level, "%s%-11s configuration: %s\n", \ |
1092 | indent, #libname, cfg); \ |
1093 | } \ |
1094 | } \ |
1095 | } \ |
1096 | |
1097 | static void print_all_libs_info(int flags, int level) |
1098 | { |
1099 | PRINT_LIB_INFO(avutil, AVUTIL, flags, level); |
1100 | PRINT_LIB_INFO(avcodec, AVCODEC, flags, level); |
1101 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); |
1102 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); |
1103 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); |
1104 | PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level); |
1105 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); |
1106 | PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); |
1107 | PRINT_LIB_INFO(postproc, POSTPROC, flags, level); |
1108 | } |
1109 | |
1110 | static void print_program_info(int flags, int level) |
1111 | { |
1112 | const char *indent = flags & INDENT? " " : ""; |
1113 | |
1114 | av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name); |
1115 | if (flags & SHOW_COPYRIGHT) |
1116 | av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers", |
1117 | program_birth_year, CONFIG_THIS_YEAR); |
1118 | av_log(NULL, level, "\n"); |
1119 | av_log(NULL, level, "%sbuilt with %s\n", indent, CC_IDENT); |
1120 | |
1121 | av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent); |
1122 | } |
1123 | |
1124 | static void print_buildconf(int flags, int level) |
1125 | { |
1126 | const char *indent = flags & INDENT ? " " : ""; |
1127 | char str[] = { FFMPEG_CONFIGURATION }; |
1128 | char *conflist, *remove_tilde, *splitconf; |
1129 | |
1130 | // Change all the ' --' strings to '~--' so that |
1131 | // they can be identified as tokens. |
1132 | while ((conflist = strstr(str, " --")) != NULL) { |
1133 | strncpy(conflist, "~--", 3); |
1134 | } |
1135 | |
1136 | // Compensate for the weirdness this would cause |
1137 | // when passing 'pkg-config --static'. |
1138 | while ((remove_tilde = strstr(str, "pkg-config~")) != NULL) { |
1139 | strncpy(remove_tilde, "pkg-config ", 11); |
1140 | } |
1141 | |
1142 | splitconf = strtok(str, "~"); |
1143 | av_log(NULL, level, "\n%sconfiguration:\n", indent); |
1144 | while (splitconf != NULL) { |
1145 | av_log(NULL, level, "%s%s%s\n", indent, indent, splitconf); |
1146 | splitconf = strtok(NULL, "~"); |
1147 | } |
1148 | } |
1149 | |
1150 | void show_banner(int argc, char **argv, const OptionDef *options) |
1151 | { |
1152 | int idx = locate_option(argc, argv, options, "version"); |
1153 | if (hide_banner || idx) |
1154 | return; |
1155 | |
1156 | print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO); |
1157 | print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_INFO); |
1158 | print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO); |
1159 | } |
1160 | |
1161 | int show_version(void *optctx, const char *opt, const char *arg) |
1162 | { |
1163 | av_log_set_callback(log_callback_help); |
1164 | print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO); |
1165 | print_all_libs_info(SHOW_VERSION, AV_LOG_INFO); |
1166 | |
1167 | return 0; |
1168 | } |
1169 | |
1170 | int show_buildconf(void *optctx, const char *opt, const char *arg) |
1171 | { |
1172 | av_log_set_callback(log_callback_help); |
1173 | print_buildconf (INDENT|0, AV_LOG_INFO); |
1174 | |
1175 | return 0; |
1176 | } |
1177 | |
1178 | int show_license(void *optctx, const char *opt, const char *arg) |
1179 | { |
1180 | #if CONFIG_NONFREE |
1181 | printf( |
1182 | "This version of %s has nonfree parts compiled in.\n" |
1183 | "Therefore it is not legally redistributable.\n", |
1184 | program_name ); |
1185 | #elif CONFIG_GPLV3 |
1186 | printf( |
1187 | "%s is free software; you can redistribute it and/or modify\n" |
1188 | "it under the terms of the GNU General Public License as published by\n" |
1189 | "the Free Software Foundation; either version 3 of the License, or\n" |
1190 | "(at your option) any later version.\n" |
1191 | "\n" |
1192 | "%s is distributed in the hope that it will be useful,\n" |
1193 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" |
1194 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" |
1195 | "GNU General Public License for more details.\n" |
1196 | "\n" |
1197 | "You should have received a copy of the GNU General Public License\n" |
1198 | "along with %s. If not, see <http://www.gnu.org/licenses/>.\n", |
1199 | program_name, program_name, program_name ); |
1200 | #elif CONFIG_GPL |
1201 | printf( |
1202 | "%s is free software; you can redistribute it and/or modify\n" |
1203 | "it under the terms of the GNU General Public License as published by\n" |
1204 | "the Free Software Foundation; either version 2 of the License, or\n" |
1205 | "(at your option) any later version.\n" |
1206 | "\n" |
1207 | "%s is distributed in the hope that it will be useful,\n" |
1208 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" |
1209 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" |
1210 | "GNU General Public License for more details.\n" |
1211 | "\n" |
1212 | "You should have received a copy of the GNU General Public License\n" |
1213 | "along with %s; if not, write to the Free Software\n" |
1214 | "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n", |
1215 | program_name, program_name, program_name ); |
1216 | #elif CONFIG_LGPLV3 |
1217 | printf( |
1218 | "%s is free software; you can redistribute it and/or modify\n" |
1219 | "it under the terms of the GNU Lesser General Public License as published by\n" |
1220 | "the Free Software Foundation; either version 3 of the License, or\n" |
1221 | "(at your option) any later version.\n" |
1222 | "\n" |
1223 | "%s is distributed in the hope that it will be useful,\n" |
1224 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" |
1225 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" |
1226 | "GNU Lesser General Public License for more details.\n" |
1227 | "\n" |
1228 | "You should have received a copy of the GNU Lesser General Public License\n" |
1229 | "along with %s. If not, see <http://www.gnu.org/licenses/>.\n", |
1230 | program_name, program_name, program_name ); |
1231 | #else |
1232 | printf( |
1233 | "%s is free software; you can redistribute it and/or\n" |
1234 | "modify it under the terms of the GNU Lesser General Public\n" |
1235 | "License as published by the Free Software Foundation; either\n" |
1236 | "version 2.1 of the License, or (at your option) any later version.\n" |
1237 | "\n" |
1238 | "%s is distributed in the hope that it will be useful,\n" |
1239 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" |
1240 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" |
1241 | "Lesser General Public License for more details.\n" |
1242 | "\n" |
1243 | "You should have received a copy of the GNU Lesser General Public\n" |
1244 | "License along with %s; if not, write to the Free Software\n" |
1245 | "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n", |
1246 | program_name, program_name, program_name ); |
1247 | #endif |
1248 | |
1249 | return 0; |
1250 | } |
1251 | |
1252 | static int is_device(const AVClass *avclass) |
1253 | { |
1254 | if (!avclass) |
1255 | return 0; |
1256 | return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category); |
1257 | } |
1258 | |
1259 | static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers) |
1260 | { |
1261 | AVInputFormat *ifmt = NULL; |
1262 | AVOutputFormat *ofmt = NULL; |
1263 | const char *last_name; |
1264 | int is_dev; |
1265 | |
1266 | printf("%s\n" |
1267 | " D. = Demuxing supported\n" |
1268 | " .E = Muxing supported\n" |
1269 | " --\n", device_only ? "Devices:" : "File formats:"); |
1270 | last_name = "000"; |
1271 | for (;;) { |
1272 | int decode = 0; |
1273 | int encode = 0; |
1274 | const char *name = NULL; |
1275 | const char *long_name = NULL; |
1276 | |
1277 | if (muxdemuxers !=SHOW_DEMUXERS) { |
1278 | while ((ofmt = av_oformat_next(ofmt))) { |
1279 | is_dev = is_device(ofmt->priv_class); |
1280 | if (!is_dev && device_only) |
1281 | continue; |
1282 | if ((!name || strcmp(ofmt->name, name) < 0) && |
1283 | strcmp(ofmt->name, last_name) > 0) { |
1284 | name = ofmt->name; |
1285 | long_name = ofmt->long_name; |
1286 | encode = 1; |
1287 | } |
1288 | } |
1289 | } |
1290 | if (muxdemuxers != SHOW_MUXERS) { |
1291 | while ((ifmt = av_iformat_next(ifmt))) { |
1292 | is_dev = is_device(ifmt->priv_class); |
1293 | if (!is_dev && device_only) |
1294 | continue; |
1295 | if ((!name || strcmp(ifmt->name, name) < 0) && |
1296 | strcmp(ifmt->name, last_name) > 0) { |
1297 | name = ifmt->name; |
1298 | long_name = ifmt->long_name; |
1299 | encode = 0; |
1300 | } |
1301 | if (name && strcmp(ifmt->name, name) == 0) |
1302 | decode = 1; |
1303 | } |
1304 | } |
1305 | if (!name) |
1306 | break; |
1307 | last_name = name; |
1308 | |
1309 | printf(" %s%s %-15s %s\n", |
1310 | decode ? "D" : " ", |
1311 | encode ? "E" : " ", |
1312 | name, |
1313 | long_name ? long_name:" "); |
1314 | } |
1315 | return 0; |
1316 | } |
1317 | |
1318 | int show_formats(void *optctx, const char *opt, const char *arg) |
1319 | { |
1320 | return show_formats_devices(optctx, opt, arg, 0, SHOW_DEFAULT); |
1321 | } |
1322 | |
1323 | int show_muxers(void *optctx, const char *opt, const char *arg) |
1324 | { |
1325 | return show_formats_devices(optctx, opt, arg, 0, SHOW_MUXERS); |
1326 | } |
1327 | |
1328 | int show_demuxers(void *optctx, const char *opt, const char *arg) |
1329 | { |
1330 | return show_formats_devices(optctx, opt, arg, 0, SHOW_DEMUXERS); |
1331 | } |
1332 | |
1333 | int show_devices(void *optctx, const char *opt, const char *arg) |
1334 | { |
1335 | return show_formats_devices(optctx, opt, arg, 1, SHOW_DEFAULT); |
1336 | } |
1337 | |
1338 | #define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \ |
1339 | if (codec->field) { \ |
1340 | const type *p = codec->field; \ |
1341 | \ |
1342 | printf(" Supported " list_name ":"); \ |
1343 | while (*p != term) { \ |
1344 | get_name(*p); \ |
1345 | printf(" %s", name); \ |
1346 | p++; \ |
1347 | } \ |
1348 | printf("\n"); \ |
1349 | } \ |
1350 | |
1351 | static void print_codec(const AVCodec *c) |
1352 | { |
1353 | int encoder = av_codec_is_encoder(c); |
1354 | |
1355 | printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name, |
1356 | c->long_name ? c->long_name : ""); |
1357 | |
1358 | printf(" General capabilities: "); |
1359 | if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND) |
1360 | printf("horizband "); |
1361 | if (c->capabilities & AV_CODEC_CAP_DR1) |
1362 | printf("dr1 "); |
1363 | if (c->capabilities & AV_CODEC_CAP_TRUNCATED) |
1364 | printf("trunc "); |
1365 | if (c->capabilities & AV_CODEC_CAP_DELAY) |
1366 | printf("delay "); |
1367 | if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME) |
1368 | printf("small "); |
1369 | if (c->capabilities & AV_CODEC_CAP_SUBFRAMES) |
1370 | printf("subframes "); |
1371 | if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL) |
1372 | printf("exp "); |
1373 | if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF) |
1374 | printf("chconf "); |
1375 | if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE) |
1376 | printf("paramchange "); |
1377 | if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) |
1378 | printf("variable "); |
1379 | if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS | |
1380 | AV_CODEC_CAP_SLICE_THREADS | |
1381 | AV_CODEC_CAP_AUTO_THREADS)) |
1382 | printf("threads "); |
1383 | if (!c->capabilities) |
1384 | printf("none"); |
1385 | printf("\n"); |
1386 | |
1387 | if (c->type == AVMEDIA_TYPE_VIDEO || |
1388 | c->type == AVMEDIA_TYPE_AUDIO) { |
1389 | printf(" Threading capabilities: "); |
1390 | switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS | |
1391 | AV_CODEC_CAP_SLICE_THREADS | |
1392 | AV_CODEC_CAP_AUTO_THREADS)) { |
1393 | case AV_CODEC_CAP_FRAME_THREADS | |
1394 | AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break; |
1395 | case AV_CODEC_CAP_FRAME_THREADS: printf("frame"); break; |
1396 | case AV_CODEC_CAP_SLICE_THREADS: printf("slice"); break; |
1397 | case AV_CODEC_CAP_AUTO_THREADS : printf("auto"); break; |
1398 | default: printf("none"); break; |
1399 | } |
1400 | printf("\n"); |
1401 | } |
1402 | |
1403 | if (c->supported_framerates) { |
1404 | const AVRational *fps = c->supported_framerates; |
1405 | |
1406 | printf(" Supported framerates:"); |
1407 | while (fps->num) { |
1408 | printf(" %d/%d", fps->num, fps->den); |
1409 | fps++; |
1410 | } |
1411 | printf("\n"); |
1412 | } |
1413 | PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats", |
1414 | AV_PIX_FMT_NONE, GET_PIX_FMT_NAME); |
1415 | PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0, |
1416 | GET_SAMPLE_RATE_NAME); |
1417 | PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats", |
1418 | AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME); |
1419 | PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts", |
1420 | 0, GET_CH_LAYOUT_DESC); |
1421 | |
1422 | if (c->priv_class) { |
1423 | show_help_children(c->priv_class, |
1424 | AV_OPT_FLAG_ENCODING_PARAM | |
1425 | AV_OPT_FLAG_DECODING_PARAM); |
1426 | } |
1427 | } |
1428 | |
1429 | static char get_media_type_char(enum AVMediaType type) |
1430 | { |
1431 | switch (type) { |
1432 | case AVMEDIA_TYPE_VIDEO: return 'V'; |
1433 | case AVMEDIA_TYPE_AUDIO: return 'A'; |
1434 | case AVMEDIA_TYPE_DATA: return 'D'; |
1435 | case AVMEDIA_TYPE_SUBTITLE: return 'S'; |
1436 | case AVMEDIA_TYPE_ATTACHMENT:return 'T'; |
1437 | default: return '?'; |
1438 | } |
1439 | } |
1440 | |
1441 | static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev, |
1442 | int encoder) |
1443 | { |
1444 | while ((prev = av_codec_next(prev))) { |
1445 | if (prev->id == id && |
1446 | (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev))) |
1447 | return prev; |
1448 | } |
1449 | return NULL; |
1450 | } |
1451 | |
1452 | static int compare_codec_desc(const void *a, const void *b) |
1453 | { |
1454 | const AVCodecDescriptor * const *da = a; |
1455 | const AVCodecDescriptor * const *db = b; |
1456 | |
1457 | return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) : |
1458 | strcmp((*da)->name, (*db)->name); |
1459 | } |
1460 | |
1461 | static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs) |
1462 | { |
1463 | const AVCodecDescriptor *desc = NULL; |
1464 | const AVCodecDescriptor **codecs; |
1465 | unsigned nb_codecs = 0, i = 0; |
1466 | |
1467 | while ((desc = avcodec_descriptor_next(desc))) |
1468 | nb_codecs++; |
1469 | if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) { |
1470 | av_log(NULL, AV_LOG_ERROR, "Out of memory\n"); |
1471 | exit_program(1); |
1472 | } |
1473 | desc = NULL; |
1474 | while ((desc = avcodec_descriptor_next(desc))) |
1475 | codecs[i++] = desc; |
1476 | av_assert0(i == nb_codecs); |
1477 | qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc); |
1478 | *rcodecs = codecs; |
1479 | return nb_codecs; |
1480 | } |
1481 | |
1482 | static void print_codecs_for_id(enum AVCodecID id, int encoder) |
1483 | { |
1484 | const AVCodec *codec = NULL; |
1485 | |
1486 | printf(" (%s: ", encoder ? "encoders" : "decoders"); |
1487 | |
1488 | while ((codec = next_codec_for_id(id, codec, encoder))) |
1489 | printf("%s ", codec->name); |
1490 | |
1491 | printf(")"); |
1492 | } |
1493 | |
1494 | int show_codecs(void *optctx, const char *opt, const char *arg) |
1495 | { |
1496 | const AVCodecDescriptor **codecs; |
1497 | unsigned i, nb_codecs = get_codecs_sorted(&codecs); |
1498 | |
1499 | printf("Codecs:\n" |
1500 | " D..... = Decoding supported\n" |
1501 | " .E.... = Encoding supported\n" |
1502 | " ..V... = Video codec\n" |
1503 | " ..A... = Audio codec\n" |
1504 | " ..S... = Subtitle codec\n" |
1505 | " ...I.. = Intra frame-only codec\n" |
1506 | " ....L. = Lossy compression\n" |
1507 | " .....S = Lossless compression\n" |
1508 | " -------\n"); |
1509 | for (i = 0; i < nb_codecs; i++) { |
1510 | const AVCodecDescriptor *desc = codecs[i]; |
1511 | const AVCodec *codec = NULL; |
1512 | |
1513 | if (strstr(desc->name, "_deprecated")) |
1514 | continue; |
1515 | |
1516 | printf(" "); |
1517 | printf(avcodec_find_decoder(desc->id) ? "D" : "."); |
1518 | printf(avcodec_find_encoder(desc->id) ? "E" : "."); |
1519 | |
1520 | printf("%c", get_media_type_char(desc->type)); |
1521 | printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : "."); |
1522 | printf((desc->props & AV_CODEC_PROP_LOSSY) ? "L" : "."); |
1523 | printf((desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : "."); |
1524 | |
1525 | printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : ""); |
1526 | |
1527 | /* print decoders/encoders when there's more than one or their |
1528 | * names are different from codec name */ |
1529 | while ((codec = next_codec_for_id(desc->id, codec, 0))) { |
1530 | if (strcmp(codec->name, desc->name)) { |
1531 | print_codecs_for_id(desc->id, 0); |
1532 | break; |
1533 | } |
1534 | } |
1535 | codec = NULL; |
1536 | while ((codec = next_codec_for_id(desc->id, codec, 1))) { |
1537 | if (strcmp(codec->name, desc->name)) { |
1538 | print_codecs_for_id(desc->id, 1); |
1539 | break; |
1540 | } |
1541 | } |
1542 | |
1543 | printf("\n"); |
1544 | } |
1545 | av_free(codecs); |
1546 | return 0; |
1547 | } |
1548 | |
1549 | static void print_codecs(int encoder) |
1550 | { |
1551 | const AVCodecDescriptor **codecs; |
1552 | unsigned i, nb_codecs = get_codecs_sorted(&codecs); |
1553 | |
1554 | printf("%s:\n" |
1555 | " V..... = Video\n" |
1556 | " A..... = Audio\n" |
1557 | " S..... = Subtitle\n" |
1558 | " .F.... = Frame-level multithreading\n" |
1559 | " ..S... = Slice-level multithreading\n" |
1560 | " ...X.. = Codec is experimental\n" |
1561 | " ....B. = Supports draw_horiz_band\n" |
1562 | " .....D = Supports direct rendering method 1\n" |
1563 | " ------\n", |
1564 | encoder ? "Encoders" : "Decoders"); |
1565 | for (i = 0; i < nb_codecs; i++) { |
1566 | const AVCodecDescriptor *desc = codecs[i]; |
1567 | const AVCodec *codec = NULL; |
1568 | |
1569 | while ((codec = next_codec_for_id(desc->id, codec, encoder))) { |
1570 | printf(" %c", get_media_type_char(desc->type)); |
1571 | printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : "."); |
1572 | printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : "."); |
1573 | printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) ? "X" : "."); |
1574 | printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : "."); |
1575 | printf((codec->capabilities & AV_CODEC_CAP_DR1) ? "D" : "."); |
1576 | |
1577 | printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : ""); |
1578 | if (strcmp(codec->name, desc->name)) |
1579 | printf(" (codec %s)", desc->name); |
1580 | |
1581 | printf("\n"); |
1582 | } |
1583 | } |
1584 | av_free(codecs); |
1585 | } |
1586 | |
1587 | int show_decoders(void *optctx, const char *opt, const char *arg) |
1588 | { |
1589 | print_codecs(0); |
1590 | return 0; |
1591 | } |
1592 | |
1593 | int show_encoders(void *optctx, const char *opt, const char *arg) |
1594 | { |
1595 | print_codecs(1); |
1596 | return 0; |
1597 | } |
1598 | |
1599 | int show_bsfs(void *optctx, const char *opt, const char *arg) |
1600 | { |
1601 | const AVBitStreamFilter *bsf = NULL; |
1602 | void *opaque = NULL; |
1603 | |
1604 | printf("Bitstream filters:\n"); |
1605 | while ((bsf = av_bsf_next(&opaque))) |
1606 | printf("%s\n", bsf->name); |
1607 | printf("\n"); |
1608 | return 0; |
1609 | } |
1610 | |
1611 | int show_protocols(void *optctx, const char *opt, const char *arg) |
1612 | { |
1613 | void *opaque = NULL; |
1614 | const char *name; |
1615 | |
1616 | printf("Supported file protocols:\n" |
1617 | "Input:\n"); |
1618 | while ((name = avio_enum_protocols(&opaque, 0))) |
1619 | printf(" %s\n", name); |
1620 | printf("Output:\n"); |
1621 | while ((name = avio_enum_protocols(&opaque, 1))) |
1622 | printf(" %s\n", name); |
1623 | return 0; |
1624 | } |
1625 | |
1626 | int show_filters(void *optctx, const char *opt, const char *arg) |
1627 | { |
1628 | #if CONFIG_AVFILTER |
1629 | const AVFilter *filter = NULL; |
1630 | char descr[64], *descr_cur; |
1631 | int i, j; |
1632 | const AVFilterPad *pad; |
1633 | |
1634 | printf("Filters:\n" |
1635 | " T.. = Timeline support\n" |
1636 | " .S. = Slice threading\n" |
1637 | " ..C = Command support\n" |
1638 | " A = Audio input/output\n" |
1639 | " V = Video input/output\n" |
1640 | " N = Dynamic number and/or type of input/output\n" |
1641 | " | = Source or sink filter\n"); |
1642 | while ((filter = avfilter_next(filter))) { |
1643 | descr_cur = descr; |
1644 | for (i = 0; i < 2; i++) { |
1645 | if (i) { |
1646 | *(descr_cur++) = '-'; |
1647 | *(descr_cur++) = '>'; |
1648 | } |
1649 | pad = i ? filter->outputs : filter->inputs; |
1650 | for (j = 0; pad && avfilter_pad_get_name(pad, j); j++) { |
1651 | if (descr_cur >= descr + sizeof(descr) - 4) |
1652 | break; |
1653 | *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j)); |
1654 | } |
1655 | if (!j) |
1656 | *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) || |
1657 | ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|'; |
1658 | } |
1659 | *descr_cur = 0; |
1660 | printf(" %c%c%c %-17s %-10s %s\n", |
1661 | filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.', |
1662 | filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.', |
1663 | filter->process_command ? 'C' : '.', |
1664 | filter->name, descr, filter->description); |
1665 | } |
1666 | #else |
1667 | printf("No filters available: libavfilter disabled\n"); |
1668 | #endif |
1669 | return 0; |
1670 | } |
1671 | |
1672 | int show_colors(void *optctx, const char *opt, const char *arg) |
1673 | { |
1674 | const char *name; |
1675 | const uint8_t *rgb; |
1676 | int i; |
1677 | |
1678 | printf("%-32s #RRGGBB\n", "name"); |
1679 | |
1680 | for (i = 0; name = av_get_known_color_name(i, &rgb); i++) |
1681 | printf("%-32s #%02x%02x%02x\n", name, rgb[0], rgb[1], rgb[2]); |
1682 | |
1683 | return 0; |
1684 | } |
1685 | |
1686 | int show_pix_fmts(void *optctx, const char *opt, const char *arg) |
1687 | { |
1688 | const AVPixFmtDescriptor *pix_desc = NULL; |
1689 | |
1690 | printf("Pixel formats:\n" |
1691 | "I.... = Supported Input format for conversion\n" |
1692 | ".O... = Supported Output format for conversion\n" |
1693 | "..H.. = Hardware accelerated format\n" |
1694 | "...P. = Paletted format\n" |
1695 | "....B = Bitstream format\n" |
1696 | "FLAGS NAME NB_COMPONENTS BITS_PER_PIXEL\n" |
1697 | "-----\n"); |
1698 | |
1699 | #if !CONFIG_SWSCALE |
1700 | # define sws_isSupportedInput(x) 0 |
1701 | # define sws_isSupportedOutput(x) 0 |
1702 | #endif |
1703 | |
1704 | while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { |
1705 | enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc); |
1706 | printf("%c%c%c%c%c %-16s %d %2d\n", |
1707 | sws_isSupportedInput (pix_fmt) ? 'I' : '.', |
1708 | sws_isSupportedOutput(pix_fmt) ? 'O' : '.', |
1709 | pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL ? 'H' : '.', |
1710 | pix_desc->flags & AV_PIX_FMT_FLAG_PAL ? 'P' : '.', |
1711 | pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.', |
1712 | pix_desc->name, |
1713 | pix_desc->nb_components, |
1714 | av_get_bits_per_pixel(pix_desc)); |
1715 | } |
1716 | return 0; |
1717 | } |
1718 | |
1719 | int show_layouts(void *optctx, const char *opt, const char *arg) |
1720 | { |
1721 | int i = 0; |
1722 | uint64_t layout, j; |
1723 | const char *name, *descr; |
1724 | |
1725 | printf("Individual channels:\n" |
1726 | "NAME DESCRIPTION\n"); |
1727 | for (i = 0; i < 63; i++) { |
1728 | name = av_get_channel_name((uint64_t)1 << i); |
1729 | if (!name) |
1730 | continue; |
1731 | descr = av_get_channel_description((uint64_t)1 << i); |
1732 | printf("%-14s %s\n", name, descr); |
1733 | } |
1734 | printf("\nStandard channel layouts:\n" |
1735 | "NAME DECOMPOSITION\n"); |
1736 | for (i = 0; !av_get_standard_channel_layout(i, &layout, &name); i++) { |
1737 | if (name) { |
1738 | printf("%-14s ", name); |
1739 | for (j = 1; j; j <<= 1) |
1740 | if ((layout & j)) |
1741 | printf("%s%s", (layout & (j - 1)) ? "+" : "", av_get_channel_name(j)); |
1742 | printf("\n"); |
1743 | } |
1744 | } |
1745 | return 0; |
1746 | } |
1747 | |
1748 | int show_sample_fmts(void *optctx, const char *opt, const char *arg) |
1749 | { |
1750 | int i; |
1751 | char fmt_str[128]; |
1752 | for (i = -1; i < AV_SAMPLE_FMT_NB; i++) |
1753 | printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i)); |
1754 | return 0; |
1755 | } |
1756 | |
1757 | static void show_help_codec(const char *name, int encoder) |
1758 | { |
1759 | const AVCodecDescriptor *desc; |
1760 | const AVCodec *codec; |
1761 | |
1762 | if (!name) { |
1763 | av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n"); |
1764 | return; |
1765 | } |
1766 | |
1767 | codec = encoder ? avcodec_find_encoder_by_name(name) : |
1768 | avcodec_find_decoder_by_name(name); |
1769 | |
1770 | if (codec) |
1771 | print_codec(codec); |
1772 | else if ((desc = avcodec_descriptor_get_by_name(name))) { |
1773 | int printed = 0; |
1774 | |
1775 | while ((codec = next_codec_for_id(desc->id, codec, encoder))) { |
1776 | printed = 1; |
1777 | print_codec(codec); |
1778 | } |
1779 | |
1780 | if (!printed) { |
1781 | av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, " |
1782 | "but no %s for it are available. FFmpeg might need to be " |
1783 | "recompiled with additional external libraries.\n", |
1784 | name, encoder ? "encoders" : "decoders"); |
1785 | } |
1786 | } else { |
1787 | av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n", |
1788 | name); |
1789 | } |
1790 | } |
1791 | |
1792 | static void show_help_demuxer(const char *name) |
1793 | { |
1794 | const AVInputFormat *fmt = av_find_input_format(name); |
1795 | |
1796 | if (!fmt) { |
1797 | av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name); |
1798 | return; |
1799 | } |
1800 | |
1801 | printf("Demuxer %s [%s]:\n", fmt->name, fmt->long_name); |
1802 | |
1803 | if (fmt->extensions) |
1804 | printf(" Common extensions: %s.\n", fmt->extensions); |
1805 | |
1806 | if (fmt->priv_class) |
1807 | show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM); |
1808 | } |
1809 | |
1810 | static void show_help_muxer(const char *name) |
1811 | { |
1812 | const AVCodecDescriptor *desc; |
1813 | const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL); |
1814 | |
1815 | if (!fmt) { |
1816 | av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name); |
1817 | return; |
1818 | } |
1819 | |
1820 | printf("Muxer %s [%s]:\n", fmt->name, fmt->long_name); |
1821 | |
1822 | if (fmt->extensions) |
1823 | printf(" Common extensions: %s.\n", fmt->extensions); |
1824 | if (fmt->mime_type) |
1825 | printf(" Mime type: %s.\n", fmt->mime_type); |
1826 | if (fmt->video_codec != AV_CODEC_ID_NONE && |
1827 | (desc = avcodec_descriptor_get(fmt->video_codec))) { |
1828 | printf(" Default video codec: %s.\n", desc->name); |
1829 | } |
1830 | if (fmt->audio_codec != AV_CODEC_ID_NONE && |
1831 | (desc = avcodec_descriptor_get(fmt->audio_codec))) { |
1832 | printf(" Default audio codec: %s.\n", desc->name); |
1833 | } |
1834 | if (fmt->subtitle_codec != AV_CODEC_ID_NONE && |
1835 | (desc = avcodec_descriptor_get(fmt->subtitle_codec))) { |
1836 | printf(" Default subtitle codec: %s.\n", desc->name); |
1837 | } |
1838 | |
1839 | if (fmt->priv_class) |
1840 | show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM); |
1841 | } |
1842 | |
1843 | #if CONFIG_AVFILTER |
1844 | static void show_help_filter(const char *name) |
1845 | { |
1846 | #if CONFIG_AVFILTER |
1847 | const AVFilter *f = avfilter_get_by_name(name); |
1848 | int i, count; |
1849 | |
1850 | if (!name) { |
1851 | av_log(NULL, AV_LOG_ERROR, "No filter name specified.\n"); |
1852 | return; |
1853 | } else if (!f) { |
1854 | av_log(NULL, AV_LOG_ERROR, "Unknown filter '%s'.\n", name); |
1855 | return; |
1856 | } |
1857 | |
1858 | printf("Filter %s\n", f->name); |
1859 | if (f->description) |
1860 | printf(" %s\n", f->description); |
1861 | |
1862 | if (f->flags & AVFILTER_FLAG_SLICE_THREADS) |
1863 | printf(" slice threading supported\n"); |
1864 | |
1865 | printf(" Inputs:\n"); |
1866 | count = avfilter_pad_count(f->inputs); |
1867 | for (i = 0; i < count; i++) { |
1868 | printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i), |
1869 | media_type_string(avfilter_pad_get_type(f->inputs, i))); |
1870 | } |
1871 | if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS) |
1872 | printf(" dynamic (depending on the options)\n"); |
1873 | else if (!count) |
1874 | printf(" none (source filter)\n"); |
1875 | |
1876 | printf(" Outputs:\n"); |
1877 | count = avfilter_pad_count(f->outputs); |
1878 | for (i = 0; i < count; i++) { |
1879 | printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i), |
1880 | media_type_string(avfilter_pad_get_type(f->outputs, i))); |
1881 | } |
1882 | if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS) |
1883 | printf(" dynamic (depending on the options)\n"); |
1884 | else if (!count) |
1885 | printf(" none (sink filter)\n"); |
1886 | |
1887 | if (f->priv_class) |
1888 | show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |
1889 | AV_OPT_FLAG_AUDIO_PARAM); |
1890 | if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) |
1891 | printf("This filter has support for timeline through the 'enable' option.\n"); |
1892 | #else |
1893 | av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; " |
1894 | "can not to satisfy request\n"); |
1895 | #endif |
1896 | } |
1897 | #endif |
1898 | |
1899 | int show_help(void *optctx, const char *opt, const char *arg) |
1900 | { |
1901 | char *topic, *par; |
1902 | av_log_set_callback(log_callback_help); |
1903 | |
1904 | topic = av_strdup(arg ? arg : ""); |
1905 | if (!topic) |
1906 | return AVERROR(ENOMEM); |
1907 | par = strchr(topic, '='); |
1908 | if (par) |
1909 | *par++ = 0; |
1910 | |
1911 | if (!*topic) { |
1912 | show_help_default(topic, par); |
1913 | } else if (!strcmp(topic, "decoder")) { |
1914 | show_help_codec(par, 0); |
1915 | } else if (!strcmp(topic, "encoder")) { |
1916 | show_help_codec(par, 1); |
1917 | } else if (!strcmp(topic, "demuxer")) { |
1918 | show_help_demuxer(par); |
1919 | } else if (!strcmp(topic, "muxer")) { |
1920 | show_help_muxer(par); |
1921 | #if CONFIG_AVFILTER |
1922 | } else if (!strcmp(topic, "filter")) { |
1923 | show_help_filter(par); |
1924 | #endif |
1925 | } else { |
1926 | show_help_default(topic, par); |
1927 | } |
1928 | |
1929 | av_freep(&topic); |
1930 | return 0; |
1931 | } |
1932 | |
1933 | int read_yesno(void) |
1934 | { |
1935 | int c = getchar(); |
1936 | int yesno = (av_toupper(c) == 'Y'); |
1937 | |
1938 | while (c != '\n' && c != EOF) |
1939 | c = getchar(); |
1940 | |
1941 | return yesno; |
1942 | } |
1943 | |
1944 | FILE *get_preset_file(char *filename, size_t filename_size, |
1945 | const char *preset_name, int is_path, |
1946 | const char *codec_name) |
1947 | { |
1948 | FILE *f = NULL; |
1949 | int i; |
1950 | const char *base[3] = { getenv("FFMPEG_DATADIR"), |
1951 | getenv("HOME"), |
1952 | FFMPEG_DATADIR, }; |
1953 | |
1954 | if (is_path) { |
1955 | av_strlcpy(filename, preset_name, filename_size); |
1956 | f = fopen(filename, "r"); |
1957 | } else { |
1958 | #ifdef _WIN32 |
1959 | char datadir[MAX_PATH], *ls; |
1960 | base[2] = NULL; |
1961 | |
1962 | if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1)) |
1963 | { |
1964 | for (ls = datadir; ls < datadir + strlen(datadir); ls++) |
1965 | if (*ls == '\\') *ls = '/'; |
1966 | |
1967 | if (ls = strrchr(datadir, '/')) |
1968 | { |
1969 | *ls = 0; |
1970 | strncat(datadir, "/ffpresets", sizeof(datadir) - 1 - strlen(datadir)); |
1971 | base[2] = datadir; |
1972 | } |
1973 | } |
1974 | #endif |
1975 | for (i = 0; i < 3 && !f; i++) { |
1976 | if (!base[i]) |
1977 | continue; |
1978 | snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i], |
1979 | i != 1 ? "" : "/.ffmpeg", preset_name); |
1980 | f = fopen(filename, "r"); |
1981 | if (!f && codec_name) { |
1982 | snprintf(filename, filename_size, |
1983 | "%s%s/%s-%s.ffpreset", |
1984 | base[i], i != 1 ? "" : "/.ffmpeg", codec_name, |
1985 | preset_name); |
1986 | f = fopen(filename, "r"); |
1987 | } |
1988 | } |
1989 | } |
1990 | |
1991 | return f; |
1992 | } |
1993 | |
1994 | int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) |
1995 | { |
1996 | int ret = avformat_match_stream_specifier(s, st, spec); |
1997 | if (ret < 0) |
1998 | av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); |
1999 | return ret; |
2000 | } |
2001 | |
2002 | AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, |
2003 | AVFormatContext *s, AVStream *st, AVCodec *codec) |
2004 | { |
2005 | AVDictionary *ret = NULL; |
2006 | AVDictionaryEntry *t = NULL; |
2007 | int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM |
2008 | : AV_OPT_FLAG_DECODING_PARAM; |
2009 | char prefix = 0; |
2010 | const AVClass *cc = avcodec_get_class(); |
2011 | |
2012 | if (!codec) |
2013 | codec = s->oformat ? avcodec_find_encoder(codec_id) |
2014 | : avcodec_find_decoder(codec_id); |
2015 | |
2016 | switch (st->codecpar->codec_type) { |
2017 | case AVMEDIA_TYPE_VIDEO: |
2018 | prefix = 'v'; |
2019 | flags |= AV_OPT_FLAG_VIDEO_PARAM; |
2020 | break; |
2021 | case AVMEDIA_TYPE_AUDIO: |
2022 | prefix = 'a'; |
2023 | flags |= AV_OPT_FLAG_AUDIO_PARAM; |
2024 | break; |
2025 | case AVMEDIA_TYPE_SUBTITLE: |
2026 | prefix = 's'; |
2027 | flags |= AV_OPT_FLAG_SUBTITLE_PARAM; |
2028 | break; |
2029 | } |
2030 | |
2031 | while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) { |
2032 | char *p = strchr(t->key, ':'); |
2033 | |
2034 | /* check stream specification in opt name */ |
2035 | if (p) |
2036 | switch (check_stream_specifier(s, st, p + 1)) { |
2037 | case 1: *p = 0; break; |
2038 | case 0: continue; |
2039 | default: exit_program(1); |
2040 | } |
2041 | |
2042 | if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) || |
2043 | !codec || |
2044 | (codec->priv_class && |
2045 | av_opt_find(&codec->priv_class, t->key, NULL, flags, |
2046 | AV_OPT_SEARCH_FAKE_OBJ))) |
2047 | av_dict_set(&ret, t->key, t->value, 0); |
2048 | else if (t->key[0] == prefix && |
2049 | av_opt_find(&cc, t->key + 1, NULL, flags, |
2050 | AV_OPT_SEARCH_FAKE_OBJ)) |
2051 | av_dict_set(&ret, t->key + 1, t->value, 0); |
2052 | |
2053 | if (p) |
2054 | *p = ':'; |
2055 | } |
2056 | return ret; |
2057 | } |
2058 | |
2059 | AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, |
2060 | AVDictionary *codec_opts) |
2061 | { |
2062 | int i; |
2063 | AVDictionary **opts; |
2064 | |
2065 | if (!s->nb_streams) |
2066 | return NULL; |
2067 | opts = av_mallocz_array(s->nb_streams, sizeof(*opts)); |
2068 | if (!opts) { |
2069 | av_log(NULL, AV_LOG_ERROR, |
2070 | "Could not alloc memory for stream options.\n"); |
2071 | return NULL; |
2072 | } |
2073 | for (i = 0; i < s->nb_streams; i++) |
2074 | opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, |
2075 | s, s->streams[i], NULL); |
2076 | return opts; |
2077 | } |
2078 | |
2079 | void *grow_array(void *array, int elem_size, int *size, int new_size) |
2080 | { |
2081 | if (new_size >= INT_MAX / elem_size) { |
2082 | av_log(NULL, AV_LOG_ERROR, "Array too big.\n"); |
2083 | exit_program(1); |
2084 | } |
2085 | if (*size < new_size) { |
2086 | uint8_t *tmp = av_realloc_array(array, new_size, elem_size); |
2087 | if (!tmp) { |
2088 | av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n"); |
2089 | exit_program(1); |
2090 | } |
2091 | memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size); |
2092 | *size = new_size; |
2093 | return tmp; |
2094 | } |
2095 | return array; |
2096 | } |
2097 | |
2098 | double get_rotation(AVStream *st) |
2099 | { |
2100 | uint8_t* displaymatrix = av_stream_get_side_data(st, |
2101 | AV_PKT_DATA_DISPLAYMATRIX, NULL); |
2102 | double theta = 0; |
2103 | if (displaymatrix) |
2104 | theta = -av_display_rotation_get((int32_t*) displaymatrix); |
2105 | |
2106 | theta -= 360*floor(theta/360 + 0.9/360); |
2107 | |
2108 | if (fabs(theta - 90*round(theta/90)) > 2) |
2109 | av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n" |
2110 | "If you want to help, upload a sample " |
2111 | "of this file to ftp://upload.ffmpeg.org/incoming/ " |
2112 | "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)"); |
2113 | |
2114 | return theta; |
2115 | } |
2116 | |
2117 | #if CONFIG_AVDEVICE |
2118 | static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts) |
2119 | { |
2120 | int ret, i; |
2121 | AVDeviceInfoList *device_list = NULL; |
2122 | |
2123 | if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category)) |
2124 | return AVERROR(EINVAL); |
2125 | |
2126 | printf("Auto-detected sources for %s:\n", fmt->name); |
2127 | if (!fmt->get_device_list) { |
2128 | ret = AVERROR(ENOSYS); |
2129 | printf("Cannot list sources. Not implemented.\n"); |
2130 | goto fail; |
2131 | } |
2132 | |
2133 | if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) { |
2134 | printf("Cannot list sources.\n"); |
2135 | goto fail; |
2136 | } |
2137 | |
2138 | for (i = 0; i < device_list->nb_devices; i++) { |
2139 | printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ", |
2140 | device_list->devices[i]->device_name, device_list->devices[i]->device_description); |
2141 | } |
2142 | |
2143 | fail: |
2144 | avdevice_free_list_devices(&device_list); |
2145 | return ret; |
2146 | } |
2147 | |
2148 | static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts) |
2149 | { |
2150 | int ret, i; |
2151 | AVDeviceInfoList *device_list = NULL; |
2152 | |
2153 | if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category)) |
2154 | return AVERROR(EINVAL); |
2155 | |
2156 | printf("Auto-detected sinks for %s:\n", fmt->name); |
2157 | if (!fmt->get_device_list) { |
2158 | ret = AVERROR(ENOSYS); |
2159 | printf("Cannot list sinks. Not implemented.\n"); |
2160 | goto fail; |
2161 | } |
2162 | |
2163 | if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) { |
2164 | printf("Cannot list sinks.\n"); |
2165 | goto fail; |
2166 | } |
2167 | |
2168 | for (i = 0; i < device_list->nb_devices; i++) { |
2169 | printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ", |
2170 | device_list->devices[i]->device_name, device_list->devices[i]->device_description); |
2171 | } |
2172 | |
2173 | fail: |
2174 | avdevice_free_list_devices(&device_list); |
2175 | return ret; |
2176 | } |
2177 | |
2178 | static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts) |
2179 | { |
2180 | int ret; |
2181 | if (arg) { |
2182 | char *opts_str = NULL; |
2183 | av_assert0(dev && opts); |
2184 | *dev = av_strdup(arg); |
2185 | if (!*dev) |
2186 | return AVERROR(ENOMEM); |
2187 | if ((opts_str = strchr(*dev, ','))) { |
2188 | *(opts_str++) = '\0'; |
2189 | if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) { |
2190 | av_freep(dev); |
2191 | return ret; |
2192 | } |
2193 | } |
2194 | } else |
2195 | printf("\nDevice name is not provided.\n" |
2196 | "You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n"); |
2197 | return 0; |
2198 | } |
2199 | |
2200 | int show_sources(void *optctx, const char *opt, const char *arg) |
2201 | { |
2202 | AVInputFormat *fmt = NULL; |
2203 | char *dev = NULL; |
2204 | AVDictionary *opts = NULL; |
2205 | int ret = 0; |
2206 | int error_level = av_log_get_level(); |
2207 | |
2208 | av_log_set_level(AV_LOG_ERROR); |
2209 | |
2210 | if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0) |
2211 | goto fail; |
2212 | |
2213 | do { |
2214 | fmt = av_input_audio_device_next(fmt); |
2215 | if (fmt) { |
2216 | if (!strcmp(fmt->name, "lavfi")) |
2217 | continue; //it's pointless to probe lavfi |
2218 | if (dev && !av_match_name(dev, fmt->name)) |
2219 | continue; |
2220 | print_device_sources(fmt, opts); |
2221 | } |
2222 | } while (fmt); |
2223 | do { |
2224 | fmt = av_input_video_device_next(fmt); |
2225 | if (fmt) { |
2226 | if (dev && !av_match_name(dev, fmt->name)) |
2227 | continue; |
2228 | print_device_sources(fmt, opts); |
2229 | } |
2230 | } while (fmt); |
2231 | fail: |
2232 | av_dict_free(&opts); |
2233 | av_free(dev); |
2234 | av_log_set_level(error_level); |
2235 | return ret; |
2236 | } |
2237 | |
2238 | int show_sinks(void *optctx, const char *opt, const char *arg) |
2239 | { |
2240 | AVOutputFormat *fmt = NULL; |
2241 | char *dev = NULL; |
2242 | AVDictionary *opts = NULL; |
2243 | int ret = 0; |
2244 | int error_level = av_log_get_level(); |
2245 | |
2246 | av_log_set_level(AV_LOG_ERROR); |
2247 | |
2248 | if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0) |
2249 | goto fail; |
2250 | |
2251 | do { |
2252 | fmt = av_output_audio_device_next(fmt); |
2253 | if (fmt) { |
2254 | if (dev && !av_match_name(dev, fmt->name)) |
2255 | continue; |
2256 | print_device_sinks(fmt, opts); |
2257 | } |
2258 | } while (fmt); |
2259 | do { |
2260 | fmt = av_output_video_device_next(fmt); |
2261 | if (fmt) { |
2262 | if (dev && !av_match_name(dev, fmt->name)) |
2263 | continue; |
2264 | print_device_sinks(fmt, opts); |
2265 | } |
2266 | } while (fmt); |
2267 | fail: |
2268 | av_dict_free(&opts); |
2269 | av_free(dev); |
2270 | av_log_set_level(error_level); |
2271 | return ret; |
2272 | } |
2273 | |
2274 | #endif |
2275 |