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