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