FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
parseutils.c
Go to the documentation of this file.
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 "time_internal.h"
33 #include "parseutils.h"
34 
35 #ifdef TEST
36 
37 #define av_get_random_seed av_get_random_seed_deterministic
38 static uint32_t av_get_random_seed_deterministic(void);
39 
40 #define time(t) 1331972053
41 
42 #endif
43 
44 int 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 
65 typedef struct VideoSizeAbbr {
66  const char *abbr;
67  int width, height;
69 
70 typedef struct VideoRateAbbr {
71  const char *abbr;
74 
75 static 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 
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 
138 int 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 
169 int 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 
189 typedef struct ColorEntry {
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 
194 static 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 
337 static 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 
344 int 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),
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 
424 const 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. */
440 static 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 
464 char *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 
532 time_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 
551 int 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;
556  struct tm dt = { 0 }, tmbuf;
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 */
651  struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf);
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 
670 int 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 
711 static uint32_t randomv = MKTAG('L','A','V','U');
712 
713 static uint32_t av_get_random_seed_deterministic(void)
714 {
715  return randomv = randomv * 1664525 + 1013904223;
716 }
717 
718 int 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 
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 
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 
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 */