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