lavu/parseutils: add more resolutions
[ffmpeg.git] / libavutil / parseutils.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 /**
20  * @file
21  * misc parsing utilities
22  */
23
24 #include <time.h>
25
26 #include "avstring.h"
27 #include "avutil.h"
28 #include "common.h"
29 #include "eval.h"
30 #include "log.h"
31 #include "random_seed.h"
32 #include "parseutils.h"
33
34 #ifdef TEST
35
36 #define av_get_random_seed av_get_random_seed_deterministic
37 static uint32_t av_get_random_seed_deterministic(void);
38
39 #define time(t) 1331972053
40
41 #endif
42
43 int av_parse_ratio(AVRational *q, const char *str, int max,
44                    int log_offset, void *log_ctx)
45 {
46     char c;
47     int ret;
48
49     if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) {
50         double d;
51         ret = av_expr_parse_and_eval(&d, str, NULL, NULL,
52                                      NULL, NULL, NULL, NULL,
53                                      NULL, log_offset, log_ctx);
54         if (ret < 0)
55             return ret;
56         *q = av_d2q(d, max);
57     } else {
58         av_reduce(&q->num, &q->den, q->num, q->den, max);
59     }
60
61     return 0;
62 }
63
64 typedef struct {
65     const char *abbr;
66     int width, height;
67 } VideoSizeAbbr;
68
69 typedef struct {
70     const char *abbr;
71     AVRational rate;
72 } VideoRateAbbr;
73
74 static const VideoSizeAbbr video_size_abbrs[] = {
75     { "ntsc",      720, 480 },
76     { "pal",       720, 576 },
77     { "qntsc",     352, 240 }, /* VCD compliant NTSC */
78     { "qpal",      352, 288 }, /* VCD compliant PAL */
79     { "sntsc",     640, 480 }, /* square pixel NTSC */
80     { "spal",      768, 576 }, /* square pixel PAL */
81     { "film",      352, 240 },
82     { "ntsc-film", 352, 240 },
83     { "sqcif",     128,  96 },
84     { "qcif",      176, 144 },
85     { "cif",       352, 288 },
86     { "4cif",      704, 576 },
87     { "16cif",    1408,1152 },
88     { "qqvga",     160, 120 },
89     { "qvga",      320, 240 },
90     { "vga",       640, 480 },
91     { "svga",      800, 600 },
92     { "xga",      1024, 768 },
93     { "uxga",     1600,1200 },
94     { "qxga",     2048,1536 },
95     { "sxga",     1280,1024 },
96     { "qsxga",    2560,2048 },
97     { "hsxga",    5120,4096 },
98     { "wvga",      852, 480 },
99     { "wxga",     1366, 768 },
100     { "wsxga",    1600,1024 },
101     { "wuxga",    1920,1200 },
102     { "woxga",    2560,1600 },
103     { "wqsxga",   3200,2048 },
104     { "wquxga",   3840,2400 },
105     { "whsxga",   6400,4096 },
106     { "whuxga",   7680,4800 },
107     { "cga",       320, 200 },
108     { "ega",       640, 350 },
109     { "hd480",     852, 480 },
110     { "hd720",    1280, 720 },
111     { "hd1080",   1920,1080 },
112     { "2k",       2048,1080 }, /* Digital Cinema System Specification */
113     { "2kflat",   1998,1080 },
114     { "2kscope",  2048, 858 },
115     { "4k",       4096,2160 }, /* Digital Cinema System Specification */
116     { "4kflat",   3996,2160 },
117     { "4kscope",  4096,1716 },
118     { "nhd",       640,360  },
119     { "hqvga",     240,160  },
120     { "wqvga",     400,240  },
121     { "fwqvga",    432,240  },
122     { "hvga",      480,320  },
123     { "qhd",       960,540  },
124 };
125
126 static const VideoRateAbbr video_rate_abbrs[]= {
127     { "ntsc",      { 30000, 1001 } },
128     { "pal",       {    25,    1 } },
129     { "qntsc",     { 30000, 1001 } }, /* VCD compliant NTSC */
130     { "qpal",      {    25,    1 } }, /* VCD compliant PAL */
131     { "sntsc",     { 30000, 1001 } }, /* square pixel NTSC */
132     { "spal",      {    25,    1 } }, /* square pixel PAL */
133     { "film",      {    24,    1 } },
134     { "ntsc-film", { 24000, 1001 } },
135 };
136
137 int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
138 {
139     int i;
140     int n = FF_ARRAY_ELEMS(video_size_abbrs);
141     const char *p;
142     int width = 0, height = 0;
143
144     for (i = 0; i < n; i++) {
145         if (!strcmp(video_size_abbrs[i].abbr, str)) {
146             width  = video_size_abbrs[i].width;
147             height = video_size_abbrs[i].height;
148             break;
149         }
150     }
151     if (i == n) {
152         width = strtol(str, (void*)&p, 10);
153         if (*p)
154             p++;
155         height = strtol(p, (void*)&p, 10);
156
157         /* trailing extraneous data detected, like in 123x345foobar */
158         if (*p)
159             return AVERROR(EINVAL);
160     }
161     if (width <= 0 || height <= 0)
162         return AVERROR(EINVAL);
163     *width_ptr  = width;
164     *height_ptr = height;
165     return 0;
166 }
167
168 int av_parse_video_rate(AVRational *rate, const char *arg)
169 {
170     int i, ret;
171     int n = FF_ARRAY_ELEMS(video_rate_abbrs);
172
173     /* First, we check our abbreviation table */
174     for (i = 0; i < n; ++i)
175         if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
176             *rate = video_rate_abbrs[i].rate;
177             return 0;
178         }
179
180     /* Then, we try to parse it as fraction */
181     if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0)
182         return ret;
183     if (rate->num <= 0 || rate->den <= 0)
184         return AVERROR(EINVAL);
185     return 0;
186 }
187
188 typedef struct {
189     const char *name;            ///< a string representing the name of the color
190     uint8_t     rgb_color[3];    ///< RGB values for the color
191 } ColorEntry;
192
193 static const ColorEntry color_table[] = {
194     { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
195     { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
196     { "Aqua",                 { 0x00, 0xFF, 0xFF } },
197     { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
198     { "Azure",                { 0xF0, 0xFF, 0xFF } },
199     { "Beige",                { 0xF5, 0xF5, 0xDC } },
200     { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
201     { "Black",                { 0x00, 0x00, 0x00 } },
202     { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
203     { "Blue",                 { 0x00, 0x00, 0xFF } },
204     { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
205     { "Brown",                { 0xA5, 0x2A, 0x2A } },
206     { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
207     { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
208     { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
209     { "Chocolate",            { 0xD2, 0x69, 0x1E } },
210     { "Coral",                { 0xFF, 0x7F, 0x50 } },
211     { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
212     { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
213     { "Crimson",              { 0xDC, 0x14, 0x3C } },
214     { "Cyan",                 { 0x00, 0xFF, 0xFF } },
215     { "DarkBlue",             { 0x00, 0x00, 0x8B } },
216     { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
217     { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
218     { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
219     { "DarkGreen",            { 0x00, 0x64, 0x00 } },
220     { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
221     { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
222     { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
223     { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
224     { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
225     { "DarkRed",              { 0x8B, 0x00, 0x00 } },
226     { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
227     { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
228     { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
229     { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
230     { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
231     { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
232     { "DeepPink",             { 0xFF, 0x14, 0x93 } },
233     { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
234     { "DimGray",              { 0x69, 0x69, 0x69 } },
235     { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
236     { "FireBrick",            { 0xB2, 0x22, 0x22 } },
237     { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
238     { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
239     { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
240     { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
241     { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
242     { "Gold",                 { 0xFF, 0xD7, 0x00 } },
243     { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
244     { "Gray",                 { 0x80, 0x80, 0x80 } },
245     { "Green",                { 0x00, 0x80, 0x00 } },
246     { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
247     { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
248     { "HotPink",              { 0xFF, 0x69, 0xB4 } },
249     { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
250     { "Indigo",               { 0x4B, 0x00, 0x82 } },
251     { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
252     { "Khaki",                { 0xF0, 0xE6, 0x8C } },
253     { "Lavender",             { 0xE6, 0xE6, 0xFA } },
254     { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
255     { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
256     { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
257     { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
258     { "LightCoral",           { 0xF0, 0x80, 0x80 } },
259     { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
260     { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
261     { "LightGreen",           { 0x90, 0xEE, 0x90 } },
262     { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
263     { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
264     { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
265     { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
266     { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
267     { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
268     { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
269     { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
270     { "Lime",                 { 0x00, 0xFF, 0x00 } },
271     { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
272     { "Linen",                { 0xFA, 0xF0, 0xE6 } },
273     { "Magenta",              { 0xFF, 0x00, 0xFF } },
274     { "Maroon",               { 0x80, 0x00, 0x00 } },
275     { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
276     { "MediumBlue",           { 0x00, 0x00, 0xCD } },
277     { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
278     { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
279     { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
280     { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
281     { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
282     { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
283     { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
284     { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
285     { "MintCream",            { 0xF5, 0xFF, 0xFA } },
286     { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
287     { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
288     { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
289     { "Navy",                 { 0x00, 0x00, 0x80 } },
290     { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
291     { "Olive",                { 0x80, 0x80, 0x00 } },
292     { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
293     { "Orange",               { 0xFF, 0xA5, 0x00 } },
294     { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
295     { "Orchid",               { 0xDA, 0x70, 0xD6 } },
296     { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
297     { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
298     { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
299     { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
300     { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
301     { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
302     { "Peru",                 { 0xCD, 0x85, 0x3F } },
303     { "Pink",                 { 0xFF, 0xC0, 0xCB } },
304     { "Plum",                 { 0xDD, 0xA0, 0xDD } },
305     { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
306     { "Purple",               { 0x80, 0x00, 0x80 } },
307     { "Red",                  { 0xFF, 0x00, 0x00 } },
308     { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
309     { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
310     { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
311     { "Salmon",               { 0xFA, 0x80, 0x72 } },
312     { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
313     { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
314     { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
315     { "Sienna",               { 0xA0, 0x52, 0x2D } },
316     { "Silver",               { 0xC0, 0xC0, 0xC0 } },
317     { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
318     { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
319     { "SlateGray",            { 0x70, 0x80, 0x90 } },
320     { "Snow",                 { 0xFF, 0xFA, 0xFA } },
321     { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
322     { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
323     { "Tan",                  { 0xD2, 0xB4, 0x8C } },
324     { "Teal",                 { 0x00, 0x80, 0x80 } },
325     { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
326     { "Tomato",               { 0xFF, 0x63, 0x47 } },
327     { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
328     { "Violet",               { 0xEE, 0x82, 0xEE } },
329     { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
330     { "White",                { 0xFF, 0xFF, 0xFF } },
331     { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
332     { "Yellow",               { 0xFF, 0xFF, 0x00 } },
333     { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
334 };
335
336 static int color_table_compare(const void *lhs, const void *rhs)
337 {
338     return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
339 }
340
341 #define ALPHA_SEP '@'
342
343 int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
344                    void *log_ctx)
345 {
346     char *tail, color_string2[128];
347     const ColorEntry *entry;
348     int len, hex_offset = 0;
349
350     if (color_string[0] == '#') {
351         hex_offset = 1;
352     } else if (!strncmp(color_string, "0x", 2))
353         hex_offset = 2;
354
355     if (slen < 0)
356         slen = strlen(color_string);
357     av_strlcpy(color_string2, color_string + hex_offset,
358                FFMIN(slen-hex_offset+1, sizeof(color_string2)));
359     if ((tail = strchr(color_string2, ALPHA_SEP)))
360         *tail++ = 0;
361     len = strlen(color_string2);
362     rgba_color[3] = 255;
363
364     if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) {
365         int rgba = av_get_random_seed();
366         rgba_color[0] = rgba >> 24;
367         rgba_color[1] = rgba >> 16;
368         rgba_color[2] = rgba >> 8;
369         rgba_color[3] = rgba;
370     } else if (hex_offset ||
371                strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
372         char *tail;
373         unsigned int rgba = strtoul(color_string2, &tail, 16);
374
375         if (*tail || (len != 6 && len != 8)) {
376             av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
377             return AVERROR(EINVAL);
378         }
379         if (len == 8) {
380             rgba_color[3] = rgba;
381             rgba >>= 8;
382         }
383         rgba_color[0] = rgba >> 16;
384         rgba_color[1] = rgba >> 8;
385         rgba_color[2] = rgba;
386     } else {
387         entry = bsearch(color_string2,
388                         color_table,
389                         FF_ARRAY_ELEMS(color_table),
390                         sizeof(ColorEntry),
391                         color_table_compare);
392         if (!entry) {
393             av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
394             return AVERROR(EINVAL);
395         }
396         memcpy(rgba_color, entry->rgb_color, 3);
397     }
398
399     if (tail) {
400         double alpha;
401         const char *alpha_string = tail;
402         if (!strncmp(alpha_string, "0x", 2)) {
403             alpha = strtoul(alpha_string, &tail, 16);
404         } else {
405             double norm_alpha = strtod(alpha_string, &tail);
406             if (norm_alpha < 0.0 || norm_alpha > 1.0)
407                 alpha = 256;
408             else
409                 alpha = 255 * norm_alpha;
410         }
411
412         if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) {
413             av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
414                    alpha_string, color_string);
415             return AVERROR(EINVAL);
416         }
417         rgba_color[3] = alpha;
418     }
419
420     return 0;
421 }
422
423 /* get a positive number between n_min and n_max, for a maximum length
424    of len_max. Return -1 if error. */
425 static int date_get_num(const char **pp,
426                         int n_min, int n_max, int len_max)
427 {
428     int i, val, c;
429     const char *p;
430
431     p = *pp;
432     val = 0;
433     for(i = 0; i < len_max; i++) {
434         c = *p;
435         if (!av_isdigit(c))
436             break;
437         val = (val * 10) + c - '0';
438         p++;
439     }
440     /* no number read ? */
441     if (p == *pp)
442         return -1;
443     if (val < n_min || val > n_max)
444         return -1;
445     *pp = p;
446     return val;
447 }
448
449 char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
450 {
451     int c, val;
452
453     for(;;) {
454         /* consume time string until a non whitespace char is found */
455         while (av_isspace(*fmt)) {
456             while (av_isspace(*p))
457                 p++;
458             fmt++;
459         }
460         c = *fmt++;
461         if (c == '\0') {
462             return (char *)p;
463         } else if (c == '%') {
464             c = *fmt++;
465             switch(c) {
466             case 'H':
467             case 'J':
468                 val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2);
469                 if (val == -1)
470                     return NULL;
471                 dt->tm_hour = val;
472                 break;
473             case 'M':
474                 val = date_get_num(&p, 0, 59, 2);
475                 if (val == -1)
476                     return NULL;
477                 dt->tm_min = val;
478                 break;
479             case 'S':
480                 val = date_get_num(&p, 0, 59, 2);
481                 if (val == -1)
482                     return NULL;
483                 dt->tm_sec = val;
484                 break;
485             case 'Y':
486                 val = date_get_num(&p, 0, 9999, 4);
487                 if (val == -1)
488                     return NULL;
489                 dt->tm_year = val - 1900;
490                 break;
491             case 'm':
492                 val = date_get_num(&p, 1, 12, 2);
493                 if (val == -1)
494                     return NULL;
495                 dt->tm_mon = val - 1;
496                 break;
497             case 'd':
498                 val = date_get_num(&p, 1, 31, 2);
499                 if (val == -1)
500                     return NULL;
501                 dt->tm_mday = val;
502                 break;
503             case '%':
504                 goto match;
505             default:
506                 return NULL;
507             }
508         } else {
509         match:
510             if (c != *p)
511                 return NULL;
512             p++;
513         }
514     }
515 }
516
517 time_t av_timegm(struct tm *tm)
518 {
519     time_t t;
520
521     int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
522
523     if (m < 3) {
524         m += 12;
525         y--;
526     }
527
528     t = 86400LL *
529         (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
530
531     t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
532
533     return t;
534 }
535
536 int av_parse_time(int64_t *timeval, const char *timestr, int duration)
537 {
538     const char *p, *q;
539     int64_t t;
540     time_t now;
541     struct tm dt = { 0 };
542     int today = 0, negative = 0, microseconds = 0;
543     int i;
544     static const char * const date_fmt[] = {
545         "%Y-%m-%d",
546         "%Y%m%d",
547     };
548     static const char * const time_fmt[] = {
549         "%H:%M:%S",
550         "%H%M%S",
551     };
552
553     p = timestr;
554     q = NULL;
555     *timeval = INT64_MIN;
556     if (!duration) {
557         now = time(0);
558
559         if (!av_strcasecmp(timestr, "now")) {
560             *timeval = (int64_t) now * 1000000;
561             return 0;
562         }
563
564         /* parse the year-month-day part */
565         for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
566             q = av_small_strptime(p, date_fmt[i], &dt);
567             if (q)
568                 break;
569         }
570
571         /* if the year-month-day part is missing, then take the
572          * current year-month-day time */
573         if (!q) {
574             today = 1;
575             q = p;
576         }
577         p = q;
578
579         if (*p == 'T' || *p == 't' || *p == ' ')
580             p++;
581
582         /* parse the hour-minute-second part */
583         for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
584             q = av_small_strptime(p, time_fmt[i], &dt);
585             if (q)
586                 break;
587         }
588     } else {
589         /* parse timestr as a duration */
590         if (p[0] == '-') {
591             negative = 1;
592             ++p;
593         }
594         /* parse timestr as HH:MM:SS */
595         q = av_small_strptime(p, "%J:%M:%S", &dt);
596         if (!q) {
597             /* parse timestr as MM:SS */
598             q = av_small_strptime(p, "%M:%S", &dt);
599             dt.tm_hour = 0;
600         }
601         if (!q) {
602             /* parse timestr as S+ */
603             dt.tm_sec = strtol(p, (void *)&q, 10);
604             if (q == p) /* the parsing didn't succeed */
605                 return AVERROR(EINVAL);
606             dt.tm_min = 0;
607             dt.tm_hour = 0;
608         }
609     }
610
611     /* Now we have all the fields that we can get */
612     if (!q)
613         return AVERROR(EINVAL);
614
615     /* parse the .m... part */
616     if (*q == '.') {
617         int n;
618         q++;
619         for (n = 100000; n >= 1; n /= 10, q++) {
620             if (!av_isdigit(*q))
621                 break;
622             microseconds += n * (*q - '0');
623         }
624         while (av_isdigit(*q))
625             q++;
626     }
627
628     if (duration) {
629         t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
630     } else {
631         int is_utc = *q == 'Z' || *q == 'z';
632         q += is_utc;
633         if (today) { /* fill in today's date */
634             struct tm dt2 = is_utc ? *gmtime(&now) : *localtime(&now);
635             dt2.tm_hour = dt.tm_hour;
636             dt2.tm_min  = dt.tm_min;
637             dt2.tm_sec  = dt.tm_sec;
638             dt = dt2;
639         }
640         t = is_utc ? av_timegm(&dt) : mktime(&dt);
641     }
642
643     /* Check that we are at the end of the string */
644     if (*q)
645         return AVERROR(EINVAL);
646
647     t *= 1000000;
648     t += microseconds;
649     *timeval = negative ? -t : t;
650     return 0;
651 }
652
653 int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
654 {
655     const char *p;
656     char tag[128], *q;
657
658     p = info;
659     if (*p == '?')
660         p++;
661     for(;;) {
662         q = tag;
663         while (*p != '\0' && *p != '=' && *p != '&') {
664             if ((q - tag) < sizeof(tag) - 1)
665                 *q++ = *p;
666             p++;
667         }
668         *q = '\0';
669         q = arg;
670         if (*p == '=') {
671             p++;
672             while (*p != '&' && *p != '\0') {
673                 if ((q - arg) < arg_size - 1) {
674                     if (*p == '+')
675                         *q++ = ' ';
676                     else
677                         *q++ = *p;
678                 }
679                 p++;
680             }
681         }
682         *q = '\0';
683         if (!strcmp(tag, tag1))
684             return 1;
685         if (*p != '&')
686             break;
687         p++;
688     }
689     return 0;
690 }
691
692 #ifdef TEST
693
694 static uint32_t randomv = MKTAG('L','A','V','U');
695
696 static uint32_t av_get_random_seed_deterministic(void)
697 {
698     return randomv = randomv * 1664525 + 1013904223;
699 }
700
701 int main(void)
702 {
703     printf("Testing av_parse_video_rate()\n");
704     {
705         int i;
706         static const char *const rates[] = {
707             "-inf",
708             "inf",
709             "nan",
710             "123/0",
711             "-123 / 0",
712             "",
713             "/",
714             " 123  /  321",
715             "foo/foo",
716             "foo/1",
717             "1/foo",
718             "0/0",
719             "/0",
720             "1/",
721             "1",
722             "0",
723             "-123/123",
724             "-foo",
725             "123.23",
726             ".23",
727             "-.23",
728             "-0.234",
729             "-0.0000001",
730             "  21332.2324   ",
731             " -21332.2324   ",
732         };
733
734         for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
735             int ret;
736             AVRational q = { 0, 0 };
737             ret = av_parse_video_rate(&q, rates[i]);
738             printf("'%s' -> %d/%d %s\n",
739                    rates[i], q.num, q.den, ret ? "ERROR" : "OK");
740         }
741     }
742
743     printf("\nTesting av_parse_color()\n");
744     {
745         int i;
746         uint8_t rgba[4];
747         static const char *const color_names[] = {
748             "bikeshed",
749             "RaNdOm",
750             "foo",
751             "red",
752             "Red ",
753             "RED",
754             "Violet",
755             "Yellow",
756             "Red",
757             "0x000000",
758             "0x0000000",
759             "0xff000000",
760             "0x3e34ff",
761             "0x3e34ffaa",
762             "0xffXXee",
763             "0xfoobar",
764             "0xffffeeeeeeee",
765             "#ff0000",
766             "#ffXX00",
767             "ff0000",
768             "ffXX00",
769             "red@foo",
770             "random@10",
771             "0xff0000@1.0",
772             "red@",
773             "red@0xfff",
774             "red@0xf",
775             "red@2",
776             "red@0.1",
777             "red@-1",
778             "red@0.5",
779             "red@1.0",
780             "red@256",
781             "red@10foo",
782             "red@-1.0",
783             "red@-0.0",
784         };
785
786         av_log_set_level(AV_LOG_DEBUG);
787
788         for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
789             if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
790                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
791                        color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
792             else
793                 printf("%s -> error\n", color_names[i]);
794         }
795     }
796
797     printf("\nTesting av_small_strptime()\n");
798     {
799         int i;
800         struct tm tm = { 0 };
801         struct fmt_timespec_entry {
802             const char *fmt, *timespec;
803         } fmt_timespec_entries[] = {
804             { "%Y-%m-%d",                    "2012-12-21" },
805             { "%Y - %m - %d",                "2012-12-21" },
806             { "%Y-%m-%d %H:%M:%S",           "2012-12-21 20:12:21" },
807             { "  %Y - %m - %d %H : %M : %S", "   2012 - 12 -  21   20 : 12 : 21" },
808         };
809
810         av_log_set_level(AV_LOG_DEBUG);
811         for (i = 0;  i < FF_ARRAY_ELEMS(fmt_timespec_entries); i++) {
812             char *p;
813             struct fmt_timespec_entry *e = &fmt_timespec_entries[i];
814             printf("fmt:'%s' spec:'%s' -> ", e->fmt, e->timespec);
815             p = av_small_strptime(e->timespec, e->fmt, &tm);
816             if (p) {
817                 printf("%04d-%02d-%2d %02d:%02d:%02d\n",
818                        1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
819                        tm.tm_hour, tm.tm_min, tm.tm_sec);
820             } else {
821                 printf("error\n");
822             }
823         }
824     }
825
826     printf("\nTesting av_parse_time()\n");
827     {
828         int i;
829         int64_t tv;
830         time_t tvi;
831         struct tm *tm;
832         static char tzstr[] = "TZ=CET-1";
833         static const char * const time_string[] = {
834             "now",
835             "12:35:46",
836             "2000-12-20 0:02:47.5z",
837             "2000-12-20T010247.6",
838         };
839         static const char * const duration_string[] = {
840             "2:34:56.79",
841             "-1:23:45.67",
842             "42.1729",
843             "-1729.42",
844             "12:34",
845         };
846
847         av_log_set_level(AV_LOG_DEBUG);
848         putenv(tzstr);
849         printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
850         for (i = 0;  i < FF_ARRAY_ELEMS(time_string); i++) {
851             printf("%-24s -> ", time_string[i]);
852             if (av_parse_time(&tv, time_string[i], 0)) {
853                 printf("error\n");
854             } else {
855                 tvi = tv / 1000000;
856                 tm = gmtime(&tvi);
857                 printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
858                        tv / 1000000, (int)(tv % 1000000),
859                        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
860                        tm->tm_hour, tm->tm_min, tm->tm_sec);
861             }
862         }
863         for (i = 0;  i < FF_ARRAY_ELEMS(duration_string); i++) {
864             printf("%-24s -> ", duration_string[i]);
865             if (av_parse_time(&tv, duration_string[i], 1)) {
866                 printf("error\n");
867             } else {
868                 printf("%+21"PRIi64"\n", tv);
869             }
870         }
871     }
872
873     return 0;
874 }
875
876 #endif /* TEST */