xref: /third_party/ffmpeg/fftools/cmdutils.c (revision cabdff1a)
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 "libswscale/swscale.h"
36#include "libswscale/version.h"
37#include "libswresample/swresample.h"
38#include "libavutil/avassert.h"
39#include "libavutil/avstring.h"
40#include "libavutil/channel_layout.h"
41#include "libavutil/display.h"
42#include "libavutil/getenv_utf8.h"
43#include "libavutil/mathematics.h"
44#include "libavutil/imgutils.h"
45#include "libavutil/libm.h"
46#include "libavutil/parseutils.h"
47#include "libavutil/eval.h"
48#include "libavutil/dict.h"
49#include "libavutil/opt.h"
50#include "cmdutils.h"
51#include "fopen_utf8.h"
52#include "opt_common.h"
53#ifdef _WIN32
54#include <windows.h>
55#include "compat/w32dlfcn.h"
56#endif
57
58AVDictionary *sws_dict;
59AVDictionary *swr_opts;
60AVDictionary *format_opts, *codec_opts;
61
62int hide_banner = 0;
63
64void uninit_opts(void)
65{
66    av_dict_free(&swr_opts);
67    av_dict_free(&sws_dict);
68    av_dict_free(&format_opts);
69    av_dict_free(&codec_opts);
70}
71
72void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
73{
74    vfprintf(stdout, fmt, vl);
75}
76
77void init_dynload(void)
78{
79#if HAVE_SETDLLDIRECTORY && defined(_WIN32)
80    /* Calling SetDllDirectory with the empty string (but not NULL) removes the
81     * current working directory from the DLL search path as a security pre-caution. */
82    SetDllDirectory("");
83#endif
84}
85
86static void (*program_exit)(int ret);
87
88void register_exit(void (*cb)(int ret))
89{
90    program_exit = cb;
91}
92
93void exit_program(int ret)
94{
95    if (program_exit)
96        program_exit(ret);
97
98    exit(ret);
99}
100
101double parse_number_or_die(const char *context, const char *numstr, int type,
102                           double min, double max)
103{
104    char *tail;
105    const char *error;
106    double d = av_strtod(numstr, &tail);
107    if (*tail)
108        error = "Expected number for %s but found: %s\n";
109    else if (d < min || d > max)
110        error = "The value for %s was %s which is not within %f - %f\n";
111    else if (type == OPT_INT64 && (int64_t)d != d)
112        error = "Expected int64 for %s but found %s\n";
113    else if (type == OPT_INT && (int)d != d)
114        error = "Expected int for %s but found %s\n";
115    else
116        return d;
117    av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max);
118    exit_program(1);
119    return 0;
120}
121
122int64_t parse_time_or_die(const char *context, const char *timestr,
123                          int is_duration)
124{
125    int64_t us;
126    if (av_parse_time(&us, timestr, is_duration) < 0) {
127        av_log(NULL, AV_LOG_FATAL, "Invalid %s specification for %s: %s\n",
128               is_duration ? "duration" : "date", context, timestr);
129        exit_program(1);
130    }
131    return us;
132}
133
134void show_help_options(const OptionDef *options, const char *msg, int req_flags,
135                       int rej_flags, int alt_flags)
136{
137    const OptionDef *po;
138    int first;
139
140    first = 1;
141    for (po = options; po->name; po++) {
142        char buf[128];
143
144        if (((po->flags & req_flags) != req_flags) ||
145            (alt_flags && !(po->flags & alt_flags)) ||
146            (po->flags & rej_flags))
147            continue;
148
149        if (first) {
150            printf("%s\n", msg);
151            first = 0;
152        }
153        av_strlcpy(buf, po->name, sizeof(buf));
154        if (po->argname) {
155            av_strlcat(buf, " ", sizeof(buf));
156            av_strlcat(buf, po->argname, sizeof(buf));
157        }
158        printf("-%-17s  %s\n", buf, po->help);
159    }
160    printf("\n");
161}
162
163void show_help_children(const AVClass *class, int flags)
164{
165    void *iter = NULL;
166    const AVClass *child;
167    if (class->option) {
168        av_opt_show2(&class, NULL, flags, 0);
169        printf("\n");
170    }
171
172    while (child = av_opt_child_class_iterate(class, &iter))
173        show_help_children(child, flags);
174}
175
176static const OptionDef *find_option(const OptionDef *po, const char *name)
177{
178    while (po->name) {
179        const char *end;
180        if (av_strstart(name, po->name, &end) && (!*end || *end == ':'))
181            break;
182        po++;
183    }
184    return po;
185}
186
187/* _WIN32 means using the windows libc - cygwin doesn't define that
188 * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while
189 * it doesn't provide the actual command line via GetCommandLineW(). */
190#if HAVE_COMMANDLINETOARGVW && defined(_WIN32)
191#include <shellapi.h>
192/* Will be leaked on exit */
193static char** win32_argv_utf8 = NULL;
194static int win32_argc = 0;
195
196/**
197 * Prepare command line arguments for executable.
198 * For Windows - perform wide-char to UTF-8 conversion.
199 * Input arguments should be main() function arguments.
200 * @param argc_ptr Arguments number (including executable)
201 * @param argv_ptr Arguments list.
202 */
203static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)
204{
205    char *argstr_flat;
206    wchar_t **argv_w;
207    int i, buffsize = 0, offset = 0;
208
209    if (win32_argv_utf8) {
210        *argc_ptr = win32_argc;
211        *argv_ptr = win32_argv_utf8;
212        return;
213    }
214
215    win32_argc = 0;
216    argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc);
217    if (win32_argc <= 0 || !argv_w)
218        return;
219
220    /* determine the UTF-8 buffer size (including NULL-termination symbols) */
221    for (i = 0; i < win32_argc; i++)
222        buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,
223                                        NULL, 0, NULL, NULL);
224
225    win32_argv_utf8 = av_mallocz(sizeof(char *) * (win32_argc + 1) + buffsize);
226    argstr_flat     = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1);
227    if (!win32_argv_utf8) {
228        LocalFree(argv_w);
229        return;
230    }
231
232    for (i = 0; i < win32_argc; i++) {
233        win32_argv_utf8[i] = &argstr_flat[offset];
234        offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,
235                                      &argstr_flat[offset],
236                                      buffsize - offset, NULL, NULL);
237    }
238    win32_argv_utf8[i] = NULL;
239    LocalFree(argv_w);
240
241    *argc_ptr = win32_argc;
242    *argv_ptr = win32_argv_utf8;
243}
244#else
245static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)
246{
247    /* nothing to do */
248}
249#endif /* HAVE_COMMANDLINETOARGVW */
250
251static int write_option(void *optctx, const OptionDef *po, const char *opt,
252                        const char *arg)
253{
254    /* new-style options contain an offset into optctx, old-style address of
255     * a global var*/
256    void *dst = po->flags & (OPT_OFFSET | OPT_SPEC) ?
257                (uint8_t *)optctx + po->u.off : po->u.dst_ptr;
258    int *dstcount;
259
260    if (po->flags & OPT_SPEC) {
261        SpecifierOpt **so = dst;
262        char *p = strchr(opt, ':');
263        char *str;
264
265        dstcount = (int *)(so + 1);
266        *so = grow_array(*so, sizeof(**so), dstcount, *dstcount + 1);
267        str = av_strdup(p ? p + 1 : "");
268        if (!str)
269            return AVERROR(ENOMEM);
270        (*so)[*dstcount - 1].specifier = str;
271        dst = &(*so)[*dstcount - 1].u;
272    }
273
274    if (po->flags & OPT_STRING) {
275        char *str;
276        str = av_strdup(arg);
277        av_freep(dst);
278        if (!str)
279            return AVERROR(ENOMEM);
280        *(char **)dst = str;
281    } else if (po->flags & OPT_BOOL || po->flags & OPT_INT) {
282        *(int *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
283    } else if (po->flags & OPT_INT64) {
284        *(int64_t *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT64_MIN, INT64_MAX);
285    } else if (po->flags & OPT_TIME) {
286        *(int64_t *)dst = parse_time_or_die(opt, arg, 1);
287    } else if (po->flags & OPT_FLOAT) {
288        *(float *)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY);
289    } else if (po->flags & OPT_DOUBLE) {
290        *(double *)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY);
291    } else if (po->u.func_arg) {
292        int ret = po->u.func_arg(optctx, opt, arg);
293        if (ret < 0) {
294            av_log(NULL, AV_LOG_ERROR,
295                   "Failed to set value '%s' for option '%s': %s\n",
296                   arg, opt, av_err2str(ret));
297            return ret;
298        }
299    }
300    if (po->flags & OPT_EXIT)
301        exit_program(0);
302
303    return 0;
304}
305
306int parse_option(void *optctx, const char *opt, const char *arg,
307                 const OptionDef *options)
308{
309    static const OptionDef opt_avoptions = {
310        .name       = "AVOption passthrough",
311        .flags      = HAS_ARG,
312        .u.func_arg = opt_default,
313    };
314
315    const OptionDef *po;
316    int ret;
317
318    po = find_option(options, opt);
319    if (!po->name && opt[0] == 'n' && opt[1] == 'o') {
320        /* handle 'no' bool option */
321        po = find_option(options, opt + 2);
322        if ((po->name && (po->flags & OPT_BOOL)))
323            arg = "0";
324    } else if (po->flags & OPT_BOOL)
325        arg = "1";
326
327    if (!po->name)
328        po = &opt_avoptions;
329    if (!po->name) {
330        av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt);
331        return AVERROR(EINVAL);
332    }
333    if (po->flags & HAS_ARG && !arg) {
334        av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'\n", opt);
335        return AVERROR(EINVAL);
336    }
337
338    ret = write_option(optctx, po, opt, arg);
339    if (ret < 0)
340        return ret;
341
342    return !!(po->flags & HAS_ARG);
343}
344
345void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
346                   void (*parse_arg_function)(void *, const char*))
347{
348    const char *opt;
349    int optindex, handleoptions = 1, ret;
350
351    /* perform system-dependent conversions for arguments list */
352    prepare_app_arguments(&argc, &argv);
353
354    /* parse options */
355    optindex = 1;
356    while (optindex < argc) {
357        opt = argv[optindex++];
358
359        if (handleoptions && opt[0] == '-' && opt[1] != '\0') {
360            if (opt[1] == '-' && opt[2] == '\0') {
361                handleoptions = 0;
362                continue;
363            }
364            opt++;
365
366            if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0)
367                exit_program(1);
368            optindex += ret;
369        } else {
370            if (parse_arg_function)
371                parse_arg_function(optctx, opt);
372        }
373    }
374}
375
376int parse_optgroup(void *optctx, OptionGroup *g)
377{
378    int i, ret;
379
380    av_log(NULL, AV_LOG_DEBUG, "Parsing a group of options: %s %s.\n",
381           g->group_def->name, g->arg);
382
383    for (i = 0; i < g->nb_opts; i++) {
384        Option *o = &g->opts[i];
385
386        if (g->group_def->flags &&
387            !(g->group_def->flags & o->opt->flags)) {
388            av_log(NULL, AV_LOG_ERROR, "Option %s (%s) cannot be applied to "
389                   "%s %s -- you are trying to apply an input option to an "
390                   "output file or vice versa. Move this option before the "
391                   "file it belongs to.\n", o->key, o->opt->help,
392                   g->group_def->name, g->arg);
393            return AVERROR(EINVAL);
394        }
395
396        av_log(NULL, AV_LOG_DEBUG, "Applying option %s (%s) with argument %s.\n",
397               o->key, o->opt->help, o->val);
398
399        ret = write_option(optctx, o->opt, o->key, o->val);
400        if (ret < 0)
401            return ret;
402    }
403
404    av_log(NULL, AV_LOG_DEBUG, "Successfully parsed a group of options.\n");
405
406    return 0;
407}
408
409int locate_option(int argc, char **argv, const OptionDef *options,
410                  const char *optname)
411{
412    const OptionDef *po;
413    int i;
414
415    for (i = 1; i < argc; i++) {
416        const char *cur_opt = argv[i];
417
418        if (*cur_opt++ != '-')
419            continue;
420
421        po = find_option(options, cur_opt);
422        if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o')
423            po = find_option(options, cur_opt + 2);
424
425        if ((!po->name && !strcmp(cur_opt, optname)) ||
426             (po->name && !strcmp(optname, po->name)))
427            return i;
428
429        if (!po->name || po->flags & HAS_ARG)
430            i++;
431    }
432    return 0;
433}
434
435static void dump_argument(FILE *report_file, const char *a)
436{
437    const unsigned char *p;
438
439    for (p = a; *p; p++)
440        if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||
441              *p == '_' || (*p >= 'a' && *p <= 'z')))
442            break;
443    if (!*p) {
444        fputs(a, report_file);
445        return;
446    }
447    fputc('"', report_file);
448    for (p = a; *p; p++) {
449        if (*p == '\\' || *p == '"' || *p == '$' || *p == '`')
450            fprintf(report_file, "\\%c", *p);
451        else if (*p < ' ' || *p > '~')
452            fprintf(report_file, "\\x%02x", *p);
453        else
454            fputc(*p, report_file);
455    }
456    fputc('"', report_file);
457}
458
459static void check_options(const OptionDef *po)
460{
461    while (po->name) {
462        if (po->flags & OPT_PERFILE)
463            av_assert0(po->flags & (OPT_INPUT | OPT_OUTPUT));
464        po++;
465    }
466}
467
468void parse_loglevel(int argc, char **argv, const OptionDef *options)
469{
470    int idx = locate_option(argc, argv, options, "loglevel");
471    char *env;
472
473    check_options(options);
474
475    if (!idx)
476        idx = locate_option(argc, argv, options, "v");
477    if (idx && argv[idx + 1])
478        opt_loglevel(NULL, "loglevel", argv[idx + 1]);
479    idx = locate_option(argc, argv, options, "report");
480    env = getenv_utf8("FFREPORT");
481    if (env || idx) {
482        FILE *report_file = NULL;
483        init_report(env, &report_file);
484        if (report_file) {
485            int i;
486            fprintf(report_file, "Command line:\n");
487            for (i = 0; i < argc; i++) {
488                dump_argument(report_file, argv[i]);
489                fputc(i < argc - 1 ? ' ' : '\n', report_file);
490            }
491            fflush(report_file);
492        }
493    }
494    freeenv_utf8(env);
495    idx = locate_option(argc, argv, options, "hide_banner");
496    if (idx)
497        hide_banner = 1;
498}
499
500static const AVOption *opt_find(void *obj, const char *name, const char *unit,
501                            int opt_flags, int search_flags)
502{
503    const AVOption *o = av_opt_find(obj, name, unit, opt_flags, search_flags);
504    if(o && !o->flags)
505        return NULL;
506    return o;
507}
508
509#define FLAGS (o->type == AV_OPT_TYPE_FLAGS && (arg[0]=='-' || arg[0]=='+')) ? AV_DICT_APPEND : 0
510int opt_default(void *optctx, const char *opt, const char *arg)
511{
512    const AVOption *o;
513    int consumed = 0;
514    char opt_stripped[128];
515    const char *p;
516    const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class();
517#if CONFIG_SWSCALE
518    const AVClass *sc = sws_get_class();
519#endif
520#if CONFIG_SWRESAMPLE
521    const AVClass *swr_class = swr_get_class();
522#endif
523
524    if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug"))
525        av_log_set_level(AV_LOG_DEBUG);
526
527    if (!(p = strchr(opt, ':')))
528        p = opt + strlen(opt);
529    av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1));
530
531    if ((o = opt_find(&cc, opt_stripped, NULL, 0,
532                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) ||
533        ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') &&
534         (o = opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) {
535        av_dict_set(&codec_opts, opt, arg, FLAGS);
536        consumed = 1;
537    }
538    if ((o = opt_find(&fc, opt, NULL, 0,
539                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
540        av_dict_set(&format_opts, opt, arg, FLAGS);
541        if (consumed)
542            av_log(NULL, AV_LOG_VERBOSE, "Routing option %s to both codec and muxer layer\n", opt);
543        consumed = 1;
544    }
545#if CONFIG_SWSCALE
546    if (!consumed && (o = opt_find(&sc, opt, NULL, 0,
547                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
548        if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") ||
549            !strcmp(opt, "dstw") || !strcmp(opt, "dsth") ||
550            !strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) {
551            av_log(NULL, AV_LOG_ERROR, "Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n");
552            return AVERROR(EINVAL);
553        }
554        av_dict_set(&sws_dict, opt, arg, FLAGS);
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    if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,
566                                    AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
567        av_dict_set(&swr_opts, opt, arg, FLAGS);
568        consumed = 1;
569    }
570#endif
571
572    if (consumed)
573        return 0;
574    return AVERROR_OPTION_NOT_FOUND;
575}
576
577/*
578 * Check whether given option is a group separator.
579 *
580 * @return index of the group definition that matched or -1 if none
581 */
582static int match_group_separator(const OptionGroupDef *groups, int nb_groups,
583                                 const char *opt)
584{
585    int i;
586
587    for (i = 0; i < nb_groups; i++) {
588        const OptionGroupDef *p = &groups[i];
589        if (p->sep && !strcmp(p->sep, opt))
590            return i;
591    }
592
593    return -1;
594}
595
596/*
597 * Finish parsing an option group.
598 *
599 * @param group_idx which group definition should this group belong to
600 * @param arg argument of the group delimiting option
601 */
602static void finish_group(OptionParseContext *octx, int group_idx,
603                         const char *arg)
604{
605    OptionGroupList *l = &octx->groups[group_idx];
606    OptionGroup *g;
607
608    GROW_ARRAY(l->groups, l->nb_groups);
609    g = &l->groups[l->nb_groups - 1];
610
611    *g             = octx->cur_group;
612    g->arg         = arg;
613    g->group_def   = l->group_def;
614    g->sws_dict    = sws_dict;
615    g->swr_opts    = swr_opts;
616    g->codec_opts  = codec_opts;
617    g->format_opts = format_opts;
618
619    codec_opts  = NULL;
620    format_opts = NULL;
621    sws_dict    = NULL;
622    swr_opts    = NULL;
623
624    memset(&octx->cur_group, 0, sizeof(octx->cur_group));
625}
626
627/*
628 * Add an option instance to currently parsed group.
629 */
630static void add_opt(OptionParseContext *octx, const OptionDef *opt,
631                    const char *key, const char *val)
632{
633    int global = !(opt->flags & (OPT_PERFILE | OPT_SPEC | OPT_OFFSET));
634    OptionGroup *g = global ? &octx->global_opts : &octx->cur_group;
635
636    GROW_ARRAY(g->opts, g->nb_opts);
637    g->opts[g->nb_opts - 1].opt = opt;
638    g->opts[g->nb_opts - 1].key = key;
639    g->opts[g->nb_opts - 1].val = val;
640}
641
642static void init_parse_context(OptionParseContext *octx,
643                               const OptionGroupDef *groups, int nb_groups)
644{
645    static const OptionGroupDef global_group = { "global" };
646    int i;
647
648    memset(octx, 0, sizeof(*octx));
649
650    octx->nb_groups = nb_groups;
651    octx->groups    = av_calloc(octx->nb_groups, sizeof(*octx->groups));
652    if (!octx->groups)
653        exit_program(1);
654
655    for (i = 0; i < octx->nb_groups; i++)
656        octx->groups[i].group_def = &groups[i];
657
658    octx->global_opts.group_def = &global_group;
659    octx->global_opts.arg       = "";
660}
661
662void uninit_parse_context(OptionParseContext *octx)
663{
664    int i, j;
665
666    for (i = 0; i < octx->nb_groups; i++) {
667        OptionGroupList *l = &octx->groups[i];
668
669        for (j = 0; j < l->nb_groups; j++) {
670            av_freep(&l->groups[j].opts);
671            av_dict_free(&l->groups[j].codec_opts);
672            av_dict_free(&l->groups[j].format_opts);
673
674            av_dict_free(&l->groups[j].sws_dict);
675            av_dict_free(&l->groups[j].swr_opts);
676        }
677        av_freep(&l->groups);
678    }
679    av_freep(&octx->groups);
680
681    av_freep(&octx->cur_group.opts);
682    av_freep(&octx->global_opts.opts);
683
684    uninit_opts();
685}
686
687int split_commandline(OptionParseContext *octx, int argc, char *argv[],
688                      const OptionDef *options,
689                      const OptionGroupDef *groups, int nb_groups)
690{
691    int optindex = 1;
692    int dashdash = -2;
693
694    /* perform system-dependent conversions for arguments list */
695    prepare_app_arguments(&argc, &argv);
696
697    init_parse_context(octx, groups, nb_groups);
698    av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n");
699
700    while (optindex < argc) {
701        const char *opt = argv[optindex++], *arg;
702        const OptionDef *po;
703        int ret;
704
705        av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt);
706
707        if (opt[0] == '-' && opt[1] == '-' && !opt[2]) {
708            dashdash = optindex;
709            continue;
710        }
711        /* unnamed group separators, e.g. output filename */
712        if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) {
713            finish_group(octx, 0, opt);
714            av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name);
715            continue;
716        }
717        opt++;
718
719#define GET_ARG(arg)                                                           \
720do {                                                                           \
721    arg = argv[optindex++];                                                    \
722    if (!arg) {                                                                \
723        av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\
724        return AVERROR(EINVAL);                                                \
725    }                                                                          \
726} while (0)
727
728        /* named group separators, e.g. -i */
729        if ((ret = match_group_separator(groups, nb_groups, opt)) >= 0) {
730            GET_ARG(arg);
731            finish_group(octx, ret, arg);
732            av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument '%s'.\n",
733                   groups[ret].name, arg);
734            continue;
735        }
736
737        /* normal options */
738        po = find_option(options, opt);
739        if (po->name) {
740            if (po->flags & OPT_EXIT) {
741                /* optional argument, e.g. -h */
742                arg = argv[optindex++];
743            } else if (po->flags & HAS_ARG) {
744                GET_ARG(arg);
745            } else {
746                arg = "1";
747            }
748
749            add_opt(octx, po, opt, arg);
750            av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with "
751                   "argument '%s'.\n", po->name, po->help, arg);
752            continue;
753        }
754
755        /* AVOptions */
756        if (argv[optindex]) {
757            ret = opt_default(NULL, opt, argv[optindex]);
758            if (ret >= 0) {
759                av_log(NULL, AV_LOG_DEBUG, " matched as AVOption '%s' with "
760                       "argument '%s'.\n", opt, argv[optindex]);
761                optindex++;
762                continue;
763            } else if (ret != AVERROR_OPTION_NOT_FOUND) {
764                av_log(NULL, AV_LOG_ERROR, "Error parsing option '%s' "
765                       "with argument '%s'.\n", opt, argv[optindex]);
766                return ret;
767            }
768        }
769
770        /* boolean -nofoo options */
771        if (opt[0] == 'n' && opt[1] == 'o' &&
772            (po = find_option(options, opt + 2)) &&
773            po->name && po->flags & OPT_BOOL) {
774            add_opt(octx, po, opt, "0");
775            av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with "
776                   "argument 0.\n", po->name, po->help);
777            continue;
778        }
779
780        av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'.\n", opt);
781        return AVERROR_OPTION_NOT_FOUND;
782    }
783
784    if (octx->cur_group.nb_opts || codec_opts || format_opts)
785        av_log(NULL, AV_LOG_WARNING, "Trailing option(s) found in the "
786               "command: may be ignored.\n");
787
788    av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n");
789
790    return 0;
791}
792
793void print_error(const char *filename, int err)
794{
795    char errbuf[128];
796    const char *errbuf_ptr = errbuf;
797
798    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
799        errbuf_ptr = strerror(AVUNERROR(err));
800    av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr);
801}
802
803int read_yesno(void)
804{
805    int c = getchar();
806    int yesno = (av_toupper(c) == 'Y');
807
808    while (c != '\n' && c != EOF)
809        c = getchar();
810
811    return yesno;
812}
813
814FILE *get_preset_file(char *filename, size_t filename_size,
815                      const char *preset_name, int is_path,
816                      const char *codec_name)
817{
818    FILE *f = NULL;
819    int i;
820#if HAVE_GETMODULEHANDLE && defined(_WIN32)
821    char *datadir = NULL;
822#endif
823    char *env_home = getenv_utf8("HOME");
824    char *env_ffmpeg_datadir = getenv_utf8("FFMPEG_DATADIR");
825    const char *base[3] = { env_ffmpeg_datadir,
826                            env_home,   /* index=1(HOME) is special: search in a .ffmpeg subfolder */
827                            FFMPEG_DATADIR, };
828
829    if (is_path) {
830        av_strlcpy(filename, preset_name, filename_size);
831        f = fopen_utf8(filename, "r");
832    } else {
833#if HAVE_GETMODULEHANDLE && defined(_WIN32)
834        wchar_t *datadir_w = get_module_filename(NULL);
835        base[2] = NULL;
836
837        if (wchartoutf8(datadir_w, &datadir))
838            datadir = NULL;
839        av_free(datadir_w);
840
841        if (datadir)
842        {
843            char *ls;
844            for (ls = datadir; *ls; ls++)
845                if (*ls == '\\') *ls = '/';
846
847            if (ls = strrchr(datadir, '/'))
848            {
849                ptrdiff_t datadir_len = ls - datadir;
850                size_t desired_size = datadir_len + strlen("/ffpresets") + 1;
851                char *new_datadir = av_realloc_array(
852                    datadir, desired_size, sizeof *datadir);
853                if (new_datadir) {
854                    datadir = new_datadir;
855                    datadir[datadir_len] = 0;
856                    strncat(datadir, "/ffpresets",  desired_size - 1 - datadir_len);
857                    base[2] = datadir;
858                }
859            }
860        }
861#endif
862        for (i = 0; i < 3 && !f; i++) {
863            if (!base[i])
864                continue;
865            snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i],
866                     i != 1 ? "" : "/.ffmpeg", preset_name);
867            f = fopen_utf8(filename, "r");
868            if (!f && codec_name) {
869                snprintf(filename, filename_size,
870                         "%s%s/%s-%s.ffpreset",
871                         base[i], i != 1 ? "" : "/.ffmpeg", codec_name,
872                         preset_name);
873                f = fopen_utf8(filename, "r");
874            }
875        }
876    }
877
878#if HAVE_GETMODULEHANDLE && defined(_WIN32)
879    av_free(datadir);
880#endif
881    freeenv_utf8(env_ffmpeg_datadir);
882    freeenv_utf8(env_home);
883    return f;
884}
885
886int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
887{
888    int ret = avformat_match_stream_specifier(s, st, spec);
889    if (ret < 0)
890        av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
891    return ret;
892}
893
894AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
895                                AVFormatContext *s, AVStream *st, const AVCodec *codec)
896{
897    AVDictionary    *ret = NULL;
898    const AVDictionaryEntry *t = NULL;
899    int            flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM
900                                      : AV_OPT_FLAG_DECODING_PARAM;
901    char          prefix = 0;
902    const AVClass    *cc = avcodec_get_class();
903
904    if (!codec)
905        codec            = s->oformat ? avcodec_find_encoder(codec_id)
906                                      : avcodec_find_decoder(codec_id);
907
908    switch (st->codecpar->codec_type) {
909    case AVMEDIA_TYPE_VIDEO:
910        prefix  = 'v';
911        flags  |= AV_OPT_FLAG_VIDEO_PARAM;
912        break;
913    case AVMEDIA_TYPE_AUDIO:
914        prefix  = 'a';
915        flags  |= AV_OPT_FLAG_AUDIO_PARAM;
916        break;
917    case AVMEDIA_TYPE_SUBTITLE:
918        prefix  = 's';
919        flags  |= AV_OPT_FLAG_SUBTITLE_PARAM;
920        break;
921    }
922
923    while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) {
924        const AVClass *priv_class;
925        char *p = strchr(t->key, ':');
926
927        /* check stream specification in opt name */
928        if (p)
929            switch (check_stream_specifier(s, st, p + 1)) {
930            case  1: *p = 0; break;
931            case  0:         continue;
932            default:         exit_program(1);
933            }
934
935        if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
936            !codec ||
937            ((priv_class = codec->priv_class) &&
938             av_opt_find(&priv_class, t->key, NULL, flags,
939                         AV_OPT_SEARCH_FAKE_OBJ)))
940            av_dict_set(&ret, t->key, t->value, 0);
941        else if (t->key[0] == prefix &&
942                 av_opt_find(&cc, t->key + 1, NULL, flags,
943                             AV_OPT_SEARCH_FAKE_OBJ))
944            av_dict_set(&ret, t->key + 1, t->value, 0);
945
946        if (p)
947            *p = ':';
948    }
949    return ret;
950}
951
952AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
953                                           AVDictionary *codec_opts)
954{
955    int i;
956    AVDictionary **opts;
957
958    if (!s->nb_streams)
959        return NULL;
960    opts = av_calloc(s->nb_streams, sizeof(*opts));
961    if (!opts) {
962        av_log(NULL, AV_LOG_ERROR,
963               "Could not alloc memory for stream options.\n");
964        exit_program(1);
965    }
966    for (i = 0; i < s->nb_streams; i++)
967        opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,
968                                    s, s->streams[i], NULL);
969    return opts;
970}
971
972void *grow_array(void *array, int elem_size, int *size, int new_size)
973{
974    if (new_size >= INT_MAX / elem_size) {
975        av_log(NULL, AV_LOG_ERROR, "Array too big.\n");
976        exit_program(1);
977    }
978    if (*size < new_size) {
979        uint8_t *tmp = av_realloc_array(array, new_size, elem_size);
980        if (!tmp) {
981            av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
982            exit_program(1);
983        }
984        memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
985        *size = new_size;
986        return tmp;
987    }
988    return array;
989}
990
991void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems)
992{
993    void *new_elem;
994
995    if (!(new_elem = av_mallocz(elem_size)) ||
996        av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) {
997        av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
998        exit_program(1);
999    }
1000    return new_elem;
1001}
1002
1003double get_rotation(int32_t *displaymatrix)
1004{
1005    double theta = 0;
1006    if (displaymatrix)
1007        theta = -round(av_display_rotation_get((int32_t*) displaymatrix));
1008
1009    theta -= 360*floor(theta/360 + 0.9/360);
1010
1011    if (fabs(theta - 90*round(theta/90)) > 2)
1012        av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n"
1013               "If you want to help, upload a sample "
1014               "of this file to https://streams.videolan.org/upload/ "
1015               "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)");
1016
1017    return theta;
1018}
1019