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