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