comparison ffmpeg/libavutil/parseutils.c @ 11:f445c3017523

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