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