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  while((c = *fmt++)) {
469  if (c != '%') {
470  if (av_isspace(c))
471  for (; *p && av_isspace(*p); p++);
472  else if (*p != c)
473  return NULL;
474  else p++;
475  continue;
476  }
477 
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 
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 'T':
519  p = av_small_strptime(p, "%H:%M:%S", dt);
520  if (!p)
521  return NULL;
522  break;
523  case '%':
524  if (*p++ != '%')
525  return NULL;
526  break;
527  default:
528  return NULL;
529  }
530  }
531 
532  return (char*)p;
533 }
534 
535 time_t av_timegm(struct tm *tm)
536 {
537  time_t t;
538 
539  int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
540 
541  if (m < 3) {
542  m += 12;
543  y--;
544  }
545 
546  t = 86400LL *
547  (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
548 
549  t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
550 
551  return t;
552 }
553 
554 int av_parse_time(int64_t *timeval, const char *timestr, int duration)
555 {
556  const char *p, *q;
557  int64_t t;
558  time_t now;
559  struct tm dt = { 0 }, tmbuf;
560  int today = 0, negative = 0, microseconds = 0;
561  int i;
562  static const char * const date_fmt[] = {
563  "%Y-%m-%d",
564  "%Y%m%d",
565  };
566  static const char * const time_fmt[] = {
567  "%H:%M:%S",
568  "%H%M%S",
569  };
570 
571  p = timestr;
572  q = NULL;
573  *timeval = INT64_MIN;
574  if (!duration) {
575  now = time(0);
576 
577  if (!av_strcasecmp(timestr, "now")) {
578  *timeval = (int64_t) now * 1000000;
579  return 0;
580  }
581 
582  /* parse the year-month-day part */
583  for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
584  q = av_small_strptime(p, date_fmt[i], &dt);
585  if (q)
586  break;
587  }
588 
589  /* if the year-month-day part is missing, then take the
590  * current year-month-day time */
591  if (!q) {
592  today = 1;
593  q = p;
594  }
595  p = q;
596 
597  if (*p == 'T' || *p == 't' || *p == ' ')
598  p++;
599 
600  /* parse the hour-minute-second part */
601  for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
602  q = av_small_strptime(p, time_fmt[i], &dt);
603  if (q)
604  break;
605  }
606  } else {
607  /* parse timestr as a duration */
608  if (p[0] == '-') {
609  negative = 1;
610  ++p;
611  }
612  /* parse timestr as HH:MM:SS */
613  q = av_small_strptime(p, "%J:%M:%S", &dt);
614  if (!q) {
615  /* parse timestr as MM:SS */
616  q = av_small_strptime(p, "%M:%S", &dt);
617  dt.tm_hour = 0;
618  }
619  if (!q) {
620  char *o;
621  /* parse timestr as S+ */
622  dt.tm_sec = strtol(p, &o, 10);
623  if (o == p) /* the parsing didn't succeed */
624  return AVERROR(EINVAL);
625  dt.tm_min = 0;
626  dt.tm_hour = 0;
627  q = o;
628  }
629  }
630 
631  /* Now we have all the fields that we can get */
632  if (!q)
633  return AVERROR(EINVAL);
634 
635  /* parse the .m... part */
636  if (*q == '.') {
637  int n;
638  q++;
639  for (n = 100000; n >= 1; n /= 10, q++) {
640  if (!av_isdigit(*q))
641  break;
642  microseconds += n * (*q - '0');
643  }
644  while (av_isdigit(*q))
645  q++;
646  }
647 
648  if (duration) {
649  t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
650  } else {
651  int is_utc = *q == 'Z' || *q == 'z';
652  q += is_utc;
653  if (today) { /* fill in today's date */
654  struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf);
655  dt2.tm_hour = dt.tm_hour;
656  dt2.tm_min = dt.tm_min;
657  dt2.tm_sec = dt.tm_sec;
658  dt = dt2;
659  }
660  t = is_utc ? av_timegm(&dt) : mktime(&dt);
661  }
662 
663  /* Check that we are at the end of the string */
664  if (*q)
665  return AVERROR(EINVAL);
666 
667  t *= 1000000;
668  t += microseconds;
669  *timeval = negative ? -t : t;
670  return 0;
671 }
672 
673 int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
674 {
675  const char *p;
676  char tag[128], *q;
677 
678  p = info;
679  if (*p == '?')
680  p++;
681  for(;;) {
682  q = tag;
683  while (*p != '\0' && *p != '=' && *p != '&') {
684  if ((q - tag) < sizeof(tag) - 1)
685  *q++ = *p;
686  p++;
687  }
688  *q = '\0';
689  q = arg;
690  if (*p == '=') {
691  p++;
692  while (*p != '&' && *p != '\0') {
693  if ((q - arg) < arg_size - 1) {
694  if (*p == '+')
695  *q++ = ' ';
696  else
697  *q++ = *p;
698  }
699  p++;
700  }
701  }
702  *q = '\0';
703  if (!strcmp(tag, tag1))
704  return 1;
705  if (*p != '&')
706  break;
707  p++;
708  }
709  return 0;
710 }
711 
712 #ifdef TEST
713 
714 static uint32_t randomv = MKTAG('L','A','V','U');
715 
716 static uint32_t av_get_random_seed_deterministic(void)
717 {
718  return randomv = randomv * 1664525 + 1013904223;
719 }
720 
721 int main(void)
722 {
723  printf("Testing av_parse_video_rate()\n");
724  {
725  int i;
726  static const char *const rates[] = {
727  "-inf",
728  "inf",
729  "nan",
730  "123/0",
731  "-123 / 0",
732  "",
733  "/",
734  " 123 / 321",
735  "foo/foo",
736  "foo/1",
737  "1/foo",
738  "0/0",
739  "/0",
740  "1/",
741  "1",
742  "0",
743  "-123/123",
744  "-foo",
745  "123.23",
746  ".23",
747  "-.23",
748  "-0.234",
749  "-0.0000001",
750  " 21332.2324 ",
751  " -21332.2324 ",
752  };
753 
754  for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
755  int ret;
756  AVRational q = { 0, 0 };
757  ret = av_parse_video_rate(&q, rates[i]);
758  printf("'%s' -> %d/%d %s\n",
759  rates[i], q.num, q.den, ret ? "ERROR" : "OK");
760  }
761  }
762 
763  printf("\nTesting av_parse_color()\n");
764  {
765  int i;
766  uint8_t rgba[4];
767  static const char *const color_names[] = {
768  "bikeshed",
769  "RaNdOm",
770  "foo",
771  "red",
772  "Red ",
773  "RED",
774  "Violet",
775  "Yellow",
776  "Red",
777  "0x000000",
778  "0x0000000",
779  "0xff000000",
780  "0x3e34ff",
781  "0x3e34ffaa",
782  "0xffXXee",
783  "0xfoobar",
784  "0xffffeeeeeeee",
785  "#ff0000",
786  "#ffXX00",
787  "ff0000",
788  "ffXX00",
789  "red@foo",
790  "random@10",
791  "0xff0000@1.0",
792  "red@",
793  "red@0xfff",
794  "red@0xf",
795  "red@2",
796  "red@0.1",
797  "red@-1",
798  "red@0.5",
799  "red@1.0",
800  "red@256",
801  "red@10foo",
802  "red@-1.0",
803  "red@-0.0",
804  };
805 
807 
808  for (i = 0; i < FF_ARRAY_ELEMS(color_names); i++) {
809  if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
810  printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
811  color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
812  else
813  printf("%s -> error\n", color_names[i]);
814  }
815  }
816 
817  printf("\nTesting av_small_strptime()\n");
818  {
819  int i;
820  struct tm tm = { 0 };
821  struct fmt_timespec_entry {
822  const char *fmt, *timespec;
823  } fmt_timespec_entries[] = {
824  { "%Y-%m-%d", "2012-12-21" },
825  { "%Y - %m - %d", "2012-12-21" },
826  { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" },
827  { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" },
828  };
829 
831  for (i = 0; i < FF_ARRAY_ELEMS(fmt_timespec_entries); i++) {
832  char *p;
833  struct fmt_timespec_entry *e = &fmt_timespec_entries[i];
834  printf("fmt:'%s' spec:'%s' -> ", e->fmt, e->timespec);
835  p = av_small_strptime(e->timespec, e->fmt, &tm);
836  if (p) {
837  printf("%04d-%02d-%2d %02d:%02d:%02d\n",
838  1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
839  tm.tm_hour, tm.tm_min, tm.tm_sec);
840  } else {
841  printf("error\n");
842  }
843  }
844  }
845 
846  printf("\nTesting av_parse_time()\n");
847  {
848  int i;
849  int64_t tv;
850  time_t tvi;
851  struct tm *tm;
852  static char tzstr[] = "TZ=CET-1";
853  static const char * const time_string[] = {
854  "now",
855  "12:35:46",
856  "2000-12-20 0:02:47.5z",
857  "2000-12-20T010247.6",
858  };
859  static const char * const duration_string[] = {
860  "2:34:56.79",
861  "-1:23:45.67",
862  "42.1729",
863  "-1729.42",
864  "12:34",
865  };
866 
868  putenv(tzstr);
869  printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
870  for (i = 0; i < FF_ARRAY_ELEMS(time_string); i++) {
871  printf("%-24s -> ", time_string[i]);
872  if (av_parse_time(&tv, time_string[i], 0)) {
873  printf("error\n");
874  } else {
875  tvi = tv / 1000000;
876  tm = gmtime(&tvi);
877  printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
878  tv / 1000000, (int)(tv % 1000000),
879  tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
880  tm->tm_hour, tm->tm_min, tm->tm_sec);
881  }
882  }
883  for (i = 0; i < FF_ARRAY_ELEMS(duration_string); i++) {
884  printf("%-24s -> ", duration_string[i]);
885  if (av_parse_time(&tv, duration_string[i], 1)) {
886  printf("error\n");
887  } else {
888  printf("%+21"PRIi64"\n", tv);
889  }
890  }
891  }
892 
893  return 0;
894 }
895 
896 #endif /* TEST */