| Line | Branch | Exec | Source |
|---|---|---|---|
| 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 "libavformat/avformat.h" | ||
| 34 | #include "libswscale/swscale.h" | ||
| 35 | #include "libswresample/swresample.h" | ||
| 36 | #include "libavutil/avassert.h" | ||
| 37 | #include "libavutil/avstring.h" | ||
| 38 | #include "libavutil/bprint.h" | ||
| 39 | #include "libavutil/display.h" | ||
| 40 | #include "libavutil/getenv_utf8.h" | ||
| 41 | #include "libavutil/libm.h" | ||
| 42 | #include "libavutil/mem.h" | ||
| 43 | #include "libavutil/parseutils.h" | ||
| 44 | #include "libavutil/eval.h" | ||
| 45 | #include "libavutil/dict.h" | ||
| 46 | #include "libavutil/opt.h" | ||
| 47 | #include "cmdutils.h" | ||
| 48 | #include "fopen_utf8.h" | ||
| 49 | #include "opt_common.h" | ||
| 50 | #ifdef _WIN32 | ||
| 51 | #include <windows.h> | ||
| 52 | #include "compat/w32dlfcn.h" | ||
| 53 | #endif | ||
| 54 | |||
| 55 | AVDictionary *sws_dict; | ||
| 56 | AVDictionary *swr_opts; | ||
| 57 | AVDictionary *format_opts, *codec_opts; | ||
| 58 | |||
| 59 | int hide_banner = 0; | ||
| 60 | |||
| 61 | 17907 | void uninit_opts(void) | |
| 62 | { | ||
| 63 | 17907 | av_dict_free(&swr_opts); | |
| 64 | 17907 | av_dict_free(&sws_dict); | |
| 65 | 17907 | av_dict_free(&format_opts); | |
| 66 | 17907 | av_dict_free(&codec_opts); | |
| 67 | 17907 | } | |
| 68 | |||
| 69 | ✗ | void log_callback_help(void *ptr, int level, const char *fmt, va_list vl) | |
| 70 | { | ||
| 71 | ✗ | vfprintf(stdout, fmt, vl); | |
| 72 | ✗ | } | |
| 73 | |||
| 74 | 9094 | void init_dynload(void) | |
| 75 | { | ||
| 76 | #if HAVE_SETDLLDIRECTORY && defined(_WIN32) | ||
| 77 | /* Calling SetDllDirectory with the empty string (but not NULL) removes the | ||
| 78 | * current working directory from the DLL search path as a security pre-caution. */ | ||
| 79 | SetDllDirectory(""); | ||
| 80 | #endif | ||
| 81 | 9094 | } | |
| 82 | |||
| 83 | 40134 | int parse_number(const char *context, const char *numstr, enum OptionType type, | |
| 84 | double min, double max, double *dst) | ||
| 85 | { | ||
| 86 | char *tail; | ||
| 87 | const char *error; | ||
| 88 | 40134 | double d = av_strtod(numstr, &tail); | |
| 89 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40134 times.
|
40134 | if (*tail) |
| 90 | ✗ | error = "Expected number for %s but found: %s\n"; | |
| 91 |
2/4✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40134 times.
|
40134 | else if (d < min || d > max) |
| 92 | ✗ | error = "The value for %s was %s which is not within %f - %f\n"; | |
| 93 |
3/4✓ Branch 0 taken 39832 times.
✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39832 times.
|
40134 | else if (type == OPT_TYPE_INT64 && (int64_t)d != d) |
| 94 | ✗ | error = "Expected int64 for %s but found %s\n"; | |
| 95 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 40134 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
40134 | else if (type == OPT_TYPE_INT && (int)d != d) |
| 96 | ✗ | error = "Expected int for %s but found %s\n"; | |
| 97 | else { | ||
| 98 | 40134 | *dst = d; | |
| 99 | 40134 | return 0; | |
| 100 | } | ||
| 101 | |||
| 102 | ✗ | av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max); | |
| 103 | ✗ | return AVERROR(EINVAL); | |
| 104 | } | ||
| 105 | |||
| 106 | ✗ | void show_help_options(const OptionDef *options, const char *msg, int req_flags, | |
| 107 | int rej_flags) | ||
| 108 | { | ||
| 109 | const OptionDef *po; | ||
| 110 | int first; | ||
| 111 | |||
| 112 | ✗ | first = 1; | |
| 113 | ✗ | for (po = options; po->name; po++) { | |
| 114 | char buf[128]; | ||
| 115 | |||
| 116 | ✗ | if (((po->flags & req_flags) != req_flags) || | |
| 117 | ✗ | (po->flags & rej_flags)) | |
| 118 | ✗ | continue; | |
| 119 | |||
| 120 | ✗ | if (first) { | |
| 121 | ✗ | printf("%s\n", msg); | |
| 122 | ✗ | first = 0; | |
| 123 | } | ||
| 124 | ✗ | av_strlcpy(buf, po->name, sizeof(buf)); | |
| 125 | |||
| 126 | ✗ | if (po->flags & OPT_FLAG_PERSTREAM) | |
| 127 | ✗ | av_strlcat(buf, "[:<stream_spec>]", sizeof(buf)); | |
| 128 | ✗ | else if (po->flags & OPT_FLAG_SPEC) | |
| 129 | ✗ | av_strlcat(buf, "[:<spec>]", sizeof(buf)); | |
| 130 | |||
| 131 | ✗ | if (po->argname) | |
| 132 | ✗ | av_strlcatf(buf, sizeof(buf), " <%s>", po->argname); | |
| 133 | |||
| 134 | ✗ | printf("-%-17s %s\n", buf, po->help); | |
| 135 | } | ||
| 136 | ✗ | printf("\n"); | |
| 137 | ✗ | } | |
| 138 | |||
| 139 | ✗ | void show_help_children(const AVClass *class, int flags) | |
| 140 | { | ||
| 141 | ✗ | void *iter = NULL; | |
| 142 | const AVClass *child; | ||
| 143 | ✗ | if (class->option) { | |
| 144 | ✗ | av_opt_show2(&class, NULL, flags, 0); | |
| 145 | ✗ | printf("\n"); | |
| 146 | } | ||
| 147 | |||
| 148 | ✗ | while (child = av_opt_child_class_iterate(class, &iter)) | |
| 149 | ✗ | show_help_children(child, flags); | |
| 150 | ✗ | } | |
| 151 | |||
| 152 | 1350060 | static const OptionDef *find_option(const OptionDef *po, const char *name) | |
| 153 | { | ||
| 154 |
2/2✓ Branch 0 taken 396 times.
✓ Branch 1 taken 1349664 times.
|
1350060 | if (*name == '/') |
| 155 | 396 | name++; | |
| 156 | |||
| 157 |
2/2✓ Branch 0 taken 199005629 times.
✓ Branch 1 taken 767127 times.
|
199772756 | while (po->name) { |
| 158 | const char *end; | ||
| 159 |
6/6✓ Branch 1 taken 1372805 times.
✓ Branch 2 taken 197632824 times.
✓ Branch 3 taken 843776 times.
✓ Branch 4 taken 529029 times.
✓ Branch 5 taken 789872 times.
✓ Branch 6 taken 53904 times.
|
199005629 | if (av_strstart(name, po->name, &end) && (!*end || *end == ':')) |
| 160 | break; | ||
| 161 | 198422696 | po++; | |
| 162 | } | ||
| 163 | 1350060 | return po; | |
| 164 | } | ||
| 165 | |||
| 166 | /* _WIN32 means using the windows libc - cygwin doesn't define that | ||
| 167 | * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while | ||
| 168 | * it doesn't provide the actual command line via GetCommandLineW(). */ | ||
| 169 | #if HAVE_COMMANDLINETOARGVW && defined(_WIN32) | ||
| 170 | #include <shellapi.h> | ||
| 171 | /* Will be leaked on exit */ | ||
| 172 | static char** win32_argv_utf8 = NULL; | ||
| 173 | static int win32_argc = 0; | ||
| 174 | |||
| 175 | /** | ||
| 176 | * Prepare command line arguments for executable. | ||
| 177 | * For Windows - perform wide-char to UTF-8 conversion. | ||
| 178 | * Input arguments should be main() function arguments. | ||
| 179 | * @param argc_ptr Arguments number (including executable) | ||
| 180 | * @param argv_ptr Arguments list. | ||
| 181 | */ | ||
| 182 | static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) | ||
| 183 | { | ||
| 184 | char *argstr_flat; | ||
| 185 | wchar_t **argv_w; | ||
| 186 | int i, buffsize = 0, offset = 0; | ||
| 187 | |||
| 188 | if (win32_argv_utf8) { | ||
| 189 | *argc_ptr = win32_argc; | ||
| 190 | *argv_ptr = win32_argv_utf8; | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | |||
| 194 | win32_argc = 0; | ||
| 195 | argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc); | ||
| 196 | if (win32_argc <= 0 || !argv_w) | ||
| 197 | return; | ||
| 198 | |||
| 199 | /* determine the UTF-8 buffer size (including NULL-termination symbols) */ | ||
| 200 | for (i = 0; i < win32_argc; i++) | ||
| 201 | buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, | ||
| 202 | NULL, 0, NULL, NULL); | ||
| 203 | |||
| 204 | win32_argv_utf8 = av_mallocz(sizeof(char *) * (win32_argc + 1) + buffsize); | ||
| 205 | argstr_flat = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1); | ||
| 206 | if (!win32_argv_utf8) { | ||
| 207 | LocalFree(argv_w); | ||
| 208 | return; | ||
| 209 | } | ||
| 210 | |||
| 211 | for (i = 0; i < win32_argc; i++) { | ||
| 212 | win32_argv_utf8[i] = &argstr_flat[offset]; | ||
| 213 | offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, | ||
| 214 | &argstr_flat[offset], | ||
| 215 | buffsize - offset, NULL, NULL); | ||
| 216 | } | ||
| 217 | win32_argv_utf8[i] = NULL; | ||
| 218 | LocalFree(argv_w); | ||
| 219 | |||
| 220 | *argc_ptr = win32_argc; | ||
| 221 | *argv_ptr = win32_argv_utf8; | ||
| 222 | } | ||
| 223 | #else | ||
| 224 | 9094 | static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) | |
| 225 | { | ||
| 226 | /* nothing to do */ | ||
| 227 | 9094 | } | |
| 228 | #endif /* HAVE_COMMANDLINETOARGVW */ | ||
| 229 | |||
| 230 | 564989 | static int opt_has_arg(const OptionDef *o) | |
| 231 | { | ||
| 232 |
2/2✓ Branch 0 taken 179240 times.
✓ Branch 1 taken 385749 times.
|
564989 | if (o->type == OPT_TYPE_BOOL) |
| 233 | 179240 | return 0; | |
| 234 |
2/2✓ Branch 0 taken 135443 times.
✓ Branch 1 taken 250306 times.
|
385749 | if (o->type == OPT_TYPE_FUNC) |
| 235 | 135443 | return !!(o->flags & OPT_FUNC_ARG); | |
| 236 | 250306 | return 1; | |
| 237 | } | ||
| 238 | |||
| 239 | 105191 | static int write_option(void *optctx, const OptionDef *po, const char *opt, | |
| 240 | const char *arg, const OptionDef *defs) | ||
| 241 | { | ||
| 242 | /* new-style options contain an offset into optctx, old-style address of | ||
| 243 | * a global var*/ | ||
| 244 | 210382 | void *dst = po->flags & OPT_FLAG_OFFSET ? | |
| 245 |
2/2✓ Branch 0 taken 50550 times.
✓ Branch 1 taken 54641 times.
|
105191 | (uint8_t *)optctx + po->u.off : po->u.dst_ptr; |
| 246 | 105191 | char *arg_allocated = NULL; | |
| 247 | |||
| 248 | 105191 | enum OptionType so_type = po->type; | |
| 249 | |||
| 250 | 105191 | SpecifierOptList *sol = NULL; | |
| 251 | double num; | ||
| 252 | 105191 | int ret = 0; | |
| 253 | |||
| 254 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 105125 times.
|
105191 | if (*opt == '/') { |
| 255 | 66 | opt++; | |
| 256 | |||
| 257 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
|
66 | if (!opt_has_arg(po)) { |
| 258 | ✗ | av_log(NULL, AV_LOG_FATAL, | |
| 259 | "Requested to load an argument from file for an option '%s'" | ||
| 260 | " which does not take an argument\n", | ||
| 261 | ✗ | po->name); | |
| 262 | ✗ | return AVERROR(EINVAL); | |
| 263 | } | ||
| 264 | |||
| 265 | 66 | arg_allocated = read_file_to_string(arg); | |
| 266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | if (!arg_allocated) { |
| 267 | ✗ | av_log(NULL, AV_LOG_FATAL, | |
| 268 | "Error reading the value for option '%s' from file: %s\n", | ||
| 269 | opt, arg); | ||
| 270 | ✗ | return AVERROR(EINVAL); | |
| 271 | } | ||
| 272 | |||
| 273 | 66 | arg = arg_allocated; | |
| 274 | } | ||
| 275 | |||
| 276 |
2/2✓ Branch 0 taken 34169 times.
✓ Branch 1 taken 71022 times.
|
105191 | if (po->flags & OPT_FLAG_SPEC) { |
| 277 | 34169 | const char *p = strchr(opt, ':'); | |
| 278 | char *str; | ||
| 279 | |||
| 280 | 34169 | sol = dst; | |
| 281 | 34169 | ret = GROW_ARRAY(sol->opt, sol->nb_opt); | |
| 282 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34169 times.
|
34169 | if (ret < 0) |
| 283 | ✗ | goto finish; | |
| 284 | |||
| 285 |
2/2✓ Branch 0 taken 16951 times.
✓ Branch 1 taken 17218 times.
|
34169 | str = av_strdup(p ? p + 1 : ""); |
| 286 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34169 times.
|
34169 | if (!str) { |
| 287 | ✗ | ret = AVERROR(ENOMEM); | |
| 288 | ✗ | goto finish; | |
| 289 | } | ||
| 290 | 34169 | sol->opt[sol->nb_opt - 1].specifier = str; | |
| 291 | |||
| 292 |
2/2✓ Branch 0 taken 33848 times.
✓ Branch 1 taken 321 times.
|
34169 | if (po->flags & OPT_FLAG_PERSTREAM) { |
| 293 | 33848 | ret = stream_specifier_parse(&sol->opt[sol->nb_opt - 1].stream_spec, | |
| 294 | str, 0, NULL); | ||
| 295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33848 times.
|
33848 | if (ret < 0) |
| 296 | ✗ | goto finish; | |
| 297 | } | ||
| 298 | |||
| 299 | 34169 | dst = &sol->opt[sol->nb_opt - 1].u; | |
| 300 | } | ||
| 301 | |||
| 302 |
2/2✓ Branch 0 taken 40996 times.
✓ Branch 1 taken 64195 times.
|
105191 | if (po->type == OPT_TYPE_STRING) { |
| 303 | char *str; | ||
| 304 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 40969 times.
|
40996 | if (arg_allocated) { |
| 305 | 27 | str = arg_allocated; | |
| 306 | 27 | arg_allocated = NULL; | |
| 307 | } else | ||
| 308 | 40969 | str = av_strdup(arg); | |
| 309 | 40996 | av_freep(dst); | |
| 310 | |||
| 311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40996 times.
|
40996 | if (!str) { |
| 312 | ✗ | ret = AVERROR(ENOMEM); | |
| 313 | ✗ | goto finish; | |
| 314 | } | ||
| 315 | |||
| 316 | 40996 | *(char **)dst = str; | |
| 317 |
4/4✓ Branch 0 taken 29955 times.
✓ Branch 1 taken 34240 times.
✓ Branch 2 taken 150 times.
✓ Branch 3 taken 29805 times.
|
64195 | } else if (po->type == OPT_TYPE_BOOL || po->type == OPT_TYPE_INT) { |
| 318 | 34390 | ret = parse_number(opt, arg, OPT_TYPE_INT64, INT_MIN, INT_MAX, &num); | |
| 319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34390 times.
|
34390 | if (ret < 0) |
| 320 | ✗ | goto finish; | |
| 321 | |||
| 322 | 34390 | *(int *)dst = num; | |
| 323 | 34390 | so_type = OPT_TYPE_INT; | |
| 324 |
2/2✓ Branch 0 taken 5442 times.
✓ Branch 1 taken 24363 times.
|
29805 | } else if (po->type == OPT_TYPE_INT64) { |
| 325 | 5442 | ret = parse_number(opt, arg, OPT_TYPE_INT64, INT64_MIN, (double)INT64_MAX, &num); | |
| 326 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5442 times.
|
5442 | if (ret < 0) |
| 327 | ✗ | goto finish; | |
| 328 | |||
| 329 | 5442 | *(int64_t *)dst = num; | |
| 330 |
2/2✓ Branch 0 taken 1391 times.
✓ Branch 1 taken 22972 times.
|
24363 | } else if (po->type == OPT_TYPE_TIME) { |
| 331 | 1391 | ret = av_parse_time(dst, arg, 1); | |
| 332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1391 times.
|
1391 | if (ret < 0) { |
| 333 | ✗ | av_log(NULL, AV_LOG_ERROR, "Invalid duration for option %s: %s\n", | |
| 334 | opt, arg); | ||
| 335 | ✗ | goto finish; | |
| 336 | } | ||
| 337 | 1391 | so_type = OPT_TYPE_INT64; | |
| 338 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 22969 times.
|
22972 | } else if (po->type == OPT_TYPE_FLOAT) { |
| 339 | 3 | ret = parse_number(opt, arg, OPT_TYPE_FLOAT, -INFINITY, INFINITY, &num); | |
| 340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
| 341 | ✗ | goto finish; | |
| 342 | |||
| 343 | 3 | *(float *)dst = num; | |
| 344 |
2/2✓ Branch 0 taken 299 times.
✓ Branch 1 taken 22670 times.
|
22969 | } else if (po->type == OPT_TYPE_DOUBLE) { |
| 345 | 299 | ret = parse_number(opt, arg, OPT_TYPE_DOUBLE, -INFINITY, INFINITY, &num); | |
| 346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 299 times.
|
299 | if (ret < 0) |
| 347 | ✗ | goto finish; | |
| 348 | |||
| 349 | 299 | *(double *)dst = num; | |
| 350 | } else { | ||
| 351 |
2/4✓ Branch 0 taken 22670 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22670 times.
|
22670 | av_assert0(po->type == OPT_TYPE_FUNC && po->u.func_arg); |
| 352 | |||
| 353 | 22670 | ret = po->u.func_arg(optctx, opt, arg); | |
| 354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22670 times.
|
22670 | if (ret < 0) { |
| 355 | ✗ | if ((strcmp(opt, "init_hw_device") != 0) || (strcmp(arg, "list") != 0)) { | |
| 356 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
| 357 | "Failed to set value '%s' for option '%s': %s\n", | ||
| 358 | ✗ | arg, opt, av_err2str(ret)); | |
| 359 | } | ||
| 360 | ✗ | goto finish; | |
| 361 | } | ||
| 362 | } | ||
| 363 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 105189 times.
|
105191 | if (po->flags & OPT_EXIT) { |
| 364 | 2 | ret = AVERROR_EXIT; | |
| 365 | 2 | goto finish; | |
| 366 | } | ||
| 367 | |||
| 368 |
2/2✓ Branch 0 taken 71020 times.
✓ Branch 1 taken 34169 times.
|
105189 | if (sol) { |
| 369 | 34169 | sol->type = so_type; | |
| 370 |
2/2✓ Branch 0 taken 2794 times.
✓ Branch 1 taken 31375 times.
|
36963 | sol->opt_canon = (po->flags & OPT_HAS_CANON) ? |
| 371 | 2794 | find_option(defs, po->u1.name_canon) : po; | |
| 372 | } | ||
| 373 | |||
| 374 | 71020 | finish: | |
| 375 | 105191 | av_freep(&arg_allocated); | |
| 376 | 105191 | return ret; | |
| 377 | } | ||
| 378 | |||
| 379 | 10923 | int parse_option(void *optctx, const char *opt, const char *arg, | |
| 380 | const OptionDef *options) | ||
| 381 | { | ||
| 382 | static const OptionDef opt_avoptions = { | ||
| 383 | .name = "AVOption passthrough", | ||
| 384 | .type = OPT_TYPE_FUNC, | ||
| 385 | .flags = OPT_FUNC_ARG, | ||
| 386 | .u.func_arg = opt_default, | ||
| 387 | }; | ||
| 388 | |||
| 389 | const OptionDef *po; | ||
| 390 | int ret; | ||
| 391 | |||
| 392 | 10923 | po = find_option(options, opt); | |
| 393 |
5/6✓ Branch 0 taken 224 times.
✓ Branch 1 taken 10699 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 223 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
10923 | if (!po->name && opt[0] == 'n' && opt[1] == 'o') { |
| 394 | /* handle 'no' bool option */ | ||
| 395 | 1 | po = find_option(options, opt + 2); | |
| 396 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if ((po->name && po->type == OPT_TYPE_BOOL)) |
| 397 | 1 | arg = "0"; | |
| 398 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 10656 times.
|
10922 | } else if (po->type == OPT_TYPE_BOOL) |
| 399 | 266 | arg = "1"; | |
| 400 | |||
| 401 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 10700 times.
|
10923 | if (!po->name) |
| 402 | 223 | po = &opt_avoptions; | |
| 403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10923 times.
|
10923 | if (!po->name) { |
| 404 | ✗ | av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt); | |
| 405 | ✗ | return AVERROR(EINVAL); | |
| 406 | } | ||
| 407 |
3/4✓ Branch 1 taken 10517 times.
✓ Branch 2 taken 406 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10517 times.
|
10923 | if (opt_has_arg(po) && !arg) { |
| 408 | ✗ | av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'\n", opt); | |
| 409 | ✗ | return AVERROR(EINVAL); | |
| 410 | } | ||
| 411 | |||
| 412 | 10923 | ret = write_option(optctx, po, opt, arg, options); | |
| 413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10923 times.
|
10923 | if (ret < 0) |
| 414 | ✗ | return ret; | |
| 415 | |||
| 416 | 10923 | return opt_has_arg(po); | |
| 417 | } | ||
| 418 | |||
| 419 | 281 | int parse_options(void *optctx, int argc, char **argv, const OptionDef *options, | |
| 420 | int (*parse_arg_function)(void *, const char*)) | ||
| 421 | { | ||
| 422 | const char *opt; | ||
| 423 | 281 | int optindex, handleoptions = 1, ret; | |
| 424 | |||
| 425 | /* perform system-dependent conversions for arguments list */ | ||
| 426 | 281 | prepare_app_arguments(&argc, &argv); | |
| 427 | |||
| 428 | /* parse options */ | ||
| 429 | 281 | optindex = 1; | |
| 430 |
2/2✓ Branch 0 taken 1382 times.
✓ Branch 1 taken 281 times.
|
1663 | while (optindex < argc) { |
| 431 | 1382 | opt = argv[optindex++]; | |
| 432 | |||
| 433 |
4/6✓ Branch 0 taken 1382 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1112 times.
✓ Branch 3 taken 270 times.
✓ Branch 4 taken 1112 times.
✗ Branch 5 not taken.
|
1382 | if (handleoptions && opt[0] == '-' && opt[1] != '\0') { |
| 434 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1112 | if (opt[1] == '-' && opt[2] == '\0') { |
| 435 | ✗ | handleoptions = 0; | |
| 436 | ✗ | continue; | |
| 437 | } | ||
| 438 | 1112 | opt++; | |
| 439 | |||
| 440 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1112 times.
|
1112 | if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0) |
| 441 | ✗ | return ret; | |
| 442 | 1112 | optindex += ret; | |
| 443 | } else { | ||
| 444 |
1/2✓ Branch 0 taken 270 times.
✗ Branch 1 not taken.
|
270 | if (parse_arg_function) { |
| 445 | 270 | ret = parse_arg_function(optctx, opt); | |
| 446 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 270 times.
|
270 | if (ret < 0) |
| 447 | ✗ | return ret; | |
| 448 | } | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | 281 | return 0; | |
| 453 | } | ||
| 454 | |||
| 455 | 25342 | int parse_optgroup(void *optctx, OptionGroup *g, const OptionDef *defs) | |
| 456 | { | ||
| 457 | int i, ret; | ||
| 458 | |||
| 459 | 25342 | av_log(NULL, AV_LOG_DEBUG, "Parsing a group of options: %s %s.\n", | |
| 460 | 25342 | g->group_def->name, g->arg); | |
| 461 | |||
| 462 |
2/2✓ Branch 0 taken 94268 times.
✓ Branch 1 taken 25340 times.
|
119608 | for (i = 0; i < g->nb_opts; i++) { |
| 463 | 94268 | Option *o = &g->opts[i]; | |
| 464 | |||
| 465 |
2/2✓ Branch 0 taken 51228 times.
✓ Branch 1 taken 43040 times.
|
94268 | if (g->group_def->flags && |
| 466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51228 times.
|
51228 | !(g->group_def->flags & o->opt->flags)) { |
| 467 | ✗ | av_log(NULL, AV_LOG_ERROR, "Option %s (%s) cannot be applied to " | |
| 468 | "%s %s -- you are trying to apply an input option to an " | ||
| 469 | "output file or vice versa. Move this option before the " | ||
| 470 | ✗ | "file it belongs to.\n", o->key, o->opt->help, | |
| 471 | ✗ | g->group_def->name, g->arg); | |
| 472 | ✗ | return AVERROR(EINVAL); | |
| 473 | } | ||
| 474 | |||
| 475 | 94268 | av_log(NULL, AV_LOG_DEBUG, "Applying option %s (%s) with argument %s.\n", | |
| 476 | 94268 | o->key, o->opt->help, o->val); | |
| 477 | |||
| 478 | 94268 | ret = write_option(optctx, o->opt, o->key, o->val, defs); | |
| 479 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94266 times.
|
94268 | if (ret < 0) |
| 480 | 2 | return ret; | |
| 481 | } | ||
| 482 | |||
| 483 | 25340 | av_log(NULL, AV_LOG_DEBUG, "Successfully parsed a group of options.\n"); | |
| 484 | |||
| 485 | 25340 | return 0; | |
| 486 | } | ||
| 487 | |||
| 488 | 45432 | int locate_option(int argc, char **argv, const OptionDef *options, | |
| 489 | const char *optname) | ||
| 490 | { | ||
| 491 | const OptionDef *po; | ||
| 492 | int i; | ||
| 493 | |||
| 494 |
2/2✓ Branch 0 taken 1034866 times.
✓ Branch 1 taken 45323 times.
|
1080189 | for (i = 1; i < argc; i++) { |
| 495 | 1034866 | const char *cur_opt = argv[i]; | |
| 496 | |||
| 497 |
4/4✓ Branch 0 taken 1004054 times.
✓ Branch 1 taken 30812 times.
✓ Branch 2 taken 14484 times.
✓ Branch 3 taken 989570 times.
|
1034866 | if (!(cur_opt[0] == '-' && cur_opt[1])) |
| 498 | 45296 | continue; | |
| 499 | 989570 | cur_opt++; | |
| 500 | |||
| 501 | 989570 | po = find_option(options, cur_opt); | |
| 502 |
5/6✓ Branch 0 taken 645622 times.
✓ Branch 1 taken 343948 times.
✓ Branch 2 taken 131260 times.
✓ Branch 3 taken 514362 times.
✓ Branch 4 taken 131260 times.
✗ Branch 5 not taken.
|
989570 | if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o') |
| 503 | 131260 | po = find_option(options, cur_opt + 2); | |
| 504 | |||
| 505 |
3/4✓ Branch 0 taken 514402 times.
✓ Branch 1 taken 475168 times.
✓ Branch 2 taken 514402 times.
✗ Branch 3 not taken.
|
989570 | if ((!po->name && !strcmp(cur_opt, optname)) || |
| 506 |
4/4✓ Branch 0 taken 475168 times.
✓ Branch 1 taken 514402 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 475059 times.
|
989570 | (po->name && !strcmp(optname, po->name))) |
| 507 | 109 | return i; | |
| 508 | |||
| 509 |
4/4✓ Branch 0 taken 475059 times.
✓ Branch 1 taken 514402 times.
✓ Branch 3 taken 303370 times.
✓ Branch 4 taken 171689 times.
|
989461 | if (!po->name || opt_has_arg(po)) |
| 510 | 817772 | i++; | |
| 511 | } | ||
| 512 | 45323 | return 0; | |
| 513 | } | ||
| 514 | |||
| 515 | ✗ | static void dump_argument(FILE *report_file, const char *a) | |
| 516 | { | ||
| 517 | const unsigned char *p; | ||
| 518 | |||
| 519 | ✗ | for (p = a; *p; p++) | |
| 520 | ✗ | if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') || | |
| 521 | ✗ | *p == '_' || (*p >= 'a' && *p <= 'z'))) | |
| 522 | break; | ||
| 523 | ✗ | if (!*p) { | |
| 524 | ✗ | fputs(a, report_file); | |
| 525 | ✗ | return; | |
| 526 | } | ||
| 527 | ✗ | fputc('"', report_file); | |
| 528 | ✗ | for (p = a; *p; p++) { | |
| 529 | ✗ | if (*p == '\\' || *p == '"' || *p == '$' || *p == '`') | |
| 530 | ✗ | fprintf(report_file, "\\%c", *p); | |
| 531 | ✗ | else if (*p < ' ' || *p > '~') | |
| 532 | ✗ | fprintf(report_file, "\\x%02x", *p); | |
| 533 | else | ||
| 534 | ✗ | fputc(*p, report_file); | |
| 535 | } | ||
| 536 | ✗ | fputc('"', report_file); | |
| 537 | } | ||
| 538 | |||
| 539 | 9094 | static void check_options(const OptionDef *po) | |
| 540 | { | ||
| 541 |
2/2✓ Branch 0 taken 1739329 times.
✓ Branch 1 taken 9094 times.
|
1748423 | while (po->name) { |
| 542 |
2/2✓ Branch 0 taken 1075186 times.
✓ Branch 1 taken 664143 times.
|
1739329 | if (po->flags & OPT_PERFILE) |
| 543 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1075186 times.
|
1075186 | av_assert0(po->flags & (OPT_INPUT | OPT_OUTPUT | OPT_DECODER)); |
| 544 | |||
| 545 |
2/2✓ Branch 0 taken 649710 times.
✓ Branch 1 taken 1089619 times.
|
1739329 | if (po->type == OPT_TYPE_FUNC) |
| 546 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 649710 times.
|
649710 | av_assert0(!(po->flags & (OPT_FLAG_OFFSET | OPT_FLAG_SPEC))); |
| 547 | |||
| 548 | // OPT_FUNC_ARG can only be ser for OPT_TYPE_FUNC | ||
| 549 |
3/4✓ Branch 0 taken 1089619 times.
✓ Branch 1 taken 649710 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1089619 times.
|
1739329 | av_assert0((po->type == OPT_TYPE_FUNC) || !(po->flags & OPT_FUNC_ARG)); |
| 550 | |||
| 551 | 1739329 | po++; | |
| 552 | } | ||
| 553 | 9094 | } | |
| 554 | |||
| 555 | 9094 | void parse_loglevel(int argc, char **argv, const OptionDef *options) | |
| 556 | { | ||
| 557 | int idx; | ||
| 558 | char *env; | ||
| 559 | |||
| 560 | 9094 | check_options(options); | |
| 561 | |||
| 562 | 9094 | idx = locate_option(argc, argv, options, "loglevel"); | |
| 563 |
2/2✓ Branch 0 taken 9056 times.
✓ Branch 1 taken 38 times.
|
9094 | if (!idx) |
| 564 | 9056 | idx = locate_option(argc, argv, options, "v"); | |
| 565 |
3/4✓ Branch 0 taken 76 times.
✓ Branch 1 taken 9018 times.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
9094 | if (idx && argv[idx + 1]) |
| 566 | 76 | opt_loglevel(NULL, "loglevel", argv[idx + 1]); | |
| 567 | 9094 | idx = locate_option(argc, argv, options, "report"); | |
| 568 | 9094 | env = getenv_utf8("FFREPORT"); | |
| 569 |
2/4✓ Branch 0 taken 9094 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9094 times.
|
9094 | if (env || idx) { |
| 570 | ✗ | FILE *report_file = NULL; | |
| 571 | ✗ | init_report(env, &report_file); | |
| 572 | ✗ | if (report_file) { | |
| 573 | int i; | ||
| 574 | ✗ | fprintf(report_file, "Command line:\n"); | |
| 575 | ✗ | for (i = 0; i < argc; i++) { | |
| 576 | ✗ | dump_argument(report_file, argv[i]); | |
| 577 | ✗ | fputc(i < argc - 1 ? ' ' : '\n', report_file); | |
| 578 | } | ||
| 579 | ✗ | fflush(report_file); | |
| 580 | } | ||
| 581 | } | ||
| 582 | 9094 | freeenv_utf8(env); | |
| 583 | 9094 | idx = locate_option(argc, argv, options, "hide_banner"); | |
| 584 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 9061 times.
|
9094 | if (idx) |
| 585 | 33 | hide_banner = 1; | |
| 586 | 9094 | } | |
| 587 | |||
| 588 | 327888 | static const AVOption *opt_find(void *obj, const char *name, const char *unit, | |
| 589 | int opt_flags, int search_flags) | ||
| 590 | { | ||
| 591 | 327888 | const AVOption *o = av_opt_find(obj, name, unit, opt_flags, search_flags); | |
| 592 |
4/4✓ Branch 0 taken 95305 times.
✓ Branch 1 taken 232583 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 95299 times.
|
327888 | if(o && !o->flags) |
| 593 | 6 | return NULL; | |
| 594 | 327882 | return o; | |
| 595 | } | ||
| 596 | |||
| 597 | #define FLAGS ((o->type == AV_OPT_TYPE_FLAGS && (arg[0]=='-' || arg[0]=='+')) ? AV_DICT_APPEND : 0) | ||
| 598 | 121464 | int opt_default(void *optctx, const char *opt, const char *arg) | |
| 599 | { | ||
| 600 | const AVOption *o; | ||
| 601 | 121464 | int consumed = 0; | |
| 602 | char opt_stripped[128]; | ||
| 603 | const char *p; | ||
| 604 | 121464 | const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(); | |
| 605 | #if CONFIG_SWSCALE | ||
| 606 | 121464 | const AVClass *sc = sws_get_class(); | |
| 607 | #endif | ||
| 608 | #if CONFIG_SWRESAMPLE | ||
| 609 | 121464 | const AVClass *swr_class = swr_get_class(); | |
| 610 | #endif | ||
| 611 | |||
| 612 |
2/4✓ Branch 0 taken 121464 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 121464 times.
|
121464 | if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug")) |
| 613 | ✗ | av_log_set_level(AV_LOG_DEBUG); | |
| 614 | |||
| 615 |
2/2✓ Branch 0 taken 121452 times.
✓ Branch 1 taken 12 times.
|
121464 | if (!(p = strchr(opt, ':'))) |
| 616 | 121452 | p = opt + strlen(opt); | |
| 617 | 121464 | av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1)); | |
| 618 | |||
| 619 |
2/2✓ Branch 1 taken 58755 times.
✓ Branch 2 taken 62709 times.
|
121464 | if ((o = opt_find(&cc, opt_stripped, NULL, 0, |
| 620 | 58755 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) || | |
| 621 |
8/8✓ Branch 0 taken 58749 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 58736 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 16234 times.
✓ Branch 5 taken 42502 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 16252 times.
|
75008 | ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') && |
| 622 | 16253 | (o = opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) { | |
| 623 |
5/6✓ Branch 0 taken 23455 times.
✓ Branch 1 taken 39255 times.
✓ Branch 2 taken 23455 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16159 times.
✓ Branch 5 taken 7296 times.
|
62710 | av_dict_set(&codec_opts, opt, arg, FLAGS); |
| 624 | 62710 | consumed = 1; | |
| 625 | } | ||
| 626 |
2/2✓ Branch 1 taken 16384 times.
✓ Branch 2 taken 105080 times.
|
121464 | if ((o = opt_find(&fc, opt, NULL, 0, |
| 627 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { | ||
| 628 |
5/6✓ Branch 0 taken 16046 times.
✓ Branch 1 taken 338 times.
✓ Branch 2 taken 16046 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16029 times.
✓ Branch 5 taken 17 times.
|
16384 | av_dict_set(&format_opts, opt, arg, FLAGS); |
| 629 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 16298 times.
|
16384 | if (consumed) |
| 630 | 86 | av_log(NULL, AV_LOG_VERBOSE, "Routing option %s to both codec and muxer layer\n", opt); | |
| 631 | 16384 | consumed = 1; | |
| 632 | } | ||
| 633 | #if CONFIG_SWSCALE | ||
| 634 |
4/4✓ Branch 0 taken 42456 times.
✓ Branch 1 taken 79008 times.
✓ Branch 3 taken 16205 times.
✓ Branch 4 taken 26251 times.
|
121464 | if (!consumed && (o = opt_find(&sc, opt, NULL, 0, |
| 635 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { | ||
| 636 |
2/4✓ Branch 0 taken 16205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16205 times.
✗ Branch 3 not taken.
|
16205 | if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") || |
| 637 |
2/4✓ Branch 0 taken 16205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16205 times.
✗ Branch 3 not taken.
|
16205 | !strcmp(opt, "dstw") || !strcmp(opt, "dsth") || |
| 638 |
2/4✓ Branch 0 taken 16205 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16205 times.
|
16205 | !strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) { |
| 639 | ✗ | av_log(NULL, AV_LOG_ERROR, "Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n"); | |
| 640 | ✗ | return AVERROR(EINVAL); | |
| 641 | } | ||
| 642 |
4/6✓ Branch 0 taken 16205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16205 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15990 times.
✓ Branch 5 taken 215 times.
|
16205 | av_dict_set(&sws_dict, opt, arg, FLAGS); |
| 643 | |||
| 644 | 16205 | consumed = 1; | |
| 645 | } | ||
| 646 | #else | ||
| 647 | if (!consumed && !strcmp(opt, "sws_flags")) { | ||
| 648 | av_log(NULL, AV_LOG_WARNING, "Ignoring %s %s, due to disabled swscale\n", opt, arg); | ||
| 649 | consumed = 1; | ||
| 650 | } | ||
| 651 | #endif | ||
| 652 | #if CONFIG_SWRESAMPLE | ||
| 653 |
3/4✓ Branch 0 taken 26251 times.
✓ Branch 1 taken 95213 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26251 times.
|
121464 | if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0, |
| 654 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { | ||
| 655 | ✗ | av_dict_set(&swr_opts, opt, arg, FLAGS); | |
| 656 | ✗ | consumed = 1; | |
| 657 | } | ||
| 658 | #endif | ||
| 659 | |||
| 660 |
2/2✓ Branch 0 taken 95213 times.
✓ Branch 1 taken 26251 times.
|
121464 | if (consumed) |
| 661 | 95213 | return 0; | |
| 662 | 26251 | return AVERROR_OPTION_NOT_FOUND; | |
| 663 | } | ||
| 664 | |||
| 665 | /* | ||
| 666 | * Check whether given option is a group separator. | ||
| 667 | * | ||
| 668 | * @return index of the group definition that matched or -1 if none | ||
| 669 | */ | ||
| 670 | 196977 | static int match_group_separator(const OptionGroupDef *groups, int nb_groups, | |
| 671 | const char *opt) | ||
| 672 | { | ||
| 673 | int i; | ||
| 674 | |||
| 675 |
2/2✓ Branch 0 taken 583216 times.
✓ Branch 1 taken 189261 times.
|
772477 | for (i = 0; i < nb_groups; i++) { |
| 676 | 583216 | const OptionGroupDef *p = &groups[i]; | |
| 677 |
4/4✓ Branch 0 taken 386239 times.
✓ Branch 1 taken 196977 times.
✓ Branch 2 taken 7716 times.
✓ Branch 3 taken 378523 times.
|
583216 | if (p->sep && !strcmp(p->sep, opt)) |
| 678 | 7716 | return i; | |
| 679 | } | ||
| 680 | |||
| 681 | 189261 | return -1; | |
| 682 | } | ||
| 683 | |||
| 684 | /* | ||
| 685 | * Finish parsing an option group. | ||
| 686 | * | ||
| 687 | * @param group_idx which group definition should this group belong to | ||
| 688 | * @param arg argument of the group delimiting option | ||
| 689 | */ | ||
| 690 | 16531 | static int finish_group(OptionParseContext *octx, int group_idx, | |
| 691 | const char *arg) | ||
| 692 | { | ||
| 693 | 16531 | OptionGroupList *l = &octx->groups[group_idx]; | |
| 694 | OptionGroup *g; | ||
| 695 | int ret; | ||
| 696 | |||
| 697 | 16531 | ret = GROW_ARRAY(l->groups, l->nb_groups); | |
| 698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16531 times.
|
16531 | if (ret < 0) |
| 699 | ✗ | return ret; | |
| 700 | |||
| 701 | 16531 | g = &l->groups[l->nb_groups - 1]; | |
| 702 | |||
| 703 | 16531 | *g = octx->cur_group; | |
| 704 | 16531 | g->arg = arg; | |
| 705 | 16531 | g->group_def = l->group_def; | |
| 706 | 16531 | g->sws_dict = sws_dict; | |
| 707 | 16531 | g->swr_opts = swr_opts; | |
| 708 | 16531 | g->codec_opts = codec_opts; | |
| 709 | 16531 | g->format_opts = format_opts; | |
| 710 | |||
| 711 | 16531 | codec_opts = NULL; | |
| 712 | 16531 | format_opts = NULL; | |
| 713 | 16531 | sws_dict = NULL; | |
| 714 | 16531 | swr_opts = NULL; | |
| 715 | |||
| 716 | 16531 | memset(&octx->cur_group, 0, sizeof(octx->cur_group)); | |
| 717 | |||
| 718 | 16531 | return ret; | |
| 719 | } | ||
| 720 | |||
| 721 | /* | ||
| 722 | * Add an option instance to currently parsed group. | ||
| 723 | */ | ||
| 724 | 94271 | static int add_opt(OptionParseContext *octx, const OptionDef *opt, | |
| 725 | const char *key, const char *val) | ||
| 726 | { | ||
| 727 | 94271 | int global = !(opt->flags & OPT_PERFILE); | |
| 728 |
2/2✓ Branch 0 taken 43040 times.
✓ Branch 1 taken 51231 times.
|
94271 | OptionGroup *g = global ? &octx->global_opts : &octx->cur_group; |
| 729 | int ret; | ||
| 730 | |||
| 731 | 94271 | ret = GROW_ARRAY(g->opts, g->nb_opts); | |
| 732 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94271 times.
|
94271 | if (ret < 0) |
| 733 | ✗ | return ret; | |
| 734 | |||
| 735 | 94271 | g->opts[g->nb_opts - 1].opt = opt; | |
| 736 | 94271 | g->opts[g->nb_opts - 1].key = key; | |
| 737 | 94271 | g->opts[g->nb_opts - 1].val = val; | |
| 738 | |||
| 739 | 94271 | return 0; | |
| 740 | } | ||
| 741 | |||
| 742 | 8813 | static int init_parse_context(OptionParseContext *octx, | |
| 743 | const OptionGroupDef *groups, int nb_groups) | ||
| 744 | { | ||
| 745 | static const OptionGroupDef global_group = { "global" }; | ||
| 746 | int i; | ||
| 747 | |||
| 748 | 8813 | memset(octx, 0, sizeof(*octx)); | |
| 749 | |||
| 750 | 8813 | octx->groups = av_calloc(nb_groups, sizeof(*octx->groups)); | |
| 751 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8813 times.
|
8813 | if (!octx->groups) |
| 752 | ✗ | return AVERROR(ENOMEM); | |
| 753 | 8813 | octx->nb_groups = nb_groups; | |
| 754 | |||
| 755 |
2/2✓ Branch 0 taken 26439 times.
✓ Branch 1 taken 8813 times.
|
35252 | for (i = 0; i < octx->nb_groups; i++) |
| 756 | 26439 | octx->groups[i].group_def = &groups[i]; | |
| 757 | |||
| 758 | 8813 | octx->global_opts.group_def = &global_group; | |
| 759 | 8813 | octx->global_opts.arg = ""; | |
| 760 | |||
| 761 | 8813 | return 0; | |
| 762 | } | ||
| 763 | |||
| 764 | 8813 | void uninit_parse_context(OptionParseContext *octx) | |
| 765 | { | ||
| 766 | int i, j; | ||
| 767 | |||
| 768 |
2/2✓ Branch 0 taken 26439 times.
✓ Branch 1 taken 8813 times.
|
35252 | for (i = 0; i < octx->nb_groups; i++) { |
| 769 | 26439 | OptionGroupList *l = &octx->groups[i]; | |
| 770 | |||
| 771 |
2/2✓ Branch 0 taken 16531 times.
✓ Branch 1 taken 26439 times.
|
42970 | for (j = 0; j < l->nb_groups; j++) { |
| 772 | 16531 | av_freep(&l->groups[j].opts); | |
| 773 | 16531 | av_dict_free(&l->groups[j].codec_opts); | |
| 774 | 16531 | av_dict_free(&l->groups[j].format_opts); | |
| 775 | |||
| 776 | 16531 | av_dict_free(&l->groups[j].sws_dict); | |
| 777 | 16531 | av_dict_free(&l->groups[j].swr_opts); | |
| 778 | } | ||
| 779 | 26439 | av_freep(&l->groups); | |
| 780 | } | ||
| 781 | 8813 | av_freep(&octx->groups); | |
| 782 | |||
| 783 | 8813 | av_freep(&octx->cur_group.opts); | |
| 784 | 8813 | av_freep(&octx->global_opts.opts); | |
| 785 | |||
| 786 | 8813 | uninit_opts(); | |
| 787 | 8813 | } | |
| 788 | |||
| 789 | 8813 | int split_commandline(OptionParseContext *octx, int argc, char *argv[], | |
| 790 | const OptionDef *options, | ||
| 791 | const OptionGroupDef *groups, int nb_groups) | ||
| 792 | { | ||
| 793 | int ret; | ||
| 794 | 8813 | int optindex = 1; | |
| 795 | 8813 | int dashdash = -2; | |
| 796 | |||
| 797 | /* perform system-dependent conversions for arguments list */ | ||
| 798 | 8813 | prepare_app_arguments(&argc, &argv); | |
| 799 | |||
| 800 | 8813 | ret = init_parse_context(octx, groups, nb_groups); | |
| 801 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8813 times.
|
8813 | if (ret < 0) |
| 802 | ✗ | return ret; | |
| 803 | |||
| 804 | 8813 | av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n"); | |
| 805 | |||
| 806 |
2/2✓ Branch 0 taken 205792 times.
✓ Branch 1 taken 8813 times.
|
214605 | while (optindex < argc) { |
| 807 | 205792 | const char *opt = argv[optindex++], *arg; | |
| 808 | const OptionDef *po; | ||
| 809 | int group_idx; | ||
| 810 | |||
| 811 | 205792 | av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt); | |
| 812 | |||
| 813 |
3/6✓ Branch 0 taken 199875 times.
✓ Branch 1 taken 5917 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 199875 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
205792 | if (opt[0] == '-' && opt[1] == '-' && !opt[2]) { |
| 814 | ✗ | dashdash = optindex; | |
| 815 | ✗ | continue; | |
| 816 | } | ||
| 817 | /* unnamed group separators, e.g. output filename */ | ||
| 818 |
5/6✓ Branch 0 taken 199875 times.
✓ Branch 1 taken 5917 times.
✓ Branch 2 taken 196977 times.
✓ Branch 3 taken 2898 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 196977 times.
|
205792 | if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) { |
| 819 | 8815 | ret = finish_group(octx, 0, opt); | |
| 820 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8815 times.
|
8815 | if (ret < 0) |
| 821 | ✗ | return ret; | |
| 822 | |||
| 823 | 8815 | av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name); | |
| 824 | 8815 | continue; | |
| 825 | } | ||
| 826 | 196977 | opt++; | |
| 827 | |||
| 828 | #define GET_ARG(arg) \ | ||
| 829 | do { \ | ||
| 830 | arg = argv[optindex++]; \ | ||
| 831 | if (!arg) { \ | ||
| 832 | av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\ | ||
| 833 | return AVERROR(EINVAL); \ | ||
| 834 | } \ | ||
| 835 | } while (0) | ||
| 836 | |||
| 837 | /* named group separators, e.g. -i */ | ||
| 838 | 196977 | group_idx = match_group_separator(groups, nb_groups, opt); | |
| 839 |
2/2✓ Branch 0 taken 7716 times.
✓ Branch 1 taken 189261 times.
|
196977 | if (group_idx >= 0) { |
| 840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7716 times.
|
7716 | GET_ARG(arg); |
| 841 | 7716 | ret = finish_group(octx, group_idx, arg); | |
| 842 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7716 times.
|
7716 | if (ret < 0) |
| 843 | ✗ | return ret; | |
| 844 | |||
| 845 | 7716 | av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument '%s'.\n", | |
| 846 | 7716 | groups[group_idx].name, arg); | |
| 847 | 7716 | continue; | |
| 848 | } | ||
| 849 | |||
| 850 | /* normal options */ | ||
| 851 | 189261 | po = find_option(options, opt); | |
| 852 |
2/2✓ Branch 0 taken 68020 times.
✓ Branch 1 taken 121241 times.
|
189261 | if (po->name) { |
| 853 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68018 times.
|
68020 | if (po->flags & OPT_EXIT) { |
| 854 | /* optional argument, e.g. -h */ | ||
| 855 | 2 | arg = argv[optindex++]; | |
| 856 |
2/2✓ Branch 1 taken 60296 times.
✓ Branch 2 taken 7722 times.
|
68018 | } else if (opt_has_arg(po)) { |
| 857 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60296 times.
|
60296 | GET_ARG(arg); |
| 858 | } else { | ||
| 859 | 7722 | arg = "1"; | |
| 860 | } | ||
| 861 | |||
| 862 | 68020 | ret = add_opt(octx, po, opt, arg); | |
| 863 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68020 times.
|
68020 | if (ret < 0) |
| 864 | ✗ | return ret; | |
| 865 | |||
| 866 | 68020 | av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " | |
| 867 | 68020 | "argument '%s'.\n", po->name, po->help, arg); | |
| 868 | 68020 | continue; | |
| 869 | } | ||
| 870 | |||
| 871 | /* AVOptions */ | ||
| 872 |
1/2✓ Branch 0 taken 121241 times.
✗ Branch 1 not taken.
|
121241 | if (argv[optindex]) { |
| 873 | 121241 | ret = opt_default(NULL, opt, argv[optindex]); | |
| 874 |
2/2✓ Branch 0 taken 94990 times.
✓ Branch 1 taken 26251 times.
|
121241 | if (ret >= 0) { |
| 875 | 94990 | av_log(NULL, AV_LOG_DEBUG, " matched as AVOption '%s' with " | |
| 876 | 94990 | "argument '%s'.\n", opt, argv[optindex]); | |
| 877 | 94990 | optindex++; | |
| 878 | 94990 | continue; | |
| 879 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26251 times.
|
26251 | } else if (ret != AVERROR_OPTION_NOT_FOUND) { |
| 880 | ✗ | av_log(NULL, AV_LOG_ERROR, "Error parsing option '%s' " | |
| 881 | ✗ | "with argument '%s'.\n", opt, argv[optindex]); | |
| 882 | ✗ | return ret; | |
| 883 | } | ||
| 884 | } | ||
| 885 | |||
| 886 | /* boolean -nofoo options */ | ||
| 887 |
3/6✓ Branch 0 taken 26251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26251 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26251 times.
✗ Branch 5 not taken.
|
52502 | if (opt[0] == 'n' && opt[1] == 'o' && |
| 888 | 26251 | (po = find_option(options, opt + 2)) && | |
| 889 |
2/4✓ Branch 0 taken 26251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26251 times.
✗ Branch 3 not taken.
|
26251 | po->name && po->type == OPT_TYPE_BOOL) { |
| 890 | 26251 | ret = add_opt(octx, po, opt, "0"); | |
| 891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26251 times.
|
26251 | if (ret < 0) |
| 892 | ✗ | return ret; | |
| 893 | |||
| 894 | 26251 | av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " | |
| 895 | 26251 | "argument 0.\n", po->name, po->help); | |
| 896 | 26251 | continue; | |
| 897 | } | ||
| 898 | |||
| 899 | ✗ | av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'.\n", opt); | |
| 900 | ✗ | return AVERROR_OPTION_NOT_FOUND; | |
| 901 | } | ||
| 902 | |||
| 903 |
3/6✓ Branch 0 taken 8813 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8813 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8813 times.
|
8813 | if (octx->cur_group.nb_opts || codec_opts || format_opts) |
| 904 | ✗ | av_log(NULL, AV_LOG_WARNING, "Trailing option(s) found in the " | |
| 905 | "command: may be ignored.\n"); | ||
| 906 | |||
| 907 | 8813 | av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n"); | |
| 908 | |||
| 909 | 8813 | return 0; | |
| 910 | } | ||
| 911 | |||
| 912 | ✗ | int read_yesno(void) | |
| 913 | { | ||
| 914 | ✗ | int c = getchar(); | |
| 915 | ✗ | int yesno = (av_toupper(c) == 'Y'); | |
| 916 | |||
| 917 | ✗ | while (c != '\n' && c != EOF) | |
| 918 | ✗ | c = getchar(); | |
| 919 | |||
| 920 | ✗ | return yesno; | |
| 921 | } | ||
| 922 | |||
| 923 | ✗ | FILE *get_preset_file(char *filename, size_t filename_size, | |
| 924 | const char *preset_name, int is_path, | ||
| 925 | const char *codec_name) | ||
| 926 | { | ||
| 927 | ✗ | FILE *f = NULL; | |
| 928 | int i; | ||
| 929 | #if HAVE_GETMODULEHANDLE && defined(_WIN32) | ||
| 930 | char *datadir = NULL; | ||
| 931 | #endif | ||
| 932 | ✗ | char *env_home = getenv_utf8("HOME"); | |
| 933 | ✗ | char *env_ffmpeg_datadir = getenv_utf8("FFMPEG_DATADIR"); | |
| 934 | ✗ | const char *base[3] = { env_ffmpeg_datadir, | |
| 935 | env_home, /* index=1(HOME) is special: search in a .ffmpeg subfolder */ | ||
| 936 | FFMPEG_DATADIR, }; | ||
| 937 | |||
| 938 | ✗ | if (is_path) { | |
| 939 | ✗ | av_strlcpy(filename, preset_name, filename_size); | |
| 940 | ✗ | f = fopen_utf8(filename, "r"); | |
| 941 | } else { | ||
| 942 | #if HAVE_GETMODULEHANDLE && defined(_WIN32) | ||
| 943 | wchar_t *datadir_w = get_module_filename(NULL); | ||
| 944 | base[2] = NULL; | ||
| 945 | |||
| 946 | if (wchartoutf8(datadir_w, &datadir)) | ||
| 947 | datadir = NULL; | ||
| 948 | av_free(datadir_w); | ||
| 949 | |||
| 950 | if (datadir) | ||
| 951 | { | ||
| 952 | char *ls; | ||
| 953 | for (ls = datadir; *ls; ls++) | ||
| 954 | if (*ls == '\\') *ls = '/'; | ||
| 955 | |||
| 956 | if (ls = strrchr(datadir, '/')) | ||
| 957 | { | ||
| 958 | ptrdiff_t datadir_len = ls - datadir; | ||
| 959 | size_t desired_size = datadir_len + strlen("/ffpresets") + 1; | ||
| 960 | char *new_datadir = av_realloc_array( | ||
| 961 | datadir, desired_size, sizeof *datadir); | ||
| 962 | if (new_datadir) { | ||
| 963 | datadir = new_datadir; | ||
| 964 | strcpy(datadir + datadir_len, "/ffpresets"); | ||
| 965 | base[2] = datadir; | ||
| 966 | } | ||
| 967 | } | ||
| 968 | } | ||
| 969 | #endif | ||
| 970 | ✗ | for (i = 0; i < 3 && !f; i++) { | |
| 971 | ✗ | if (!base[i]) | |
| 972 | ✗ | continue; | |
| 973 | ✗ | snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i], | |
| 974 | i != 1 ? "" : "/.ffmpeg", preset_name); | ||
| 975 | ✗ | f = fopen_utf8(filename, "r"); | |
| 976 | ✗ | if (!f && codec_name) { | |
| 977 | ✗ | snprintf(filename, filename_size, | |
| 978 | "%s%s/%s-%s.ffpreset", | ||
| 979 | base[i], i != 1 ? "" : "/.ffmpeg", codec_name, | ||
| 980 | preset_name); | ||
| 981 | ✗ | f = fopen_utf8(filename, "r"); | |
| 982 | } | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | #if HAVE_GETMODULEHANDLE && defined(_WIN32) | ||
| 987 | av_free(datadir); | ||
| 988 | #endif | ||
| 989 | ✗ | freeenv_utf8(env_ffmpeg_datadir); | |
| 990 | ✗ | freeenv_utf8(env_home); | |
| 991 | ✗ | return f; | |
| 992 | } | ||
| 993 | |||
| 994 | 17638 | int cmdutils_isalnum(char c) | |
| 995 | { | ||
| 996 |
4/4✓ Branch 0 taken 310 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 17586 times.
|
17638 | return (c >= '0' && c <= '9') || |
| 997 |
5/6✓ Branch 0 taken 311 times.
✓ Branch 1 taken 17327 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 17588 times.
|
35325 | (c >= 'A' && c <= 'Z') || |
| 998 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | (c >= 'a' && c <= 'z'); |
| 999 | } | ||
| 1000 | |||
| 1001 | 35064 | void stream_specifier_uninit(StreamSpecifier *ss) | |
| 1002 | { | ||
| 1003 | 35064 | av_freep(&ss->meta_key); | |
| 1004 | 35064 | av_freep(&ss->meta_val); | |
| 1005 | 35064 | av_freep(&ss->remainder); | |
| 1006 | |||
| 1007 | 35064 | memset(ss, 0, sizeof(*ss)); | |
| 1008 | 35064 | } | |
| 1009 | |||
| 1010 | 35060 | int stream_specifier_parse(StreamSpecifier *ss, const char *spec, | |
| 1011 | int allow_remainder, void *logctx) | ||
| 1012 | { | ||
| 1013 | char *endptr; | ||
| 1014 | int ret; | ||
| 1015 | |||
| 1016 | 35060 | memset(ss, 0, sizeof(*ss)); | |
| 1017 | |||
| 1018 | 35060 | ss->idx = -1; | |
| 1019 | 35060 | ss->media_type = AVMEDIA_TYPE_UNKNOWN; | |
| 1020 | 35060 | ss->stream_list = STREAM_LIST_ALL; | |
| 1021 | |||
| 1022 | 35060 | av_log(logctx, AV_LOG_TRACE, "Parsing stream specifier: %s\n", spec); | |
| 1023 | |||
| 1024 |
2/2✓ Branch 0 taken 18240 times.
✓ Branch 1 taken 34447 times.
|
87747 | while (*spec) { |
| 1025 |
3/4✓ Branch 0 taken 518 times.
✓ Branch 1 taken 17722 times.
✓ Branch 2 taken 518 times.
✗ Branch 3 not taken.
|
18240 | if (*spec <= '9' && *spec >= '0') { /* opt:index */ |
| 1026 | 518 | ss->idx = strtol(spec, &endptr, 0); | |
| 1027 | |||
| 1028 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 518 times.
|
518 | av_assert0(endptr > spec); |
| 1029 | 518 | spec = endptr; | |
| 1030 | |||
| 1031 | 518 | av_log(logctx, AV_LOG_TRACE, | |
| 1032 | "Parsed index: %d; remainder: %s\n", ss->idx, spec); | ||
| 1033 | |||
| 1034 | // this terminates the specifier | ||
| 1035 | 518 | break; | |
| 1036 |
6/6✓ Branch 0 taken 1962 times.
✓ Branch 1 taken 15760 times.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 1787 times.
✓ Branch 4 taken 121 times.
✓ Branch 5 taken 54 times.
|
17722 | } else if ((*spec == 'v' || *spec == 'a' || *spec == 's' || |
| 1037 |
7/8✓ Branch 0 taken 118 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 115 times.
✓ Branch 6 taken 17583 times.
✓ Branch 7 taken 24 times.
|
17728 | *spec == 'd' || *spec == 't' || *spec == 'V') && |
| 1038 | 17607 | !cmdutils_isalnum(*(spec + 1))) { /* opt:[vasdtV] */ | |
| 1039 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17583 times.
|
17583 | if (ss->media_type != AVMEDIA_TYPE_UNKNOWN) { |
| 1040 | ✗ | av_log(logctx, AV_LOG_ERROR, "Stream type specified multiple times\n"); | |
| 1041 | ✗ | ret = AVERROR(EINVAL); | |
| 1042 | ✗ | goto fail; | |
| 1043 | } | ||
| 1044 | |||
| 1045 |
5/7✓ Branch 0 taken 15745 times.
✓ Branch 1 taken 1781 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
17583 | switch (*spec++) { |
| 1046 | 15745 | case 'v': ss->media_type = AVMEDIA_TYPE_VIDEO; break; | |
| 1047 | 1781 | case 'a': ss->media_type = AVMEDIA_TYPE_AUDIO; break; | |
| 1048 | 52 | case 's': ss->media_type = AVMEDIA_TYPE_SUBTITLE; break; | |
| 1049 | 2 | case 'd': ss->media_type = AVMEDIA_TYPE_DATA; break; | |
| 1050 | 3 | case 't': ss->media_type = AVMEDIA_TYPE_ATTACHMENT; break; | |
| 1051 | ✗ | case 'V': ss->media_type = AVMEDIA_TYPE_VIDEO; | |
| 1052 | ✗ | ss->no_apic = 1; break; | |
| 1053 | ✗ | default: av_assert0(0); | |
| 1054 | } | ||
| 1055 | |||
| 1056 | 17583 | av_log(logctx, AV_LOG_TRACE, "Parsed media type: %s; remainder: %s\n", | |
| 1057 | av_get_media_type_string(ss->media_type), spec); | ||
| 1058 |
3/4✓ Branch 0 taken 43 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
|
139 | } else if (*spec == 'g' && *(spec + 1) == ':') { |
| 1059 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ss->stream_list != STREAM_LIST_ALL) |
| 1060 | ✗ | goto multiple_stream_lists; | |
| 1061 | |||
| 1062 | 43 | spec += 2; | |
| 1063 |
5/6✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
43 | if (*spec == '#' || (*spec == 'i' && *(spec + 1) == ':')) { |
| 1064 | 5 | ss->stream_list = STREAM_LIST_GROUP_ID; | |
| 1065 | |||
| 1066 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | spec += 1 + (*spec == 'i'); |
| 1067 | } else | ||
| 1068 | 38 | ss->stream_list = STREAM_LIST_GROUP_IDX; | |
| 1069 | |||
| 1070 | 43 | ss->list_id = strtol(spec, &endptr, 0); | |
| 1071 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (spec == endptr) { |
| 1072 | ✗ | av_log(logctx, AV_LOG_ERROR, "Expected stream group idx/ID, got: %s\n", spec); | |
| 1073 | ✗ | ret = AVERROR(EINVAL); | |
| 1074 | ✗ | goto fail; | |
| 1075 | } | ||
| 1076 | 43 | spec = endptr; | |
| 1077 | |||
| 1078 | 43 | av_log(logctx, AV_LOG_TRACE, "Parsed stream group %s: %"PRId64"; remainder: %s\n", | |
| 1079 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 38 times.
|
43 | ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index", ss->list_id, spec); |
| 1080 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
96 | } else if (*spec == 'p' && *(spec + 1) == ':') { |
| 1081 | ✗ | if (ss->stream_list != STREAM_LIST_ALL) | |
| 1082 | ✗ | goto multiple_stream_lists; | |
| 1083 | |||
| 1084 | ✗ | ss->stream_list = STREAM_LIST_PROGRAM; | |
| 1085 | |||
| 1086 | ✗ | spec += 2; | |
| 1087 | ✗ | ss->list_id = strtol(spec, &endptr, 0); | |
| 1088 | ✗ | if (spec == endptr) { | |
| 1089 | ✗ | av_log(logctx, AV_LOG_ERROR, "Expected program ID, got: %s\n", spec); | |
| 1090 | ✗ | ret = AVERROR(EINVAL); | |
| 1091 | ✗ | goto fail; | |
| 1092 | } | ||
| 1093 | ✗ | spec = endptr; | |
| 1094 | |||
| 1095 | ✗ | av_log(logctx, AV_LOG_TRACE, | |
| 1096 | "Parsed program ID: %"PRId64"; remainder: %s\n", ss->list_id, spec); | ||
| 1097 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
|
96 | } else if (!strncmp(spec, "disp:", 5)) { |
| 1098 | 1 | const AVClass *st_class = av_stream_get_class(); | |
| 1099 | 1 | const AVOption *o = av_opt_find(&st_class, "disposition", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ); | |
| 1100 | 1 | char *disp = NULL; | |
| 1101 | size_t len; | ||
| 1102 | |||
| 1103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | av_assert0(o); |
| 1104 | |||
| 1105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ss->disposition) { |
| 1106 | ✗ | av_log(logctx, AV_LOG_ERROR, "Multiple disposition specifiers\n"); | |
| 1107 | ✗ | ret = AVERROR(EINVAL); | |
| 1108 | ✗ | goto fail; | |
| 1109 | } | ||
| 1110 | |||
| 1111 | 1 | spec += 5; | |
| 1112 | |||
| 1113 | 29 | for (len = 0; cmdutils_isalnum(spec[len]) || | |
| 1114 |
6/6✓ Branch 0 taken 26 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
57 | spec[len] == '_' || spec[len] == '+'; len++) |
| 1115 | 28 | continue; | |
| 1116 | |||
| 1117 | 1 | disp = av_strndup(spec, len); | |
| 1118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!disp) { |
| 1119 | ✗ | ret = AVERROR(ENOMEM); | |
| 1120 | ✗ | goto fail; | |
| 1121 | } | ||
| 1122 | |||
| 1123 | 1 | ret = av_opt_eval_flags(&st_class, o, disp, &ss->disposition); | |
| 1124 | 1 | av_freep(&disp); | |
| 1125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) { |
| 1126 | ✗ | av_log(logctx, AV_LOG_ERROR, "Invalid disposition specifier\n"); | |
| 1127 | ✗ | goto fail; | |
| 1128 | } | ||
| 1129 | |||
| 1130 | 1 | spec += len; | |
| 1131 | |||
| 1132 | 1 | av_log(logctx, AV_LOG_TRACE, | |
| 1133 | "Parsed disposition: 0x%x; remainder: %s\n", ss->disposition, spec); | ||
| 1134 |
1/2✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
|
95 | } else if (*spec == '#' || |
| 1135 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | (*spec == 'i' && *(spec + 1) == ':')) { |
| 1136 | ✗ | if (ss->stream_list != STREAM_LIST_ALL) | |
| 1137 | ✗ | goto multiple_stream_lists; | |
| 1138 | |||
| 1139 | ✗ | ss->stream_list = STREAM_LIST_STREAM_ID; | |
| 1140 | |||
| 1141 | ✗ | spec += 1 + (*spec == 'i'); | |
| 1142 | ✗ | ss->list_id = strtol(spec, &endptr, 0); | |
| 1143 | ✗ | if (spec == endptr) { | |
| 1144 | ✗ | av_log(logctx, AV_LOG_ERROR, "Expected stream ID, got: %s\n", spec); | |
| 1145 | ✗ | ret = AVERROR(EINVAL); | |
| 1146 | ✗ | goto fail; | |
| 1147 | } | ||
| 1148 | ✗ | spec = endptr; | |
| 1149 | |||
| 1150 | ✗ | av_log(logctx, AV_LOG_TRACE, | |
| 1151 | "Parsed stream ID: %"PRId64"; remainder: %s\n", ss->list_id, spec); | ||
| 1152 | |||
| 1153 | // this terminates the specifier | ||
| 1154 | ✗ | break; | |
| 1155 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
95 | } else if (*spec == 'm' && *(spec + 1) == ':') { |
| 1156 | ✗ | av_assert0(!ss->meta_key && !ss->meta_val); | |
| 1157 | |||
| 1158 | ✗ | spec += 2; | |
| 1159 | ✗ | ss->meta_key = av_get_token(&spec, ":"); | |
| 1160 | ✗ | if (!ss->meta_key) { | |
| 1161 | ✗ | ret = AVERROR(ENOMEM); | |
| 1162 | ✗ | goto fail; | |
| 1163 | } | ||
| 1164 | ✗ | if (*spec == ':') { | |
| 1165 | ✗ | spec++; | |
| 1166 | ✗ | ss->meta_val = av_get_token(&spec, ":"); | |
| 1167 | ✗ | if (!ss->meta_val) { | |
| 1168 | ✗ | ret = AVERROR(ENOMEM); | |
| 1169 | ✗ | goto fail; | |
| 1170 | } | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | ✗ | av_log(logctx, AV_LOG_TRACE, | |
| 1174 | "Parsed metadata: %s:%s; remainder: %s", ss->meta_key, | ||
| 1175 | ✗ | ss->meta_val ? ss->meta_val : "<any value>", spec); | |
| 1176 | |||
| 1177 | // this terminates the specifier | ||
| 1178 | ✗ | break; | |
| 1179 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
95 | } else if (*spec == 'u' && (*(spec + 1) == '\0' || *(spec + 1) == ':')) { |
| 1180 | ✗ | ss->usable_only = 1; | |
| 1181 | ✗ | spec++; | |
| 1182 | ✗ | av_log(logctx, AV_LOG_ERROR, "Parsed 'usable only'\n"); | |
| 1183 | |||
| 1184 | // this terminates the specifier | ||
| 1185 | ✗ | break; | |
| 1186 | } else | ||
| 1187 | break; | ||
| 1188 | |||
| 1189 |
2/2✓ Branch 0 taken 293 times.
✓ Branch 1 taken 17334 times.
|
17627 | if (*spec == ':') |
| 1190 | 293 | spec++; | |
| 1191 | } | ||
| 1192 | |||
| 1193 |
2/2✓ Branch 0 taken 95 times.
✓ Branch 1 taken 34965 times.
|
35060 | if (*spec) { |
| 1194 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 94 times.
|
95 | if (!allow_remainder) { |
| 1195 | 1 | av_log(logctx, AV_LOG_ERROR, | |
| 1196 | "Trailing garbage at the end of a stream specifier: %s\n", | ||
| 1197 | spec); | ||
| 1198 | 1 | ret = AVERROR(EINVAL); | |
| 1199 | 1 | goto fail; | |
| 1200 | } | ||
| 1201 | |||
| 1202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (*spec == ':') |
| 1203 | ✗ | spec++; | |
| 1204 | |||
| 1205 | 94 | ss->remainder = av_strdup(spec); | |
| 1206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (!ss->remainder) { |
| 1207 | ✗ | ret = AVERROR(EINVAL); | |
| 1208 | ✗ | goto fail; | |
| 1209 | } | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | 35059 | return 0; | |
| 1213 | |||
| 1214 | ✗ | multiple_stream_lists: | |
| 1215 | ✗ | av_log(logctx, AV_LOG_ERROR, | |
| 1216 | "Cannot combine multiple program/group designators in a " | ||
| 1217 | "single stream specifier"); | ||
| 1218 | ✗ | ret = AVERROR(EINVAL); | |
| 1219 | |||
| 1220 | 1 | fail: | |
| 1221 | 1 | stream_specifier_uninit(ss); | |
| 1222 | 1 | return ret; | |
| 1223 | } | ||
| 1224 | |||
| 1225 | 36806 | unsigned stream_specifier_match(const StreamSpecifier *ss, | |
| 1226 | const AVFormatContext *s, const AVStream *st, | ||
| 1227 | void *logctx) | ||
| 1228 | { | ||
| 1229 | 36806 | const AVStreamGroup *g = NULL; | |
| 1230 | 36806 | const AVProgram *p = NULL; | |
| 1231 | 36806 | int start_stream = 0, nb_streams; | |
| 1232 | 36806 | int nb_matched = 0; | |
| 1233 | |||
| 1234 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 36691 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
|
36806 | switch (ss->stream_list) { |
| 1235 | ✗ | case STREAM_LIST_STREAM_ID: | |
| 1236 | // <n-th> stream with given ID makes no sense and should be impossible to request | ||
| 1237 | ✗ | av_assert0(ss->idx < 0); | |
| 1238 | // return early if we know for sure the stream does not match | ||
| 1239 | ✗ | if (st->id != ss->list_id) | |
| 1240 | ✗ | return 0; | |
| 1241 | ✗ | start_stream = st->index; | |
| 1242 | ✗ | nb_streams = st->index + 1; | |
| 1243 | ✗ | break; | |
| 1244 | 36691 | case STREAM_LIST_ALL: | |
| 1245 |
2/2✓ Branch 0 taken 35873 times.
✓ Branch 1 taken 818 times.
|
36691 | start_stream = ss->idx >= 0 ? 0 : st->index; |
| 1246 | 36691 | nb_streams = st->index + 1; | |
| 1247 | 36691 | break; | |
| 1248 | ✗ | case STREAM_LIST_PROGRAM: | |
| 1249 | ✗ | for (unsigned i = 0; i < s->nb_programs; i++) { | |
| 1250 | ✗ | if (s->programs[i]->id == ss->list_id) { | |
| 1251 | ✗ | p = s->programs[i]; | |
| 1252 | ✗ | break; | |
| 1253 | } | ||
| 1254 | } | ||
| 1255 | ✗ | if (!p) { | |
| 1256 | ✗ | av_log(logctx, AV_LOG_WARNING, "No program with ID %"PRId64" exists," | |
| 1257 | ✗ | " stream specifier can never match\n", ss->list_id); | |
| 1258 | ✗ | return 0; | |
| 1259 | } | ||
| 1260 | ✗ | nb_streams = p->nb_stream_indexes; | |
| 1261 | ✗ | break; | |
| 1262 | 17 | case STREAM_LIST_GROUP_ID: | |
| 1263 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | for (unsigned i = 0; i < s->nb_stream_groups; i++) { |
| 1264 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 9 times.
|
26 | if (ss->list_id == s->stream_groups[i]->id) { |
| 1265 | 17 | g = s->stream_groups[i]; | |
| 1266 | 17 | break; | |
| 1267 | } | ||
| 1268 | } | ||
| 1269 | av_fallthrough; | ||
| 1270 | case STREAM_LIST_GROUP_IDX: | ||
| 1271 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 17 times.
|
115 | if (ss->stream_list == STREAM_LIST_GROUP_IDX && |
| 1272 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
|
98 | ss->list_id >= 0 && ss->list_id < s->nb_stream_groups) |
| 1273 | 98 | g = s->stream_groups[ss->list_id]; | |
| 1274 | |||
| 1275 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
|
115 | if (!g) { |
| 1276 | ✗ | av_log(logctx, AV_LOG_WARNING, "No stream group with group %s %" | |
| 1277 | PRId64" exists, stream specifier can never match\n", | ||
| 1278 | ✗ | ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index", | |
| 1279 | ✗ | ss->list_id); | |
| 1280 | ✗ | return 0; | |
| 1281 | } | ||
| 1282 | 115 | nb_streams = g->nb_streams; | |
| 1283 | 115 | break; | |
| 1284 | ✗ | default: av_assert0(0); | |
| 1285 | } | ||
| 1286 | |||
| 1287 |
2/2✓ Branch 0 taken 38496 times.
✓ Branch 1 taken 521 times.
|
39017 | for (int i = start_stream; i < nb_streams; i++) { |
| 1288 |
3/4✓ Branch 0 taken 271 times.
✓ Branch 1 taken 38225 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38225 times.
|
38496 | const AVStream *candidate = s->streams[g ? g->streams[i]->index : |
| 1289 | ✗ | p ? p->stream_index[i] : i]; | |
| 1290 | |||
| 1291 |
2/2✓ Branch 0 taken 22016 times.
✓ Branch 1 taken 16480 times.
|
38496 | if (ss->media_type != AVMEDIA_TYPE_UNKNOWN && |
| 1292 |
2/2✓ Branch 0 taken 21232 times.
✓ Branch 1 taken 784 times.
|
22016 | (ss->media_type != candidate->codecpar->codec_type || |
| 1293 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 21232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
21232 | (ss->no_apic && (candidate->disposition & AV_DISPOSITION_ATTACHED_PIC)))) |
| 1294 | 784 | continue; | |
| 1295 | |||
| 1296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37712 times.
|
37712 | if (ss->meta_key) { |
| 1297 | ✗ | const AVDictionaryEntry *tag = av_dict_get(candidate->metadata, | |
| 1298 | ✗ | ss->meta_key, NULL, 0); | |
| 1299 | |||
| 1300 | ✗ | if (!tag) | |
| 1301 | ✗ | continue; | |
| 1302 | ✗ | if (ss->meta_val && strcmp(tag->value, ss->meta_val)) | |
| 1303 | ✗ | continue; | |
| 1304 | } | ||
| 1305 | |||
| 1306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37712 times.
|
37712 | if (ss->usable_only) { |
| 1307 | ✗ | const AVCodecParameters *par = candidate->codecpar; | |
| 1308 | |||
| 1309 | ✗ | switch (par->codec_type) { | |
| 1310 | ✗ | case AVMEDIA_TYPE_AUDIO: | |
| 1311 | ✗ | if (!par->sample_rate || !par->ch_layout.nb_channels || | |
| 1312 | ✗ | par->format == AV_SAMPLE_FMT_NONE) | |
| 1313 | ✗ | continue; | |
| 1314 | ✗ | break; | |
| 1315 | ✗ | case AVMEDIA_TYPE_VIDEO: | |
| 1316 | ✗ | if (!par->width || !par->height || par->format == AV_PIX_FMT_NONE) | |
| 1317 | ✗ | continue; | |
| 1318 | ✗ | break; | |
| 1319 | ✗ | case AVMEDIA_TYPE_UNKNOWN: | |
| 1320 | ✗ | continue; | |
| 1321 | } | ||
| 1322 | } | ||
| 1323 | |||
| 1324 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 37657 times.
|
37712 | if (ss->disposition && |
| 1325 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 11 times.
|
55 | (candidate->disposition & ss->disposition) != ss->disposition) |
| 1326 | 44 | continue; | |
| 1327 | |||
| 1328 |
2/2✓ Branch 0 taken 36285 times.
✓ Branch 1 taken 1383 times.
|
37668 | if (st == candidate) |
| 1329 |
4/4✓ Branch 0 taken 775 times.
✓ Branch 1 taken 35510 times.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 489 times.
|
36285 | return ss->idx < 0 || ss->idx == nb_matched; |
| 1330 | |||
| 1331 | 1383 | nb_matched++; | |
| 1332 | } | ||
| 1333 | |||
| 1334 | 521 | return 0; | |
| 1335 | } | ||
| 1336 | |||
| 1337 | 587 | int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) | |
| 1338 | { | ||
| 1339 | StreamSpecifier ss; | ||
| 1340 | int ret; | ||
| 1341 | |||
| 1342 | 587 | ret = stream_specifier_parse(&ss, spec, 0, NULL); | |
| 1343 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 586 times.
|
587 | if (ret < 0) |
| 1344 | 1 | return ret; | |
| 1345 | |||
| 1346 | 586 | ret = stream_specifier_match(&ss, s, st, NULL); | |
| 1347 | 586 | stream_specifier_uninit(&ss); | |
| 1348 | 586 | return ret; | |
| 1349 | } | ||
| 1350 | |||
| 1351 | ✗ | unsigned stream_group_specifier_match(const StreamSpecifier *ss, | |
| 1352 | const AVFormatContext *s, const AVStreamGroup *stg, | ||
| 1353 | void *logctx) | ||
| 1354 | { | ||
| 1355 | ✗ | int start_stream_group = 0, nb_stream_groups; | |
| 1356 | ✗ | int nb_matched = 0; | |
| 1357 | |||
| 1358 | ✗ | if (ss->idx >= 0) | |
| 1359 | ✗ | return 0; | |
| 1360 | |||
| 1361 | ✗ | switch (ss->stream_list) { | |
| 1362 | ✗ | case STREAM_LIST_STREAM_ID: | |
| 1363 | case STREAM_LIST_ALL: | ||
| 1364 | case STREAM_LIST_PROGRAM: | ||
| 1365 | ✗ | return 0; | |
| 1366 | ✗ | case STREAM_LIST_GROUP_ID: | |
| 1367 | // <n-th> stream with given ID makes no sense and should be impossible to request | ||
| 1368 | ✗ | av_assert0(ss->idx < 0); | |
| 1369 | // return early if we know for sure the stream does not match | ||
| 1370 | ✗ | if (stg->id != ss->list_id) | |
| 1371 | ✗ | return 0; | |
| 1372 | ✗ | start_stream_group = stg->index; | |
| 1373 | ✗ | nb_stream_groups = stg->index + 1; | |
| 1374 | ✗ | break; | |
| 1375 | ✗ | case STREAM_LIST_GROUP_IDX: | |
| 1376 | ✗ | start_stream_group = ss->list_id >= 0 ? 0 : stg->index; | |
| 1377 | ✗ | nb_stream_groups = stg->index + 1; | |
| 1378 | ✗ | break; | |
| 1379 | ✗ | default: av_assert0(0); | |
| 1380 | } | ||
| 1381 | |||
| 1382 | ✗ | for (int i = start_stream_group; i < nb_stream_groups; i++) { | |
| 1383 | ✗ | const AVStreamGroup *candidate = s->stream_groups[i]; | |
| 1384 | |||
| 1385 | ✗ | if (ss->meta_key) { | |
| 1386 | ✗ | const AVDictionaryEntry *tag = av_dict_get(candidate->metadata, | |
| 1387 | ✗ | ss->meta_key, NULL, 0); | |
| 1388 | |||
| 1389 | ✗ | if (!tag) | |
| 1390 | ✗ | continue; | |
| 1391 | ✗ | if (ss->meta_val && strcmp(tag->value, ss->meta_val)) | |
| 1392 | ✗ | continue; | |
| 1393 | } | ||
| 1394 | |||
| 1395 | ✗ | if (ss->usable_only) { | |
| 1396 | ✗ | switch (candidate->type) { | |
| 1397 | ✗ | case AV_STREAM_GROUP_PARAMS_TILE_GRID: { | |
| 1398 | ✗ | const AVStreamGroupTileGrid *tg = candidate->params.tile_grid; | |
| 1399 | ✗ | if (!tg->coded_width || !tg->coded_height || !tg->nb_tiles || | |
| 1400 | ✗ | !tg->width || !tg->height || !tg->offsets) | |
| 1401 | ✗ | continue; | |
| 1402 | ✗ | break; | |
| 1403 | } | ||
| 1404 | ✗ | default: | |
| 1405 | ✗ | continue; | |
| 1406 | } | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | ✗ | if (ss->disposition && | |
| 1410 | ✗ | (candidate->disposition & ss->disposition) != ss->disposition) | |
| 1411 | ✗ | continue; | |
| 1412 | |||
| 1413 | ✗ | if (stg == candidate) | |
| 1414 | ✗ | return ss->list_id < 0 || ss->list_id == nb_matched; | |
| 1415 | |||
| 1416 | ✗ | nb_matched++; | |
| 1417 | } | ||
| 1418 | |||
| 1419 | ✗ | return 0; | |
| 1420 | } | ||
| 1421 | |||
| 1422 | 26636 | int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, | |
| 1423 | AVFormatContext *s, AVStream *st, const AVCodec *codec, | ||
| 1424 | AVDictionary **dst, AVDictionary **opts_used) | ||
| 1425 | { | ||
| 1426 | 26636 | AVDictionary *ret = NULL; | |
| 1427 | 26636 | const AVDictionaryEntry *t = NULL; | |
| 1428 | 53272 | int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM | |
| 1429 |
2/2✓ Branch 0 taken 9320 times.
✓ Branch 1 taken 17316 times.
|
26636 | : AV_OPT_FLAG_DECODING_PARAM; |
| 1430 | 26636 | char prefix = 0; | |
| 1431 | 26636 | const AVClass *cc = avcodec_get_class(); | |
| 1432 | |||
| 1433 |
4/4✓ Branch 0 taken 20174 times.
✓ Branch 1 taken 6090 times.
✓ Branch 2 taken 270 times.
✓ Branch 3 taken 102 times.
|
26636 | switch (st->codecpar->codec_type) { |
| 1434 | 20174 | case AVMEDIA_TYPE_VIDEO: | |
| 1435 | 20174 | prefix = 'v'; | |
| 1436 | 20174 | flags |= AV_OPT_FLAG_VIDEO_PARAM; | |
| 1437 | 20174 | break; | |
| 1438 | 6090 | case AVMEDIA_TYPE_AUDIO: | |
| 1439 | 6090 | prefix = 'a'; | |
| 1440 | 6090 | flags |= AV_OPT_FLAG_AUDIO_PARAM; | |
| 1441 | 6090 | break; | |
| 1442 | 270 | case AVMEDIA_TYPE_SUBTITLE: | |
| 1443 | 270 | prefix = 's'; | |
| 1444 | 270 | flags |= AV_OPT_FLAG_SUBTITLE_PARAM; | |
| 1445 | 270 | break; | |
| 1446 | } | ||
| 1447 | |||
| 1448 |
2/2✓ Branch 1 taken 80807 times.
✓ Branch 2 taken 26636 times.
|
107443 | while (t = av_dict_iterate(opts, t)) { |
| 1449 | const AVClass *priv_class; | ||
| 1450 | 80807 | char *p = strchr(t->key, ':'); | |
| 1451 | 80807 | int used = 0; | |
| 1452 | |||
| 1453 | /* check stream specification in opt name */ | ||
| 1454 |
2/2✓ Branch 0 taken 305 times.
✓ Branch 1 taken 80502 times.
|
80807 | if (p) { |
| 1455 | 305 | int err = check_stream_specifier(s, st, p + 1); | |
| 1456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
|
305 | if (err < 0) { |
| 1457 | ✗ | av_dict_free(&ret); | |
| 1458 | ✗ | return err; | |
| 1459 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 224 times.
|
305 | } else if (!err) |
| 1460 | 81 | continue; | |
| 1461 | |||
| 1462 | 224 | *p = 0; | |
| 1463 | } | ||
| 1464 | |||
| 1465 |
4/4✓ Branch 1 taken 3332 times.
✓ Branch 2 taken 77394 times.
✓ Branch 3 taken 1919 times.
✓ Branch 4 taken 1413 times.
|
80726 | if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) || |
| 1466 | 1919 | !codec || | |
| 1467 |
4/4✓ Branch 0 taken 902 times.
✓ Branch 1 taken 1017 times.
✓ Branch 2 taken 376 times.
✓ Branch 3 taken 526 times.
|
2821 | ((priv_class = codec->priv_class) && |
| 1468 | 902 | av_opt_find(&priv_class, t->key, NULL, flags, | |
| 1469 | AV_OPT_SEARCH_FAKE_OBJ))) { | ||
| 1470 | 79183 | av_dict_set(&ret, t->key, t->value, 0); | |
| 1471 | 79183 | used = 1; | |
| 1472 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1538 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
1548 | } else if (t->key[0] == prefix && |
| 1473 | 5 | av_opt_find(&cc, t->key + 1, NULL, flags, | |
| 1474 | AV_OPT_SEARCH_FAKE_OBJ)) { | ||
| 1475 | 1 | av_dict_set(&ret, t->key + 1, t->value, 0); | |
| 1476 | 1 | used = 1; | |
| 1477 | } | ||
| 1478 | |||
| 1479 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 80502 times.
|
80726 | if (p) |
| 1480 | 224 | *p = ':'; | |
| 1481 | |||
| 1482 |
4/4✓ Branch 0 taken 79184 times.
✓ Branch 1 taken 1542 times.
✓ Branch 2 taken 51902 times.
✓ Branch 3 taken 27282 times.
|
80726 | if (used && opts_used) |
| 1483 | 51902 | av_dict_set(opts_used, t->key, "", 0); | |
| 1484 | } | ||
| 1485 | |||
| 1486 | 26636 | *dst = ret; | |
| 1487 | 26636 | return 0; | |
| 1488 | } | ||
| 1489 | |||
| 1490 | 7992 | int setup_find_stream_info_opts(AVFormatContext *s, | |
| 1491 | AVDictionary *local_codec_opts, | ||
| 1492 | AVDictionary ***dst) | ||
| 1493 | { | ||
| 1494 | int ret; | ||
| 1495 | AVDictionary **opts; | ||
| 1496 | |||
| 1497 | 7992 | *dst = NULL; | |
| 1498 | |||
| 1499 |
2/2✓ Branch 0 taken 95 times.
✓ Branch 1 taken 7897 times.
|
7992 | if (!s->nb_streams) |
| 1500 | 95 | return 0; | |
| 1501 | |||
| 1502 | 7897 | opts = av_calloc(s->nb_streams, sizeof(*opts)); | |
| 1503 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7897 times.
|
7897 | if (!opts) |
| 1504 | ✗ | return AVERROR(ENOMEM); | |
| 1505 | |||
| 1506 |
2/2✓ Branch 0 taken 8629 times.
✓ Branch 1 taken 7897 times.
|
16526 | for (int i = 0; i < s->nb_streams; i++) { |
| 1507 | 8629 | ret = filter_codec_opts(local_codec_opts, s->streams[i]->codecpar->codec_id, | |
| 1508 | 8629 | s, s->streams[i], NULL, &opts[i], NULL); | |
| 1509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8629 times.
|
8629 | if (ret < 0) |
| 1510 | ✗ | goto fail; | |
| 1511 | } | ||
| 1512 | 7897 | *dst = opts; | |
| 1513 | 7897 | return 0; | |
| 1514 | ✗ | fail: | |
| 1515 | ✗ | for (int i = 0; i < s->nb_streams; i++) | |
| 1516 | ✗ | av_dict_free(&opts[i]); | |
| 1517 | ✗ | av_freep(&opts); | |
| 1518 | ✗ | return ret; | |
| 1519 | } | ||
| 1520 | |||
| 1521 | 263929 | int grow_array(void **array, int elem_size, int *size, int new_size) | |
| 1522 | { | ||
| 1523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 263929 times.
|
263929 | if (new_size >= INT_MAX / elem_size) { |
| 1524 | ✗ | av_log(NULL, AV_LOG_ERROR, "Array too big.\n"); | |
| 1525 | ✗ | return AVERROR(ERANGE); | |
| 1526 | } | ||
| 1527 |
1/2✓ Branch 0 taken 263929 times.
✗ Branch 1 not taken.
|
263929 | if (*size < new_size) { |
| 1528 | 263929 | uint8_t *tmp = av_realloc_array(*array, new_size, elem_size); | |
| 1529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 263929 times.
|
263929 | if (!tmp) |
| 1530 | ✗ | return AVERROR(ENOMEM); | |
| 1531 | 263929 | memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size); | |
| 1532 | 263929 | *size = new_size; | |
| 1533 | 263929 | *array = tmp; | |
| 1534 | 263929 | return 0; | |
| 1535 | } | ||
| 1536 | ✗ | return 0; | |
| 1537 | } | ||
| 1538 | |||
| 1539 | 49791 | void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems) | |
| 1540 | { | ||
| 1541 | void *new_elem; | ||
| 1542 | |||
| 1543 | 49791 | new_elem = av_mallocz(elem_size); | |
| 1544 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49791 times.
|
49791 | if (!new_elem) |
| 1545 | ✗ | return NULL; | |
| 1546 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 49791 times.
|
49791 | if (av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) |
| 1547 | ✗ | av_freep(&new_elem); | |
| 1548 | |||
| 1549 | 49791 | return new_elem; | |
| 1550 | } | ||
| 1551 | |||
| 1552 | 5803 | double get_rotation(const int32_t *displaymatrix) | |
| 1553 | { | ||
| 1554 | 5803 | double theta = 0; | |
| 1555 |
1/2✓ Branch 0 taken 5803 times.
✗ Branch 1 not taken.
|
5803 | if (displaymatrix) |
| 1556 | 5803 | theta = -round(av_display_rotation_get(displaymatrix)); | |
| 1557 | |||
| 1558 | 5803 | theta -= 360*floor(theta/360 + 0.9/360); | |
| 1559 | |||
| 1560 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5803 times.
|
5803 | if (fabs(theta - 90*round(theta/90)) > 2) |
| 1561 | ✗ | av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n" | |
| 1562 | "If you want to help, upload a sample " | ||
| 1563 | "of this file to https://streams.videolan.org/upload/ " | ||
| 1564 | "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)"); | ||
| 1565 | |||
| 1566 | 5803 | return theta; | |
| 1567 | } | ||
| 1568 | |||
| 1569 | /* read file contents into a string */ | ||
| 1570 | 74 | char *read_file_to_string(const char *filename) | |
| 1571 | { | ||
| 1572 | 74 | AVIOContext *pb = NULL; | |
| 1573 | 74 | int ret = avio_open(&pb, filename, AVIO_FLAG_READ); | |
| 1574 | AVBPrint bprint; | ||
| 1575 | char *str; | ||
| 1576 | |||
| 1577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
|
74 | if (ret < 0) { |
| 1578 | ✗ | av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename); | |
| 1579 | ✗ | return NULL; | |
| 1580 | } | ||
| 1581 | |||
| 1582 | 74 | av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); | |
| 1583 | 74 | ret = avio_read_to_bprint(pb, &bprint, SIZE_MAX); | |
| 1584 | 74 | avio_closep(&pb); | |
| 1585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
|
74 | if (ret < 0) { |
| 1586 | ✗ | av_bprint_finalize(&bprint, NULL); | |
| 1587 | ✗ | return NULL; | |
| 1588 | } | ||
| 1589 | 74 | ret = av_bprint_finalize(&bprint, &str); | |
| 1590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
|
74 | if (ret < 0) |
| 1591 | ✗ | return NULL; | |
| 1592 | 74 | return str; | |
| 1593 | } | ||
| 1594 | |||
| 1595 | 7713 | void remove_avoptions(AVDictionary **a, AVDictionary *b) | |
| 1596 | { | ||
| 1597 | 7713 | const AVDictionaryEntry *t = NULL; | |
| 1598 | |||
| 1599 |
2/2✓ Branch 1 taken 25180 times.
✓ Branch 2 taken 7713 times.
|
32893 | while ((t = av_dict_iterate(b, t))) { |
| 1600 | 25180 | av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE); | |
| 1601 | } | ||
| 1602 | 7713 | } | |
| 1603 | |||
| 1604 | 31661 | int check_avoptions(AVDictionary *m) | |
| 1605 | { | ||
| 1606 | 31661 | const AVDictionaryEntry *t = av_dict_iterate(m, NULL); | |
| 1607 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31661 times.
|
31661 | if (t) { |
| 1608 | ✗ | av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key); | |
| 1609 | ✗ | return AVERROR_OPTION_NOT_FOUND; | |
| 1610 | } | ||
| 1611 | |||
| 1612 | 31661 | return 0; | |
| 1613 | } | ||
| 1614 | |||
| 1615 | ✗ | void dump_dictionary(void *ctx, const AVDictionary *m, | |
| 1616 | const char *name, const char *indent, | ||
| 1617 | int log_level) | ||
| 1618 | { | ||
| 1619 | ✗ | const AVDictionaryEntry *tag = NULL; | |
| 1620 | |||
| 1621 | ✗ | if (!m) | |
| 1622 | ✗ | return; | |
| 1623 | |||
| 1624 | ✗ | av_log(ctx, log_level, "%s%s:\n", indent, name); | |
| 1625 | ✗ | while ((tag = av_dict_iterate(m, tag))) { | |
| 1626 | ✗ | const char *p = tag->value; | |
| 1627 | ✗ | av_log(ctx, log_level, "%s %-16s: ", indent, tag->key); | |
| 1628 | ✗ | while (*p) { | |
| 1629 | ✗ | size_t len = strcspn(p, "\x8\xa\xb\xc\xd"); | |
| 1630 | ✗ | av_log(ctx, log_level, "%.*s", (int)(FFMIN(255, len)), p); | |
| 1631 | ✗ | p += len; | |
| 1632 | ✗ | if (*p == 0xd) av_log(ctx, log_level, " "); | |
| 1633 | ✗ | if (*p == 0xa) av_log(ctx, log_level, "\n%s %-16s: ", indent, ""); | |
| 1634 | ✗ | if (*p) p++; | |
| 1635 | } | ||
| 1636 | ✗ | av_log(ctx, log_level, "\n"); | |
| 1637 | } | ||
| 1638 | } | ||
| 1639 |