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"
51 #ifdef _WIN32
52 #include <windows.h>
54 #endif
55
59
61
63 {
68 }
69
71 {
72 vfprintf(stdout, fmt, vl);
73 }
74
76 {
77 #if HAVE_SETDLLDIRECTORY && defined(_WIN32)
78 /* Calling SetDllDirectory with the empty string (but not NULL) removes the
79 * current working directory from the DLL search path as a security pre-caution. */
80 SetDllDirectory("");
81 #endif
82 }
83
86 {
87 char *tail;
90 if (*tail)
91 error =
"Expected number for %s but found: %s\n";
92 else if (d < min || d >
max)
93 error =
"The value for %s was %s which is not within %f - %f\n";
95 error =
"Expected int64 for %s but found %s\n";
97 error =
"Expected int for %s but found %s\n";
98 else {
100 return 0;
101 }
102
105 }
106
108 int rej_flags)
109 {
112
115 char buf[128];
116
117 if (((po->
flags & req_flags) != req_flags) ||
118 (po->
flags & rej_flags))
119 continue;
120
124 }
126
128 av_strlcat(buf,
"[:<stream_spec>]",
sizeof(buf));
131
134
136 }
138 }
139
141 {
147 }
148
151 }
152
154 {
157
159 const char *end;
161 break;
162 po++;
163 }
164 return po;
165 }
166
167 /* _WIN32 means using the windows libc - cygwin doesn't define that
168 * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while
169 * it doesn't provide the actual command line via GetCommandLineW(). */
170 #if HAVE_COMMANDLINETOARGVW && defined(_WIN32)
171 #include <shellapi.h>
172 /* Will be leaked on exit */
173 static char** win32_argv_utf8 =
NULL;
174 static int win32_argc = 0;
175
176 /**
177 * Prepare command line arguments for executable.
178 * For Windows - perform wide-char to UTF-8 conversion.
179 * Input arguments should be main() function arguments.
180 * @param argc_ptr Arguments number (including executable)
181 * @param argv_ptr Arguments list.
182 */
184 {
185 char *argstr_flat;
186 wchar_t **argv_w;
187 int i, buffsize = 0,
offset = 0;
188
189 if (win32_argv_utf8) {
190 *argc_ptr = win32_argc;
191 *argv_ptr = win32_argv_utf8;
192 return;
193 }
194
195 win32_argc = 0;
196 argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc);
197 if (win32_argc <= 0 || !argv_w)
198 return;
199
200 /* determine the UTF-8 buffer size (including NULL-termination symbols) */
201 for (
i = 0;
i < win32_argc;
i++)
202 buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[
i], -1,
204
205 win32_argv_utf8 =
av_mallocz(
sizeof(
char *) * (win32_argc + 1) + buffsize);
206 argstr_flat = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1);
207 if (!win32_argv_utf8) {
208 LocalFree(argv_w);
209 return;
210 }
211
212 for (
i = 0;
i < win32_argc;
i++) {
213 win32_argv_utf8[
i] = &argstr_flat[
offset];
214 offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[
i], -1,
217 }
218 win32_argv_utf8[
i] =
NULL;
219 LocalFree(argv_w);
220
221 *argc_ptr = win32_argc;
222 *argv_ptr = win32_argv_utf8;
223 }
224 #else
226 {
227 /* nothing to do */
228 }
229 #endif /* HAVE_COMMANDLINETOARGVW */
230
232 {
234 return 0;
237 return 1;
238 }
239
242 {
243 /* new-style options contain an offset into optctx, old-style address of
244 * a global var*/
247 char *arg_allocated =
NULL;
248
250
252 double num;
254
256 opt++;
257
260 "Requested to load an argument from file for a bool option '%s'\n",
263 }
264
266 if (!arg_allocated) {
268 "Error reading the value for option '%s' from file: %s\n",
271 }
272
274 }
275
277 char *p = strchr(opt, ':');
278 char *str;
279
284
286 if (!str) {
289 }
290 sol->opt[sol->nb_opt - 1].specifier = str;
291
297 }
298
299 dst = &sol->opt[sol->nb_opt - 1].u;
300 }
301
303 char *str;
304 if (arg_allocated) {
305 str = arg_allocated;
306 arg_allocated =
NULL;
307 } else
310
311 if (!str) {
314 }
315
321
328
336 }
342
348
349 *(
double *)
dst = num;
350 } else {
352
356 "Failed to set value '%s' for option '%s': %s\n",
359 }
360 }
364 }
365
366 if (sol) {
367 sol->type = so_type;
370 }
371
375 }
376
379 {
381 .
name =
"AVOption passthrough",
385 };
386
389
391 if (!po->
name && opt[0] ==
'n' && opt[1] ==
'o') {
392 /* handle 'no' bool option */
398
400 po = &opt_avoptions;
404 }
408 }
409
413
415 }
416
418 int (*parse_arg_function)(void *, const char*))
419 {
420 const char *opt;
421 int optindex, handleoptions = 1,
ret;
422
423 /* perform system-dependent conversions for arguments list */
425
426 /* parse options */
427 optindex = 1;
428 while (optindex < argc) {
429 opt = argv[optindex++];
430
431 if (handleoptions && opt[0] == '-' && opt[1] != '0円') {
432 if (opt[1] == '-' && opt[2] == '0円') {
433 handleoptions = 0;
434 continue;
435 }
436 opt++;
437
441 } else {
442 if (parse_arg_function) {
443 ret = parse_arg_function(optctx, opt);
446 }
447 }
448 }
449
450 return 0;
451 }
452
454 {
456
458 g->group_def->name,
g->arg);
459
460 for (
i = 0;
i <
g->nb_opts;
i++) {
462
463 if (
g->group_def->flags &&
464 !(
g->group_def->flags & o->
opt->
flags)) {
466 "%s %s -- you are trying to apply an input option to an "
467 "output file or vice versa. Move this option before the "
468 "file it belongs to.\n", o->
key, o->
opt->
help,
469 g->group_def->name,
g->arg);
471 }
472
475
479 }
480
482
483 return 0;
484 }
485
487 const char *optname)
488 {
491
492 for (
i = 1;
i < argc;
i++) {
493 const char *cur_opt = argv[
i];
494
495 if (*cur_opt++ != '-')
496 continue;
497
499 if (!po->
name && cur_opt[0] ==
'n' && cur_opt[1] ==
'o')
501
502 if ((!po->
name && !strcmp(cur_opt, optname)) ||
503 (po->
name && !strcmp(optname, po->
name)))
505
508 }
509 return 0;
510 }
511
513 {
514 const unsigned char *p;
515
517 if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||
518 *p == '_' || (*p >= 'a' && *p <= 'z')))
519 break;
520 if (!*p) {
522 return;
523 }
525 for (p =
a; *p; p++) {
526 if (*p == '\\' || *p == '"' || *p == '$' || *p == '`')
528 else if (*p < ' ' || *p > '~')
530 else
532 }
534 }
535
537 {
541
544
545 // OPT_FUNC_ARG can only be ser for OPT_TYPE_FUNC
547
548 po++;
549 }
550 }
551
553 {
555 char *env;
556
558
559 if (!idx)
561 if (idx && argv[idx + 1])
565 if (env || idx) {
571 for (
i = 0;
i < argc;
i++) {
574 }
576 }
577 }
580 if (idx)
582 }
583
585 int opt_flags, int search_flags)
586 {
590 return o;
591 }
592
593 #define FLAGS ((o->type == AV_OPT_TYPE_FLAGS && (arg[0]=='-' || arg[0]=='+')) ? AV_DICT_APPEND : 0)
595 {
597 int consumed = 0;
598 char opt_stripped[128];
599 const char *p;
601 #if CONFIG_SWSCALE
603 #endif
604 #if CONFIG_SWRESAMPLE
606 #endif
607
608 if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug"))
610
611 if (!(p = strchr(opt, ':')))
612 p = opt + strlen(opt);
613 av_strlcpy(opt_stripped, opt,
FFMIN(
sizeof(opt_stripped), p - opt + 1));
614
617 ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') &&
620 consumed = 1;
621 }
625 if (consumed)
627 consumed = 1;
628 }
629 #if CONFIG_SWSCALE
632 if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") ||
633 !strcmp(opt, "dstw") || !strcmp(opt, "dsth") ||
634 !strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) {
635 av_log(
NULL,
AV_LOG_ERROR,
"Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n");
637 }
639
640 consumed = 1;
641 }
642 #else
643 if (!consumed && !strcmp(opt, "sws_flags")) {
645 consumed = 1;
646 }
647 #endif
648 #if CONFIG_SWRESAMPLE
652 consumed = 1;
653 }
654 #endif
655
656 if (consumed)
657 return 0;
659 }
660
661 /*
662 * Check whether given option is a group separator.
663 *
664 * @return index of the group definition that matched or -1 if none
665 */
667 const char *opt)
668 {
670
671 for (
i = 0;
i < nb_groups;
i++) {
673 if (p->
sep && !strcmp(p->
sep, opt))
675 }
676
677 return -1;
678 }
679
680 /*
681 * Finish parsing an option group.
682 *
683 * @param group_idx which group definition should this group belong to
684 * @param arg argument of the group delimiting option
685 */
688 {
692
696
698
706
711
713
715 }
716
717 /*
718 * Add an option instance to currently parsed group.
719 */
721 const char *
key,
const char *
val)
722 {
726
730
731 g->opts[
g->nb_opts - 1].opt = opt;
732 g->opts[
g->nb_opts - 1].key =
key;
733 g->opts[
g->nb_opts - 1].val =
val;
734
735 return 0;
736 }
737
740 {
743
744 memset(octx, 0, sizeof(*octx));
745
750
753
756
757 return 0;
758 }
759
761 {
763
766
771
774 }
776 }
778
781
783 }
784
788 {
790 int optindex = 1;
791 int dashdash = -2;
792
793 /* perform system-dependent conversions for arguments list */
795
799
801
802 while (optindex < argc) {
803 const char *opt = argv[optindex++], *
arg;
805 int group_idx;
806
808
809 if (opt[0] == '-' && opt[1] == '-' && !opt[2]) {
810 dashdash = optindex;
811 continue;
812 }
813 /* unnamed group separators, e.g. output filename */
814 if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) {
818
820 continue;
821 }
822 opt++;
823
824 #define GET_ARG(arg) \
825 do { \
826 arg = argv[optindex++]; \
827 if (!arg) { \
828 av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\
829 return AVERROR(EINVAL); \
830 } \
831 } while (0)
832
833 /* named group separators, e.g. -i */
835 if (group_idx >= 0) {
840
843 continue;
844 }
845
846 /* normal options */
850 /* optional argument, e.g. -h */
851 arg = argv[optindex++];
854 } else {
856 }
857
861
864 continue;
865 }
866
867 /* AVOptions */
868 if (argv[optindex]) {
872 "argument '%s'.\n", opt, argv[optindex]);
873 optindex++;
874 continue;
877 "with argument '%s'.\n", opt, argv[optindex]);
879 }
880 }
881
882 /* boolean -nofoo options */
883 if (opt[0] == 'n' && opt[1] == 'o' &&
889
891 "argument 0.\n", po->
name, po->
help);
892 continue;
893 }
894
897 }
898
901 "command: may be ignored.\n");
902
904
905 return 0;
906 }
907
909 {
912
913 while (
c !=
'\n' &&
c != EOF)
915
916 return yesno;
917 }
918
920 const char *preset_name, int is_path,
921 const char *codec_name)
922 {
925 #if HAVE_GETMODULEHANDLE && defined(_WIN32)
926 char *datadir =
NULL;
927 #endif
929 char *env_ffmpeg_datadir =
getenv_utf8(
"FFMPEG_DATADIR");
930 const char *
base[3] = { env_ffmpeg_datadir,
931 env_home, /* index=1(HOME) is special: search in a .ffmpeg subfolder */
932 FFMPEG_DATADIR, };
933
934 if (is_path) {
935 av_strlcpy(filename, preset_name, filename_size);
937 } else {
938 #if HAVE_GETMODULEHANDLE && defined(_WIN32)
939 wchar_t *datadir_w = get_module_filename(
NULL);
941
942 if (wchartoutf8(datadir_w, &datadir))
945
946 if (datadir)
947 {
948 char *ls;
949 for (ls = datadir; *ls; ls++)
950 if (*ls == '\\') *ls = '/';
951
952 if (ls = strrchr(datadir, '/'))
953 {
954 ptrdiff_t datadir_len = ls - datadir;
955 size_t desired_size = datadir_len + strlen("/ffpresets") + 1;
957 datadir, desired_size, sizeof *datadir);
958 if (new_datadir) {
959 datadir = new_datadir;
960 datadir[datadir_len] = 0;
961 strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len);
963 }
964 }
965 }
966 #endif
967 for (
i = 0;
i < 3 && !
f;
i++) {
969 continue;
970 snprintf(filename, filename_size,
"%s%s/%s.ffpreset",
base[
i],
971 i != 1 ?
"" :
"/.ffmpeg", preset_name);
973 if (!
f && codec_name) {
975 "%s%s/%s-%s.ffpreset",
976 base[
i],
i != 1 ?
"" :
"/.ffmpeg", codec_name,
977 preset_name);
979 }
980 }
981 }
982
983 #if HAVE_GETMODULEHANDLE && defined(_WIN32)
985 #endif
989 }
990
992 {
993 return (
c >=
'0' &&
c <=
'9') ||
994 (
c >=
'A' &&
c <=
'Z') ||
995 (
c >=
'a' &&
c <=
'z');
996 }
997
999 {
1003
1004 memset(
ss, 0,
sizeof(*
ss));
1005 }
1006
1008 int allow_remainder, void *logctx)
1009 {
1010 char *endptr;
1012
1013 memset(
ss, 0,
sizeof(*
ss));
1014
1018
1020
1021 while (*spec) {
1022 if (*spec <= '9' && *spec >= '0') { /* opt:index */
1023 ss->idx = strtol(spec, &endptr, 0);
1024
1026 spec = endptr;
1027
1029 "Parsed index: %d; remainder: %s\n",
ss->idx, spec);
1030
1031 // this terminates the specifier
1032 break;
1033 } else if ((*spec == 'v' || *spec == 'a' || *spec == 's' ||
1034 *spec == 'd' || *spec == 't' || *spec == 'V') &&
1040 }
1041
1042 switch (*spec++) {
1049 ss->no_apic = 1;
break;
1051 }
1052
1055 } else if (*spec == 'g' && *(spec + 1) == ':') {
1057 goto multiple_stream_lists;
1058
1059 spec += 2;
1060 if (*spec == '#' || (*spec == 'i' && *(spec + 1) == ':')) {
1062
1063 spec += 1 + (*spec == 'i');
1064 } else
1066
1067 ss->list_id = strtol(spec, &endptr, 0);
1068 if (spec == endptr) {
1072 }
1073 spec = endptr;
1074
1077 } else if (*spec == 'p' && *(spec + 1) == ':') {
1079 goto multiple_stream_lists;
1080
1082
1083 spec += 2;
1084 ss->list_id = strtol(spec, &endptr, 0);
1085 if (spec == endptr) {
1089 }
1090 spec = endptr;
1091
1093 "Parsed program ID: %"PRId64
"; remainder: %s\n",
ss->list_id, spec);
1094 } else if (!strncmp(spec, "disp:", 5)) {
1099
1101
1102 if (
ss->disposition) {
1106 }
1107
1108 spec += 5;
1109
1111 spec[
len] ==
'_' || spec[
len] ==
'+';
len++)
1112 continue;
1113
1115 if (!disp) {
1118 }
1119
1125 }
1126
1128
1130 "Parsed disposition: 0x%x; remainder: %s\n",
ss->disposition, spec);
1131 } else if (*spec == '#' ||
1132 (*spec == 'i' && *(spec + 1) == ':')) {
1134 goto multiple_stream_lists;
1135
1137
1138 spec += 1 + (*spec == 'i');
1139 ss->list_id = strtol(spec, &endptr, 0);
1140 if (spec == endptr) {
1144 }
1145 spec = endptr;
1146
1148 "Parsed stream ID: %"PRId64
"; remainder: %s\n",
ss->list_id, spec);
1149
1150 // this terminates the specifier
1151 break;
1152 } else if (*spec == 'm' && *(spec + 1) == ':') {
1154
1155 spec += 2;
1157 if (!
ss->meta_key) {
1160 }
1161 if (*spec == ':') {
1162 spec++;
1164 if (!
ss->meta_val) {
1167 }
1168 }
1169
1171 "Parsed metadata: %s:%s; remainder: %s",
ss->meta_key,
1172 ss->meta_val ?
ss->meta_val :
"<any value>", spec);
1173
1174 // this terminates the specifier
1175 break;
1176 } else if (*spec == 'u' && (*(spec + 1) == '0円' || *(spec + 1) == ':')) {
1177 ss->usable_only = 1;
1178 spec++;
1180
1181 // this terminates the specifier
1182 break;
1183 } else
1184 break;
1185
1186 if (*spec == ':')
1187 spec++;
1188 }
1189
1190 if (*spec) {
1191 if (!allow_remainder) {
1193 "Trailing garbage at the end of a stream specifier: %s\n",
1194 spec);
1197 }
1198
1199 if (*spec == ':')
1200 spec++;
1201
1203 if (!
ss->remainder) {
1206 }
1207 }
1208
1209 return 0;
1210
1211 multiple_stream_lists:
1213 "Cannot combine multiple program/group designators in a "
1214 "single stream specifier");
1216
1220 }
1221
1224 void *logctx)
1225 {
1229 int nb_matched = 0;
1230
1231 switch (
ss->stream_list) {
1233 // <n-th> stream with given ID makes no sense and should be impossible to request
1235 // return early if we know for sure the stream does not match
1236 if (st->
id !=
ss->list_id)
1237 return 0;
1238 start_stream = st->
index;
1240 break;
1242 start_stream =
ss->idx >= 0 ? 0 : st->
index;
1244 break;
1246 for (
unsigned i = 0;
i <
s->nb_programs;
i++) {
1247 if (
s->programs[
i]->id ==
ss->list_id) {
1249 break;
1250 }
1251 }
1252 if (!p) {
1254 " stream specifier can never match\n",
ss->list_id);
1255 return 0;
1256 }
1258 break;
1260 for (
unsigned i = 0;
i <
s->nb_stream_groups;
i++) {
1261 if (
ss->list_id ==
s->stream_groups[
i]->id) {
1262 g =
s->stream_groups[
i];
1263 break;
1264 }
1265 }
1266 // fall-through
1269 ss->list_id >= 0 &&
ss->list_id <
s->nb_stream_groups)
1270 g =
s->stream_groups[
ss->list_id];
1271
1274 PRId64" exists, stream specifier can never match\n",
1277 return 0;
1278 }
1280 break;
1282 }
1283
1285 const AVStream *candidate =
s->streams[
g ?
g->streams[
i]->index :
1287
1291 continue;
1292
1296
1298 continue;
1299 if (
ss->meta_val && strcmp(
tag->value,
ss->meta_val))
1300 continue;
1301 }
1302
1303 if (
ss->usable_only) {
1305
1310 continue;
1311 break;
1314 continue;
1315 break;
1317 continue;
1318 }
1319 }
1320
1321 if (
ss->disposition &&
1323 continue;
1324
1325 if (st == candidate)
1326 return ss->idx < 0 ||
ss->idx == nb_matched;
1327
1328 nb_matched++;
1329 }
1330
1331 return 0;
1332 }
1333
1335 {
1338
1342
1346 }
1347
1351 {
1356 char prefix = 0;
1358
1361 prefix = 'v';
1363 break;
1365 prefix = 'a';
1367 break;
1369 prefix = 's';
1371 break;
1372 }
1373
1376 char *p = strchr(t->
key,
':');
1377 int used = 0;
1378
1379 /* check stream specification in opt name */
1380 if (p) {
1382 if (err < 0) {
1384 return err;
1385 } else if (!err)
1386 continue;
1387
1388 *p = 0;
1389 }
1390
1392 !codec ||
1397 used = 1;
1398 }
else if (t->
key[0] == prefix &&
1402 used = 1;
1403 }
1404
1405 if (p)
1406 *p = ':';
1407
1408 if (used && opts_used)
1410 }
1411
1413 return 0;
1414 }
1415
1419 {
1422
1424
1426 return 0;
1427
1431
1432 for (
int i = 0;
i <
s->nb_streams;
i++) {
1437 }
1439 return 0;
1441 for (
int i = 0;
i <
s->nb_streams;
i++)
1445 }
1446
1448 {
1449 if (new_size >= INT_MAX / elem_size) {
1452 }
1453 if (*
size < new_size) {
1457 memset(
tmp + *
size*elem_size, 0, (new_size-*
size) * elem_size);
1460 return 0;
1461 }
1462 return 0;
1463 }
1464
1466 {
1467 void *new_elem;
1468
1472 return new_elem;
1473 }
1474
1476 {
1477 double theta = 0;
1478 if (displaymatrix)
1480
1481 theta -= 360*
floor(theta/360 + 0.9/360);
1482
1483 if (
fabs(theta - 90*
round(theta/90)) > 2)
1485 "If you want to help, upload a sample "
1486 "of this file to https://streams.videolan.org/upload/ "
1487 "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)");
1488
1489 return theta;
1490 }
1491
1492 /* read file contents into a string */
1494 {
1497 AVBPrint bprint;
1498 char *str;
1499
1503 }
1504
1511 }
1515 return str;
1516 }
1517
1519 {
1521
1524 }
1525 }
1526
1528 {
1530 if (t) {
1533 }
1534
1535 return 0;
1536 }