02113518ee0924064220d0d9fb00ab3716ca0f24
[ffmpeg.git] / cmdutils.c
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 <stdlib.h>
24 #include <errno.h>
25 #include <math.h>
26
27 /* Include only the enabled headers since some compilers (namely, Sun
28    Studio) will not omit unused inline functions and create undefined
29    references to libraries that are not being built. */
30
31 #include "config.h"
32 #include "libavformat/avformat.h"
33 #include "libavfilter/avfilter.h"
34 #include "libavdevice/avdevice.h"
35 #include "libswscale/swscale.h"
36 #include "libswresample/swresample.h"
37 #if CONFIG_POSTPROC
38 #include "libpostproc/postprocess.h"
39 #endif
40 #include "libavutil/avstring.h"
41 #include "libavutil/mathematics.h"
42 #include "libavutil/parseutils.h"
43 #include "libavutil/pixdesc.h"
44 #include "libavutil/eval.h"
45 #include "libavutil/dict.h"
46 #include "libavutil/opt.h"
47 #include "cmdutils.h"
48 #include "version.h"
49 #if CONFIG_NETWORK
50 #include "libavformat/network.h"
51 #endif
52 #if HAVE_SYS_RESOURCE_H
53 #include <sys/resource.h>
54 #endif
55
56 struct SwsContext *sws_opts;
57 AVDictionary *format_opts, *codec_opts;
58
59 const int this_year = 2012;
60
61 static FILE *report_file;
62
63 void init_opts(void)
64 {
65 #if CONFIG_SWSCALE
66     sws_opts = sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC,
67                               NULL, NULL, NULL);
68 #endif
69 }
70
71 void uninit_opts(void)
72 {
73 #if CONFIG_SWSCALE
74     sws_freeContext(sws_opts);
75     sws_opts = NULL;
76 #endif
77     av_dict_free(&format_opts);
78     av_dict_free(&codec_opts);
79 }
80
81 void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
82 {
83     vfprintf(stdout, fmt, vl);
84 }
85
86 static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
87 {
88     va_list vl2;
89     char line[1024];
90     static int print_prefix = 1;
91
92     va_copy(vl2, vl);
93     av_log_default_callback(ptr, level, fmt, vl);
94     av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
95     va_end(vl2);
96     fputs(line, report_file);
97     fflush(report_file);
98 }
99
100 double parse_number_or_die(const char *context, const char *numstr, int type,
101                            double min, double max)
102 {
103     char *tail;
104     const char *error;
105     double d = av_strtod(numstr, &tail);
106     if (*tail)
107         error = "Expected number for %s but found: %s\n";
108     else if (d < min || d > max)
109         error = "The value for %s was %s which is not within %f - %f\n";
110     else if (type == OPT_INT64 && (int64_t)d != d)
111         error = "Expected int64 for %s but found %s\n";
112     else if (type == OPT_INT && (int)d != d)
113         error = "Expected int for %s but found %s\n";
114     else
115         return d;
116     av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max);
117     exit_program(1);
118     return 0;
119 }
120
121 int64_t parse_time_or_die(const char *context, const char *timestr,
122                           int is_duration)
123 {
124     int64_t us;
125     if (av_parse_time(&us, timestr, is_duration) < 0) {
126         av_log(NULL, AV_LOG_FATAL, "Invalid %s specification for %s: %s\n",
127                is_duration ? "duration" : "date", context, timestr);
128         exit_program(1);
129     }
130     return us;
131 }
132
133 void show_help_options(const OptionDef *options, const char *msg, int mask,
134                        int value)
135 {
136     const OptionDef *po;
137     int first;
138
139     first = 1;
140     for (po = options; po->name != NULL; po++) {
141         char buf[64];
142         if ((po->flags & mask) == value) {
143             if (first) {
144                 printf("%s", msg);
145                 first = 0;
146             }
147             av_strlcpy(buf, po->name, sizeof(buf));
148             if (po->flags & HAS_ARG) {
149                 av_strlcat(buf, " ", sizeof(buf));
150                 av_strlcat(buf, po->argname, sizeof(buf));
151             }
152             printf("-%-17s  %s\n", buf, po->help);
153         }
154     }
155 }
156
157 void show_help_children(const AVClass *class, int flags)
158 {
159     const AVClass *child = NULL;
160     av_opt_show2(&class, NULL, flags, 0);
161     printf("\n");
162
163     while (child = av_opt_child_class_next(class, child))
164         show_help_children(child, flags);
165 }
166
167 static const OptionDef *find_option(const OptionDef *po, const char *name)
168 {
169     const char *p = strchr(name, ':');
170     int len = p ? p - name : strlen(name);
171
172     while (po->name != NULL) {
173         if (!strncmp(name, po->name, len) && strlen(po->name) == len)
174             break;
175         po++;
176     }
177     return po;
178 }
179
180 #if defined(_WIN32) && !defined(__MINGW32CE__)
181 #include <windows.h>
182 /* Will be leaked on exit */
183 static char** win32_argv_utf8 = NULL;
184 static int win32_argc = 0;
185
186 /**
187  * Prepare command line arguments for executable.
188  * For Windows - perform wide-char to UTF-8 conversion.
189  * Input arguments should be main() function arguments.
190  * @param argc_ptr Arguments number (including executable)
191  * @param argv_ptr Arguments list.
192  */
193 static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)
194 {
195     char *argstr_flat;
196     wchar_t **argv_w;
197     int i, buffsize = 0, offset = 0;
198
199     if (win32_argv_utf8) {
200         *argc_ptr = win32_argc;
201         *argv_ptr = win32_argv_utf8;
202         return;
203     }
204
205     win32_argc = 0;
206     argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc);
207     if (win32_argc <= 0 || !argv_w)
208         return;
209
210     /* determine the UTF-8 buffer size (including NULL-termination symbols) */
211     for (i = 0; i < win32_argc; i++)
212         buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,
213                                         NULL, 0, NULL, NULL);
214
215     win32_argv_utf8 = av_mallocz(sizeof(char *) * (win32_argc + 1) + buffsize);
216     argstr_flat     = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1);
217     if (win32_argv_utf8 == NULL) {
218         LocalFree(argv_w);
219         return;
220     }
221
222     for (i = 0; i < win32_argc; i++) {
223         win32_argv_utf8[i] = &argstr_flat[offset];
224         offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,
225                                       &argstr_flat[offset],
226                                       buffsize - offset, NULL, NULL);
227     }
228     win32_argv_utf8[i] = NULL;
229     LocalFree(argv_w);
230
231     *argc_ptr = win32_argc;
232     *argv_ptr = win32_argv_utf8;
233 }
234 #else
235 static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)
236 {
237     /* nothing to do */
238 }
239 #endif /* WIN32 && !__MINGW32CE__ */
240
241 int parse_option(void *optctx, const char *opt, const char *arg,
242                  const OptionDef *options)
243 {
244     const OptionDef *po;
245     int bool_val = 1;
246     int *dstcount;
247     void *dst;
248
249     po = find_option(options, opt);
250     if (!po->name && opt[0] == 'n' && opt[1] == 'o') {
251         /* handle 'no' bool option */
252         po = find_option(options, opt + 2);
253         if ((po->name && (po->flags & OPT_BOOL)))
254             bool_val = 0;
255     }
256     if (!po->name)
257         po = find_option(options, "default");
258     if (!po->name) {
259         av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt);
260         return AVERROR(EINVAL);
261     }
262     if (po->flags & HAS_ARG && !arg) {
263         av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'\n", opt);
264         return AVERROR(EINVAL);
265     }
266
267     /* new-style options contain an offset into optctx, old-style address of
268      * a global var*/
269     dst = po->flags & (OPT_OFFSET | OPT_SPEC) ? (uint8_t *)optctx + po->u.off
270                                               : po->u.dst_ptr;
271
272     if (po->flags & OPT_SPEC) {
273         SpecifierOpt **so = dst;
274         char *p = strchr(opt, ':');
275
276         dstcount = (int *)(so + 1);
277         *so = grow_array(*so, sizeof(**so), dstcount, *dstcount + 1);
278         (*so)[*dstcount - 1].specifier = av_strdup(p ? p + 1 : "");
279         dst = &(*so)[*dstcount - 1].u;
280     }
281
282     if (po->flags & OPT_STRING) {
283         char *str;
284         str = av_strdup(arg);
285         *(char **)dst = str;
286     } else if (po->flags & OPT_BOOL) {
287         *(int *)dst = bool_val;
288     } else if (po->flags & OPT_INT) {
289         *(int *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
290     } else if (po->flags & OPT_INT64) {
291         *(int64_t *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT64_MIN, INT64_MAX);
292     } else if (po->flags & OPT_TIME) {
293         *(int64_t *)dst = parse_time_or_die(opt, arg, 1);
294     } else if (po->flags & OPT_FLOAT) {
295         *(float *)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY);
296     } else if (po->flags & OPT_DOUBLE) {
297         *(double *)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY);
298     } else if (po->u.func_arg) {
299         int ret = po->flags & OPT_FUNC2 ? po->u.func2_arg(optctx, opt, arg)
300                                         : po->u.func_arg(opt, arg);
301         if (ret < 0) {
302             av_log(NULL, AV_LOG_ERROR,
303                    "Failed to set value '%s' for option '%s'\n", arg, opt);
304             return ret;
305         }
306     }
307     if (po->flags & OPT_EXIT)
308         exit_program(0);
309     return !!(po->flags & HAS_ARG);
310 }
311
312 void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
313                    void (*parse_arg_function)(void *, const char*))
314 {
315     const char *opt;
316     int optindex, handleoptions = 1, ret;
317
318     /* perform system-dependent conversions for arguments list */
319     prepare_app_arguments(&argc, &argv);
320
321     /* parse options */
322     optindex = 1;
323     while (optindex < argc) {
324         opt = argv[optindex++];
325
326         if (handleoptions && opt[0] == '-' && opt[1] != '\0') {
327             if (opt[1] == '-' && opt[2] == '\0') {
328                 handleoptions = 0;
329                 continue;
330             }
331             opt++;
332
333             if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0)
334                 exit_program(1);
335             optindex += ret;
336         } else {
337             if (parse_arg_function)
338                 parse_arg_function(optctx, opt);
339         }
340     }
341 }
342
343 int locate_option(int argc, char **argv, const OptionDef *options,
344                   const char *optname)
345 {
346     const OptionDef *po;
347     int i;
348
349     for (i = 1; i < argc; i++) {
350         const char *cur_opt = argv[i];
351
352         if (*cur_opt++ != '-')
353             continue;
354
355         po = find_option(options, cur_opt);
356         if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o')
357             po = find_option(options, cur_opt + 2);
358
359         if ((!po->name && !strcmp(cur_opt, optname)) ||
360              (po->name && !strcmp(optname, po->name)))
361             return i;
362
363         if (!po || po->flags & HAS_ARG)
364             i++;
365     }
366     return 0;
367 }
368
369 static void dump_argument(const char *a)
370 {
371     const unsigned char *p;
372
373     for (p = a; *p; p++)
374         if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||
375               *p == '_' || (*p >= 'a' && *p <= 'z')))
376             break;
377     if (!*p) {
378         fputs(a, report_file);
379         return;
380     }
381     fputc('"', report_file);
382     for (p = a; *p; p++) {
383         if (*p == '\\' || *p == '"' || *p == '$' || *p == '`')
384             fprintf(report_file, "\\%c", *p);
385         else if (*p < ' ' || *p > '~')
386             fprintf(report_file, "\\x%02x", *p);
387         else
388             fputc(*p, report_file);
389     }
390     fputc('"', report_file);
391 }
392
393 void parse_loglevel(int argc, char **argv, const OptionDef *options)
394 {
395     int idx = locate_option(argc, argv, options, "loglevel");
396     if (!idx)
397         idx = locate_option(argc, argv, options, "v");
398     if (idx && argv[idx + 1])
399         opt_loglevel("loglevel", argv[idx + 1]);
400     idx = locate_option(argc, argv, options, "report");
401     if (idx || getenv("FFREPORT")) {
402         opt_report("report");
403         if (report_file) {
404             int i;
405             fprintf(report_file, "Command line:\n");
406             for (i = 0; i < argc; i++) {
407                 dump_argument(argv[i]);
408                 fputc(i < argc - 1 ? ' ' : '\n', report_file);
409             }
410             fflush(report_file);
411         }
412     }
413 }
414
415 #define FLAGS(o) ((o)->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0
416 int opt_default(const char *opt, const char *arg)
417 {
418     const AVOption *oc, *of, *os;
419     char opt_stripped[128];
420     const char *p;
421     const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(), *sc;
422
423     if (!(p = strchr(opt, ':')))
424         p = opt + strlen(opt);
425     av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1));
426
427     if ((oc = av_opt_find(&cc, opt_stripped, NULL, 0,
428                          AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) ||
429         ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') &&
430          (oc = av_opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ))))
431         av_dict_set(&codec_opts, opt, arg, FLAGS(oc));
432     if ((of = av_opt_find(&fc, opt, NULL, 0,
433                           AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
434         av_dict_set(&format_opts, opt, arg, FLAGS(of));
435 #if CONFIG_SWSCALE
436     sc = sws_get_class();
437     if ((os = av_opt_find(&sc, opt, NULL, 0,
438                           AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
439         // XXX we only support sws_flags, not arbitrary sws options
440         int ret = av_opt_set(sws_opts, opt, arg, 0);
441         if (ret < 0) {
442             av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
443             return ret;
444         }
445     }
446 #endif
447
448     if (oc || of || os)
449         return 0;
450     av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt);
451     return AVERROR_OPTION_NOT_FOUND;
452 }
453
454 int opt_loglevel(const char *opt, const char *arg)
455 {
456     const struct { const char *name; int level; } log_levels[] = {
457         { "quiet"  , AV_LOG_QUIET   },
458         { "panic"  , AV_LOG_PANIC   },
459         { "fatal"  , AV_LOG_FATAL   },
460         { "error"  , AV_LOG_ERROR   },
461         { "warning", AV_LOG_WARNING },
462         { "info"   , AV_LOG_INFO    },
463         { "verbose", AV_LOG_VERBOSE },
464         { "debug"  , AV_LOG_DEBUG   },
465     };
466     char *tail;
467     int level;
468     int i;
469
470     for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
471         if (!strcmp(log_levels[i].name, arg)) {
472             av_log_set_level(log_levels[i].level);
473             return 0;
474         }
475     }
476
477     level = strtol(arg, &tail, 10);
478     if (*tail) {
479         av_log(NULL, AV_LOG_FATAL, "Invalid loglevel \"%s\". "
480                "Possible levels are numbers or:\n", arg);
481         for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)
482             av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name);
483         exit_program(1);
484     }
485     av_log_set_level(level);
486     return 0;
487 }
488
489 int opt_report(const char *opt)
490 {
491     char filename[64];
492     time_t now;
493     struct tm *tm;
494
495     if (report_file) /* already opened */
496         return 0;
497     time(&now);
498     tm = localtime(&now);
499     snprintf(filename, sizeof(filename), "%s-%04d%02d%02d-%02d%02d%02d.log",
500              program_name,
501              tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
502              tm->tm_hour, tm->tm_min, tm->tm_sec);
503     report_file = fopen(filename, "w");
504     if (!report_file) {
505         av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
506                filename, strerror(errno));
507         return AVERROR(errno);
508     }
509     av_log_set_callback(log_callback_report);
510     av_log(NULL, AV_LOG_INFO,
511            "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n"
512            "Report written to \"%s\"\n",
513            program_name,
514            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
515            tm->tm_hour, tm->tm_min, tm->tm_sec,
516            filename);
517     av_log_set_level(FFMAX(av_log_get_level(), AV_LOG_VERBOSE));
518     return 0;
519 }
520
521 int opt_max_alloc(const char *opt, const char *arg)
522 {
523     char *tail;
524     size_t max;
525
526     max = strtol(arg, &tail, 10);
527     if (*tail) {
528         av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg);
529         exit_program(1);
530     }
531     av_max_alloc(max);
532     return 0;
533 }
534
535 int opt_cpuflags(const char *opt, const char *arg)
536 {
537     static const AVOption cpuflags_opts[] = {
538         { "flags"   , NULL, 0, AV_OPT_TYPE_FLAGS, { 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
539         { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ALTIVEC  },    .unit = "flags" },
540         { "mmx"     , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_MMX      },    .unit = "flags" },
541         { "mmx2"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_MMX2     },    .unit = "flags" },
542         { "sse"     , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE      },    .unit = "flags" },
543         { "sse2"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE2     },    .unit = "flags" },
544         { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE2SLOW },    .unit = "flags" },
545         { "sse3"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE3     },    .unit = "flags" },
546         { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE3SLOW },    .unit = "flags" },
547         { "ssse3"   , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSSE3    },    .unit = "flags" },
548         { "atom"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ATOM     },    .unit = "flags" },
549         { "sse4.1"  , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE4     },    .unit = "flags" },
550         { "sse4.2"  , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_SSE42    },    .unit = "flags" },
551         { "avx"     , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_AVX      },    .unit = "flags" },
552         { "xop"     , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_XOP      },    .unit = "flags" },
553         { "fma4"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_FMA4     },    .unit = "flags" },
554         { "3dnow"   , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_3DNOW    },    .unit = "flags" },
555         { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_3DNOWEXT },    .unit = "flags" },
556         { NULL },
557     };
558     static const AVClass class = {
559         .class_name = "cpuflags",
560         .item_name  = av_default_item_name,
561         .option     = cpuflags_opts,
562         .version    = LIBAVUTIL_VERSION_INT,
563     };
564     int flags = av_get_cpu_flags();
565     int ret;
566     const AVClass *pclass = &class;
567
568     if ((ret = av_opt_eval_flags(&pclass, &cpuflags_opts[0], arg, &flags)) < 0)
569         return ret;
570
571     av_force_cpu_flags(flags);
572     return 0;
573 }
574
575 int opt_codec_debug(const char *opt, const char *arg)
576 {
577     av_log_set_level(AV_LOG_DEBUG);
578     return opt_default(opt, arg);
579 }
580
581 int opt_timelimit(const char *opt, const char *arg)
582 {
583 #if HAVE_SETRLIMIT
584     int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
585     struct rlimit rl = { lim, lim + 1 };
586     if (setrlimit(RLIMIT_CPU, &rl))
587         perror("setrlimit");
588 #else
589     av_log(NULL, AV_LOG_WARNING, "-%s not implemented on this OS\n", opt);
590 #endif
591     return 0;
592 }
593
594 void print_error(const char *filename, int err)
595 {
596     char errbuf[128];
597     const char *errbuf_ptr = errbuf;
598
599     if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
600         errbuf_ptr = strerror(AVUNERROR(err));
601     av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr);
602 }
603
604 static int warned_cfg = 0;
605
606 #define INDENT        1
607 #define SHOW_VERSION  2
608 #define SHOW_CONFIG   4
609 #define SHOW_COPYRIGHT 8
610
611 #define PRINT_LIB_INFO(libname, LIBNAME, flags, level)                  \
612     if (CONFIG_##LIBNAME) {                                             \
613         const char *indent = flags & INDENT? "  " : "";                 \
614         if (flags & SHOW_VERSION) {                                     \
615             unsigned int version = libname##_version();                 \
616             av_log(NULL, level, "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n",\
617                    indent, #libname,                                    \
618                    LIB##LIBNAME##_VERSION_MAJOR,                        \
619                    LIB##LIBNAME##_VERSION_MINOR,                        \
620                    LIB##LIBNAME##_VERSION_MICRO,                        \
621                    version >> 16, version >> 8 & 0xff, version & 0xff); \
622         }                                                               \
623         if (flags & SHOW_CONFIG) {                                      \
624             const char *cfg = libname##_configuration();                \
625             if (strcmp(FFMPEG_CONFIGURATION, cfg)) {                    \
626                 if (!warned_cfg) {                                      \
627                     av_log(NULL, level,                                 \
628                             "%sWARNING: library configuration mismatch\n", \
629                             indent);                                    \
630                     warned_cfg = 1;                                     \
631                 }                                                       \
632                 av_log(NULL, level, "%s%-11s configuration: %s\n",      \
633                         indent, #libname, cfg);                         \
634             }                                                           \
635         }                                                               \
636     }                                                                   \
637
638 static void print_all_libs_info(int flags, int level)
639 {
640     PRINT_LIB_INFO(avutil,   AVUTIL,   flags, level);
641     PRINT_LIB_INFO(avcodec,  AVCODEC,  flags, level);
642     PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
643     PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);
644     PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
645     PRINT_LIB_INFO(swscale,  SWSCALE,  flags, level);
646     PRINT_LIB_INFO(swresample,SWRESAMPLE,  flags, level);
647 #if CONFIG_POSTPROC
648     PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
649 #endif
650 }
651
652 static void print_program_info(int flags, int level)
653 {
654     const char *indent = flags & INDENT? "  " : "";
655
656     av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name);
657     if (flags & SHOW_COPYRIGHT)
658         av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers",
659                program_birth_year, this_year);
660     av_log(NULL, level, "\n");
661     av_log(NULL, level, "%sbuilt on %s %s with %s %s\n",
662            indent, __DATE__, __TIME__, CC_TYPE, CC_VERSION);
663     av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent);
664 }
665
666 void show_banner(int argc, char **argv, const OptionDef *options)
667 {
668     int idx = locate_option(argc, argv, options, "version");
669     if (idx)
670         return;
671
672     print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
673     print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_INFO);
674     print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
675 }
676
677 int opt_version(const char *opt, const char *arg) {
678     av_log_set_callback(log_callback_help);
679     print_program_info (0           , AV_LOG_INFO);
680     print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
681     return 0;
682 }
683
684 int opt_license(const char *opt, const char *arg)
685 {
686     printf(
687 #if CONFIG_NONFREE
688     "This version of %s has nonfree parts compiled in.\n"
689     "Therefore it is not legally redistributable.\n",
690     program_name
691 #elif CONFIG_GPLV3
692     "%s is free software; you can redistribute it and/or modify\n"
693     "it under the terms of the GNU General Public License as published by\n"
694     "the Free Software Foundation; either version 3 of the License, or\n"
695     "(at your option) any later version.\n"
696     "\n"
697     "%s is distributed in the hope that it will be useful,\n"
698     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
699     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
700     "GNU General Public License for more details.\n"
701     "\n"
702     "You should have received a copy of the GNU General Public License\n"
703     "along with %s.  If not, see <http://www.gnu.org/licenses/>.\n",
704     program_name, program_name, program_name
705 #elif CONFIG_GPL
706     "%s is free software; you can redistribute it and/or modify\n"
707     "it under the terms of the GNU General Public License as published by\n"
708     "the Free Software Foundation; either version 2 of the License, or\n"
709     "(at your option) any later version.\n"
710     "\n"
711     "%s is distributed in the hope that it will be useful,\n"
712     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
713     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
714     "GNU General Public License for more details.\n"
715     "\n"
716     "You should have received a copy of the GNU General Public License\n"
717     "along with %s; if not, write to the Free Software\n"
718     "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
719     program_name, program_name, program_name
720 #elif CONFIG_LGPLV3
721     "%s is free software; you can redistribute it and/or modify\n"
722     "it under the terms of the GNU Lesser General Public License as published by\n"
723     "the Free Software Foundation; either version 3 of the License, or\n"
724     "(at your option) any later version.\n"
725     "\n"
726     "%s is distributed in the hope that it will be useful,\n"
727     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
728     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
729     "GNU Lesser General Public License for more details.\n"
730     "\n"
731     "You should have received a copy of the GNU Lesser General Public License\n"
732     "along with %s.  If not, see <http://www.gnu.org/licenses/>.\n",
733     program_name, program_name, program_name
734 #else
735     "%s is free software; you can redistribute it and/or\n"
736     "modify it under the terms of the GNU Lesser General Public\n"
737     "License as published by the Free Software Foundation; either\n"
738     "version 2.1 of the License, or (at your option) any later version.\n"
739     "\n"
740     "%s is distributed in the hope that it will be useful,\n"
741     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
742     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
743     "Lesser General Public License for more details.\n"
744     "\n"
745     "You should have received a copy of the GNU Lesser General Public\n"
746     "License along with %s; if not, write to the Free Software\n"
747     "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
748     program_name, program_name, program_name
749 #endif
750     );
751     return 0;
752 }
753
754 int opt_formats(const char *opt, const char *arg)
755 {
756     AVInputFormat *ifmt  = NULL;
757     AVOutputFormat *ofmt = NULL;
758     const char *last_name;
759
760     printf("File formats:\n"
761            " D. = Demuxing supported\n"
762            " .E = Muxing supported\n"
763            " --\n");
764     last_name = "000";
765     for (;;) {
766         int decode = 0;
767         int encode = 0;
768         const char *name      = NULL;
769         const char *long_name = NULL;
770
771         while ((ofmt = av_oformat_next(ofmt))) {
772             if ((name == NULL || strcmp(ofmt->name, name) < 0) &&
773                 strcmp(ofmt->name, last_name) > 0) {
774                 name      = ofmt->name;
775                 long_name = ofmt->long_name;
776                 encode    = 1;
777             }
778         }
779         while ((ifmt = av_iformat_next(ifmt))) {
780             if ((name == NULL || strcmp(ifmt->name, name) < 0) &&
781                 strcmp(ifmt->name, last_name) > 0) {
782                 name      = ifmt->name;
783                 long_name = ifmt->long_name;
784                 encode    = 0;
785             }
786             if (name && strcmp(ifmt->name, name) == 0)
787                 decode = 1;
788         }
789         if (name == NULL)
790             break;
791         last_name = name;
792
793         printf(" %s%s %-15s %s\n",
794                decode ? "D" : " ",
795                encode ? "E" : " ",
796                name,
797             long_name ? long_name:" ");
798     }
799     return 0;
800 }
801
802 static char get_media_type_char(enum AVMediaType type)
803 {
804     static const char map[AVMEDIA_TYPE_NB] = {
805         [AVMEDIA_TYPE_VIDEO]      = 'V',
806         [AVMEDIA_TYPE_AUDIO]      = 'A',
807         [AVMEDIA_TYPE_DATA]       = 'D',
808         [AVMEDIA_TYPE_SUBTITLE]   = 'S',
809         [AVMEDIA_TYPE_ATTACHMENT] = 'T',
810     };
811     return type >= 0 && type < AVMEDIA_TYPE_NB && map[type] ? map[type] : '?';
812 }
813
814 int opt_codecs(const char *opt, const char *arg)
815 {
816     AVCodec *p = NULL, *p2;
817     const char *last_name;
818     printf("Codecs:\n"
819            " D..... = Decoding supported\n"
820            " .E.... = Encoding supported\n"
821            " ..V... = Video codec\n"
822            " ..A... = Audio codec\n"
823            " ..S... = Subtitle codec\n"
824            " ...S.. = Supports draw_horiz_band\n"
825            " ....D. = Supports direct rendering method 1\n"
826            " .....T = Supports weird frame truncation\n"
827            " ------\n");
828     last_name= "000";
829     for (;;) {
830         int decode = 0;
831         int encode = 0;
832         int cap    = 0;
833
834         p2 = NULL;
835         while ((p = av_codec_next(p))) {
836             if ((p2 == NULL || strcmp(p->name, p2->name) < 0) &&
837                 strcmp(p->name, last_name) > 0) {
838                 p2 = p;
839                 decode = encode = cap = 0;
840             }
841             if (p2 && strcmp(p->name, p2->name) == 0) {
842                 if (av_codec_is_decoder(p))
843                     decode = 1;
844                 if (av_codec_is_encoder(p))
845                     encode = 1;
846                 cap |= p->capabilities;
847             }
848         }
849         if (p2 == NULL)
850             break;
851         last_name = p2->name;
852
853         printf(" %s%s%c%s%s%s %-15s %s",
854                decode ? "D" : (/* p2->decoder ? "d" : */ " "),
855                encode ? "E" : " ",
856                get_media_type_char(p2->type),
857                cap & CODEC_CAP_DRAW_HORIZ_BAND ? "S" : " ",
858                cap & CODEC_CAP_DR1 ? "D" : " ",
859                cap & CODEC_CAP_TRUNCATED ? "T" : " ",
860                p2->name,
861                p2->long_name ? p2->long_name : "");
862 #if 0
863             if (p2->decoder && decode == 0)
864                 printf(" use %s for decoding", p2->decoder->name);
865 #endif
866         printf("\n");
867     }
868     printf("\n");
869     printf("Note, the names of encoders and decoders do not always match, so there are\n"
870            "several cases where the above table shows encoder only or decoder only entries\n"
871            "even though both encoding and decoding are supported. For example, the h263\n"
872            "decoder corresponds to the h263 and h263p encoders, for file formats it is even\n"
873            "worse.\n");
874     return 0;
875 }
876
877 int opt_bsfs(const char *opt, const char *arg)
878 {
879     AVBitStreamFilter *bsf = NULL;
880
881     printf("Bitstream filters:\n");
882     while ((bsf = av_bitstream_filter_next(bsf)))
883         printf("%s\n", bsf->name);
884     printf("\n");
885     return 0;
886 }
887
888 int opt_protocols(const char *opt, const char *arg)
889 {
890     void *opaque = NULL;
891     const char *name;
892
893     printf("Supported file protocols:\n"
894            "Input:\n");
895     while ((name = avio_enum_protocols(&opaque, 0)))
896         printf("%s\n", name);
897     printf("Output:\n");
898     while ((name = avio_enum_protocols(&opaque, 1)))
899         printf("%s\n", name);
900     return 0;
901 }
902
903 int opt_filters(const char *opt, const char *arg)
904 {
905     AVFilter av_unused(**filter) = NULL;
906     char descr[64], *descr_cur;
907     int i, j;
908     const AVFilterPad *pad;
909
910     printf("Filters:\n");
911 #if CONFIG_AVFILTER
912     while ((filter = av_filter_next(filter)) && *filter) {
913         descr_cur = descr;
914         for (i = 0; i < 2; i++) {
915             if (i) {
916                 *(descr_cur++) = '-';
917                 *(descr_cur++) = '>';
918             }
919             pad = i ? (*filter)->outputs : (*filter)->inputs;
920             for (j = 0; pad[j].name; j++) {
921                 if (descr_cur >= descr + sizeof(descr) - 4)
922                     break;
923                 *(descr_cur++) = get_media_type_char(pad[j].type);
924             }
925             if (!j)
926                 *(descr_cur++) = '|';
927         }
928         *descr_cur = 0;
929         printf("%-16s %-10s %s\n", (*filter)->name, descr, (*filter)->description);
930     }
931 #endif
932     return 0;
933 }
934
935 int opt_pix_fmts(const char *opt, const char *arg)
936 {
937     enum PixelFormat pix_fmt;
938
939     printf("Pixel formats:\n"
940            "I.... = Supported Input  format for conversion\n"
941            ".O... = Supported Output format for conversion\n"
942            "..H.. = Hardware accelerated format\n"
943            "...P. = Paletted format\n"
944            "....B = Bitstream format\n"
945            "FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL\n"
946            "-----\n");
947
948 #if !CONFIG_SWSCALE
949 #   define sws_isSupportedInput(x)  0
950 #   define sws_isSupportedOutput(x) 0
951 #endif
952
953     for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) {
954         const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[pix_fmt];
955         if(!pix_desc->name)
956             continue;
957         printf("%c%c%c%c%c %-16s       %d            %2d\n",
958                sws_isSupportedInput (pix_fmt)      ? 'I' : '.',
959                sws_isSupportedOutput(pix_fmt)      ? 'O' : '.',
960                pix_desc->flags & PIX_FMT_HWACCEL   ? 'H' : '.',
961                pix_desc->flags & PIX_FMT_PAL       ? 'P' : '.',
962                pix_desc->flags & PIX_FMT_BITSTREAM ? 'B' : '.',
963                pix_desc->name,
964                pix_desc->nb_components,
965                av_get_bits_per_pixel(pix_desc));
966     }
967     return 0;
968 }
969
970 int show_sample_fmts(const char *opt, const char *arg)
971 {
972     int i;
973     char fmt_str[128];
974     for (i = -1; i < AV_SAMPLE_FMT_NB; i++)
975         printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i));
976     return 0;
977 }
978
979 int read_yesno(void)
980 {
981     int c = getchar();
982     int yesno = (toupper(c) == 'Y');
983
984     while (c != '\n' && c != EOF)
985         c = getchar();
986
987     return yesno;
988 }
989
990 int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
991 {
992     int ret;
993     FILE *f = fopen(filename, "rb");
994
995     if (!f) {
996         av_log(NULL, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename,
997                strerror(errno));
998         return AVERROR(errno);
999     }
1000     fseek(f, 0, SEEK_END);
1001     *size = ftell(f);
1002     fseek(f, 0, SEEK_SET);
1003     *bufptr = av_malloc(*size + 1);
1004     if (!*bufptr) {
1005         av_log(NULL, AV_LOG_ERROR, "Could not allocate file buffer\n");
1006         fclose(f);
1007         return AVERROR(ENOMEM);
1008     }
1009     ret = fread(*bufptr, 1, *size, f);
1010     if (ret < *size) {
1011         av_free(*bufptr);
1012         if (ferror(f)) {
1013             av_log(NULL, AV_LOG_ERROR, "Error while reading file '%s': %s\n",
1014                    filename, strerror(errno));
1015             ret = AVERROR(errno);
1016         } else
1017             ret = AVERROR_EOF;
1018     } else {
1019         ret = 0;
1020         (*bufptr)[*size++] = '\0';
1021     }
1022
1023     fclose(f);
1024     return ret;
1025 }
1026
1027 FILE *get_preset_file(char *filename, size_t filename_size,
1028                       const char *preset_name, int is_path,
1029                       const char *codec_name)
1030 {
1031     FILE *f = NULL;
1032     int i;
1033     const char *base[3] = { getenv("FFMPEG_DATADIR"),
1034                             getenv("HOME"),
1035                             FFMPEG_DATADIR, };
1036
1037     if (is_path) {
1038         av_strlcpy(filename, preset_name, filename_size);
1039         f = fopen(filename, "r");
1040     } else {
1041 #ifdef _WIN32
1042         char datadir[MAX_PATH], *ls;
1043         base[2] = NULL;
1044
1045         if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1))
1046         {
1047             for (ls = datadir; ls < datadir + strlen(datadir); ls++)
1048                 if (*ls == '\\') *ls = '/';
1049
1050             if (ls = strrchr(datadir, '/'))
1051             {
1052                 *ls = 0;
1053                 strncat(datadir, "/ffpresets",  sizeof(datadir) - 1 - strlen(datadir));
1054                 base[2] = datadir;
1055             }
1056         }
1057 #endif
1058         for (i = 0; i < 3 && !f; i++) {
1059             if (!base[i])
1060                 continue;
1061             snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i],
1062                      i != 1 ? "" : "/.ffmpeg", preset_name);
1063             f = fopen(filename, "r");
1064             if (!f && codec_name) {
1065                 snprintf(filename, filename_size,
1066                          "%s%s/%s-%s.ffpreset",
1067                          base[i],  i != 1 ? "" : "/.ffmpeg", codec_name,
1068                          preset_name);
1069                 f = fopen(filename, "r");
1070             }
1071         }
1072     }
1073
1074     return f;
1075 }
1076
1077 int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
1078 {
1079     if (*spec <= '9' && *spec >= '0') /* opt:index */
1080         return strtol(spec, NULL, 0) == st->index;
1081     else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
1082              *spec == 't') { /* opt:[vasdt] */
1083         enum AVMediaType type;
1084
1085         switch (*spec++) {
1086         case 'v': type = AVMEDIA_TYPE_VIDEO;      break;
1087         case 'a': type = AVMEDIA_TYPE_AUDIO;      break;
1088         case 's': type = AVMEDIA_TYPE_SUBTITLE;   break;
1089         case 'd': type = AVMEDIA_TYPE_DATA;       break;
1090         case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
1091         default: abort(); // never reached, silence warning
1092         }
1093         if (type != st->codec->codec_type)
1094             return 0;
1095         if (*spec++ == ':') { /* possibly followed by :index */
1096             int i, index = strtol(spec, NULL, 0);
1097             for (i = 0; i < s->nb_streams; i++)
1098                 if (s->streams[i]->codec->codec_type == type && index-- == 0)
1099                    return i == st->index;
1100             return 0;
1101         }
1102         return 1;
1103     } else if (*spec == 'p' && *(spec + 1) == ':') {
1104         int prog_id, i, j;
1105         char *endptr;
1106         spec += 2;
1107         prog_id = strtol(spec, &endptr, 0);
1108         for (i = 0; i < s->nb_programs; i++) {
1109             if (s->programs[i]->id != prog_id)
1110                 continue;
1111
1112             if (*endptr++ == ':') {
1113                 int stream_idx = strtol(endptr, NULL, 0);
1114                 return stream_idx >= 0 &&
1115                     stream_idx < s->programs[i]->nb_stream_indexes &&
1116                     st->index == s->programs[i]->stream_index[stream_idx];
1117             }
1118
1119             for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
1120                 if (st->index == s->programs[i]->stream_index[j])
1121                     return 1;
1122         }
1123         return 0;
1124     } else if (!*spec) /* empty specifier, matches everything */
1125         return 1;
1126
1127     av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
1128     return AVERROR(EINVAL);
1129 }
1130
1131 AVDictionary *filter_codec_opts(AVDictionary *opts, AVCodec *codec,
1132                                 AVFormatContext *s, AVStream *st)
1133 {
1134     AVDictionary    *ret = NULL;
1135     AVDictionaryEntry *t = NULL;
1136     int            flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM
1137                                       : AV_OPT_FLAG_DECODING_PARAM;
1138     char          prefix = 0;
1139     const AVClass    *cc = avcodec_get_class();
1140
1141     if (!codec)
1142         return NULL;
1143
1144     switch (codec->type) {
1145     case AVMEDIA_TYPE_VIDEO:
1146         prefix  = 'v';
1147         flags  |= AV_OPT_FLAG_VIDEO_PARAM;
1148         break;
1149     case AVMEDIA_TYPE_AUDIO:
1150         prefix  = 'a';
1151         flags  |= AV_OPT_FLAG_AUDIO_PARAM;
1152         break;
1153     case AVMEDIA_TYPE_SUBTITLE:
1154         prefix  = 's';
1155         flags  |= AV_OPT_FLAG_SUBTITLE_PARAM;
1156         break;
1157     }
1158
1159     while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) {
1160         char *p = strchr(t->key, ':');
1161
1162         /* check stream specification in opt name */
1163         if (p)
1164             switch (check_stream_specifier(s, st, p + 1)) {
1165             case  1: *p = 0; break;
1166             case  0:         continue;
1167             default:         return NULL;
1168             }
1169
1170         if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
1171             (codec && codec->priv_class &&
1172              av_opt_find(&codec->priv_class, t->key, NULL, flags,
1173                          AV_OPT_SEARCH_FAKE_OBJ)))
1174             av_dict_set(&ret, t->key, t->value, 0);
1175         else if (t->key[0] == prefix &&
1176                  av_opt_find(&cc, t->key + 1, NULL, flags,
1177                              AV_OPT_SEARCH_FAKE_OBJ))
1178             av_dict_set(&ret, t->key + 1, t->value, 0);
1179
1180         if (p)
1181             *p = ':';
1182     }
1183     return ret;
1184 }
1185
1186 AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
1187                                            AVDictionary *codec_opts)
1188 {
1189     int i;
1190     AVDictionary **opts;
1191
1192     if (!s->nb_streams)
1193         return NULL;
1194     opts = av_mallocz(s->nb_streams * sizeof(*opts));
1195     if (!opts) {
1196         av_log(NULL, AV_LOG_ERROR,
1197                "Could not alloc memory for stream options.\n");
1198         return NULL;
1199     }
1200     for (i = 0; i < s->nb_streams; i++)
1201         opts[i] = filter_codec_opts(codec_opts, avcodec_find_decoder(s->streams[i]->codec->codec_id),
1202                                     s, s->streams[i]);
1203     return opts;
1204 }
1205
1206 void *grow_array(void *array, int elem_size, int *size, int new_size)
1207 {
1208     if (new_size >= INT_MAX / elem_size) {
1209         av_log(NULL, AV_LOG_ERROR, "Array too big.\n");
1210         exit_program(1);
1211     }
1212     if (*size < new_size) {
1213         uint8_t *tmp = av_realloc(array, new_size*elem_size);
1214         if (!tmp) {
1215             av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
1216             exit_program(1);
1217         }
1218         memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
1219         *size = new_size;
1220         return tmp;
1221     }
1222     return array;
1223 }