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