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