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