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