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