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