Libav
|
00001 /* 00002 * copyright (c) 2009 Stefano Sabatini 00003 * This file is part of FFmpeg. 00004 * 00005 * FFmpeg is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * FFmpeg is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with FFmpeg; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 00025 #include <strings.h> 00026 #include "libavutil/avutil.h" 00027 #include "libavutil/random_seed.h" 00028 #include "parseutils.h" 00029 00030 #define WHITESPACES " \n\t" 00031 00032 char *av_get_token(const char **buf, const char *term) 00033 { 00034 char *out = av_malloc(strlen(*buf) + 1); 00035 char *ret= out, *end= out; 00036 const char *p = *buf; 00037 p += strspn(p, WHITESPACES); 00038 00039 while(*p && !strspn(p, term)) { 00040 char c = *p++; 00041 if(c == '\\' && *p){ 00042 *out++ = *p++; 00043 end= out; 00044 }else if(c == '\''){ 00045 while(*p && *p != '\'') 00046 *out++ = *p++; 00047 if(*p){ 00048 p++; 00049 end= out; 00050 } 00051 }else{ 00052 *out++ = c; 00053 } 00054 } 00055 00056 do{ 00057 *out-- = 0; 00058 }while(out >= end && strspn(out, WHITESPACES)); 00059 00060 *buf = p; 00061 00062 return ret; 00063 } 00064 00065 typedef struct { 00066 const char *name; 00067 uint8_t rgba_color[4]; 00068 } ColorEntry; 00069 00070 static ColorEntry color_table[] = { 00071 { "AliceBlue", { 0xF0, 0xF8, 0xFF } }, 00072 { "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } }, 00073 { "Aqua", { 0x00, 0xFF, 0xFF } }, 00074 { "Aquamarine", { 0x7F, 0xFF, 0xD4 } }, 00075 { "Azure", { 0xF0, 0xFF, 0xFF } }, 00076 { "Beige", { 0xF5, 0xF5, 0xDC } }, 00077 { "Bisque", { 0xFF, 0xE4, 0xC4 } }, 00078 { "Black", { 0x00, 0x00, 0x00 } }, 00079 { "BlanchedAlmond", { 0xFF, 0xEB, 0xCD } }, 00080 { "Blue", { 0x00, 0x00, 0xFF } }, 00081 { "BlueViolet", { 0x8A, 0x2B, 0xE2 } }, 00082 { "Brown", { 0xA5, 0x2A, 0x2A } }, 00083 { "BurlyWood", { 0xDE, 0xB8, 0x87 } }, 00084 { "CadetBlue", { 0x5F, 0x9E, 0xA0 } }, 00085 { "Chartreuse", { 0x7F, 0xFF, 0x00 } }, 00086 { "Chocolate", { 0xD2, 0x69, 0x1E } }, 00087 { "Coral", { 0xFF, 0x7F, 0x50 } }, 00088 { "CornflowerBlue", { 0x64, 0x95, 0xED } }, 00089 { "Cornsilk", { 0xFF, 0xF8, 0xDC } }, 00090 { "Crimson", { 0xDC, 0x14, 0x3C } }, 00091 { "Cyan", { 0x00, 0xFF, 0xFF } }, 00092 { "DarkBlue", { 0x00, 0x00, 0x8B } }, 00093 { "DarkCyan", { 0x00, 0x8B, 0x8B } }, 00094 { "DarkGoldenRod", { 0xB8, 0x86, 0x0B } }, 00095 { "DarkGray", { 0xA9, 0xA9, 0xA9 } }, 00096 { "DarkGreen", { 0x00, 0x64, 0x00 } }, 00097 { "DarkKhaki", { 0xBD, 0xB7, 0x6B } }, 00098 { "DarkMagenta", { 0x8B, 0x00, 0x8B } }, 00099 { "DarkOliveGreen", { 0x55, 0x6B, 0x2F } }, 00100 { "Darkorange", { 0xFF, 0x8C, 0x00 } }, 00101 { "DarkOrchid", { 0x99, 0x32, 0xCC } }, 00102 { "DarkRed", { 0x8B, 0x00, 0x00 } }, 00103 { "DarkSalmon", { 0xE9, 0x96, 0x7A } }, 00104 { "DarkSeaGreen", { 0x8F, 0xBC, 0x8F } }, 00105 { "DarkSlateBlue", { 0x48, 0x3D, 0x8B } }, 00106 { "DarkSlateGray", { 0x2F, 0x4F, 0x4F } }, 00107 { "DarkTurquoise", { 0x00, 0xCE, 0xD1 } }, 00108 { "DarkViolet", { 0x94, 0x00, 0xD3 } }, 00109 { "DeepPink", { 0xFF, 0x14, 0x93 } }, 00110 { "DeepSkyBlue", { 0x00, 0xBF, 0xFF } }, 00111 { "DimGray", { 0x69, 0x69, 0x69 } }, 00112 { "DodgerBlue", { 0x1E, 0x90, 0xFF } }, 00113 { "FireBrick", { 0xB2, 0x22, 0x22 } }, 00114 { "FloralWhite", { 0xFF, 0xFA, 0xF0 } }, 00115 { "ForestGreen", { 0x22, 0x8B, 0x22 } }, 00116 { "Fuchsia", { 0xFF, 0x00, 0xFF } }, 00117 { "Gainsboro", { 0xDC, 0xDC, 0xDC } }, 00118 { "GhostWhite", { 0xF8, 0xF8, 0xFF } }, 00119 { "Gold", { 0xFF, 0xD7, 0x00 } }, 00120 { "GoldenRod", { 0xDA, 0xA5, 0x20 } }, 00121 { "Gray", { 0x80, 0x80, 0x80 } }, 00122 { "Green", { 0x00, 0x80, 0x00 } }, 00123 { "GreenYellow", { 0xAD, 0xFF, 0x2F } }, 00124 { "HoneyDew", { 0xF0, 0xFF, 0xF0 } }, 00125 { "HotPink", { 0xFF, 0x69, 0xB4 } }, 00126 { "IndianRed", { 0xCD, 0x5C, 0x5C } }, 00127 { "Indigo", { 0x4B, 0x00, 0x82 } }, 00128 { "Ivory", { 0xFF, 0xFF, 0xF0 } }, 00129 { "Khaki", { 0xF0, 0xE6, 0x8C } }, 00130 { "Lavender", { 0xE6, 0xE6, 0xFA } }, 00131 { "LavenderBlush", { 0xFF, 0xF0, 0xF5 } }, 00132 { "LawnGreen", { 0x7C, 0xFC, 0x00 } }, 00133 { "LemonChiffon", { 0xFF, 0xFA, 0xCD } }, 00134 { "LightBlue", { 0xAD, 0xD8, 0xE6 } }, 00135 { "LightCoral", { 0xF0, 0x80, 0x80 } }, 00136 { "LightCyan", { 0xE0, 0xFF, 0xFF } }, 00137 { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } }, 00138 { "LightGrey", { 0xD3, 0xD3, 0xD3 } }, 00139 { "LightGreen", { 0x90, 0xEE, 0x90 } }, 00140 { "LightPink", { 0xFF, 0xB6, 0xC1 } }, 00141 { "LightSalmon", { 0xFF, 0xA0, 0x7A } }, 00142 { "LightSeaGreen", { 0x20, 0xB2, 0xAA } }, 00143 { "LightSkyBlue", { 0x87, 0xCE, 0xFA } }, 00144 { "LightSlateGray", { 0x77, 0x88, 0x99 } }, 00145 { "LightSteelBlue", { 0xB0, 0xC4, 0xDE } }, 00146 { "LightYellow", { 0xFF, 0xFF, 0xE0 } }, 00147 { "Lime", { 0x00, 0xFF, 0x00 } }, 00148 { "LimeGreen", { 0x32, 0xCD, 0x32 } }, 00149 { "Linen", { 0xFA, 0xF0, 0xE6 } }, 00150 { "Magenta", { 0xFF, 0x00, 0xFF } }, 00151 { "Maroon", { 0x80, 0x00, 0x00 } }, 00152 { "MediumAquaMarine", { 0x66, 0xCD, 0xAA } }, 00153 { "MediumBlue", { 0x00, 0x00, 0xCD } }, 00154 { "MediumOrchid", { 0xBA, 0x55, 0xD3 } }, 00155 { "MediumPurple", { 0x93, 0x70, 0xD8 } }, 00156 { "MediumSeaGreen", { 0x3C, 0xB3, 0x71 } }, 00157 { "MediumSlateBlue", { 0x7B, 0x68, 0xEE } }, 00158 { "MediumSpringGreen", { 0x00, 0xFA, 0x9A } }, 00159 { "MediumTurquoise", { 0x48, 0xD1, 0xCC } }, 00160 { "MediumVioletRed", { 0xC7, 0x15, 0x85 } }, 00161 { "MidnightBlue", { 0x19, 0x19, 0x70 } }, 00162 { "MintCream", { 0xF5, 0xFF, 0xFA } }, 00163 { "MistyRose", { 0xFF, 0xE4, 0xE1 } }, 00164 { "Moccasin", { 0xFF, 0xE4, 0xB5 } }, 00165 { "NavajoWhite", { 0xFF, 0xDE, 0xAD } }, 00166 { "Navy", { 0x00, 0x00, 0x80 } }, 00167 { "OldLace", { 0xFD, 0xF5, 0xE6 } }, 00168 { "Olive", { 0x80, 0x80, 0x00 } }, 00169 { "OliveDrab", { 0x6B, 0x8E, 0x23 } }, 00170 { "Orange", { 0xFF, 0xA5, 0x00 } }, 00171 { "OrangeRed", { 0xFF, 0x45, 0x00 } }, 00172 { "Orchid", { 0xDA, 0x70, 0xD6 } }, 00173 { "PaleGoldenRod", { 0xEE, 0xE8, 0xAA } }, 00174 { "PaleGreen", { 0x98, 0xFB, 0x98 } }, 00175 { "PaleTurquoise", { 0xAF, 0xEE, 0xEE } }, 00176 { "PaleVioletRed", { 0xD8, 0x70, 0x93 } }, 00177 { "PapayaWhip", { 0xFF, 0xEF, 0xD5 } }, 00178 { "PeachPuff", { 0xFF, 0xDA, 0xB9 } }, 00179 { "Peru", { 0xCD, 0x85, 0x3F } }, 00180 { "Pink", { 0xFF, 0xC0, 0xCB } }, 00181 { "Plum", { 0xDD, 0xA0, 0xDD } }, 00182 { "PowderBlue", { 0xB0, 0xE0, 0xE6 } }, 00183 { "Purple", { 0x80, 0x00, 0x80 } }, 00184 { "Red", { 0xFF, 0x00, 0x00 } }, 00185 { "RosyBrown", { 0xBC, 0x8F, 0x8F } }, 00186 { "RoyalBlue", { 0x41, 0x69, 0xE1 } }, 00187 { "SaddleBrown", { 0x8B, 0x45, 0x13 } }, 00188 { "Salmon", { 0xFA, 0x80, 0x72 } }, 00189 { "SandyBrown", { 0xF4, 0xA4, 0x60 } }, 00190 { "SeaGreen", { 0x2E, 0x8B, 0x57 } }, 00191 { "SeaShell", { 0xFF, 0xF5, 0xEE } }, 00192 { "Sienna", { 0xA0, 0x52, 0x2D } }, 00193 { "Silver", { 0xC0, 0xC0, 0xC0 } }, 00194 { "SkyBlue", { 0x87, 0xCE, 0xEB } }, 00195 { "SlateBlue", { 0x6A, 0x5A, 0xCD } }, 00196 { "SlateGray", { 0x70, 0x80, 0x90 } }, 00197 { "Snow", { 0xFF, 0xFA, 0xFA } }, 00198 { "SpringGreen", { 0x00, 0xFF, 0x7F } }, 00199 { "SteelBlue", { 0x46, 0x82, 0xB4 } }, 00200 { "Tan", { 0xD2, 0xB4, 0x8C } }, 00201 { "Teal", { 0x00, 0x80, 0x80 } }, 00202 { "Thistle", { 0xD8, 0xBF, 0xD8 } }, 00203 { "Tomato", { 0xFF, 0x63, 0x47 } }, 00204 { "Turquoise", { 0x40, 0xE0, 0xD0 } }, 00205 { "Violet", { 0xEE, 0x82, 0xEE } }, 00206 { "Wheat", { 0xF5, 0xDE, 0xB3 } }, 00207 { "White", { 0xFF, 0xFF, 0xFF } }, 00208 { "WhiteSmoke", { 0xF5, 0xF5, 0xF5 } }, 00209 { "Yellow", { 0xFF, 0xFF, 0x00 } }, 00210 { "YellowGreen", { 0x9A, 0xCD, 0x32 } }, 00211 }; 00212 00213 static int color_table_compare(const void *lhs, const void *rhs) 00214 { 00215 return strcasecmp(lhs, ((const ColorEntry *)rhs)->name); 00216 } 00217 00218 int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx) 00219 { 00220 if (!strcasecmp(color_string, "random") || !strcasecmp(color_string, "bikeshed")) { 00221 int rgba = ff_random_get_seed(); 00222 rgba_color[0] = rgba >> 24; 00223 rgba_color[1] = rgba >> 16; 00224 rgba_color[2] = rgba >> 8; 00225 rgba_color[3] = rgba; 00226 } else 00227 if (!strncmp(color_string, "0x", 2)) { 00228 char *tail; 00229 int len = strlen(color_string); 00230 unsigned int rgba = strtoul(color_string, &tail, 16); 00231 00232 if (*tail || (len != 8 && len != 10)) { 00233 av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string); 00234 return -1; 00235 } 00236 if (len == 10) { 00237 rgba_color[3] = rgba; 00238 rgba >>= 8; 00239 } 00240 rgba_color[0] = rgba >> 16; 00241 rgba_color[1] = rgba >> 8; 00242 rgba_color[2] = rgba; 00243 } else { 00244 const ColorEntry *entry = bsearch(color_string, 00245 color_table, 00246 FF_ARRAY_ELEMS(color_table), 00247 sizeof(ColorEntry), 00248 color_table_compare); 00249 if (!entry) { 00250 av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string); 00251 return -1; 00252 } 00253 memcpy(rgba_color, entry->rgba_color, 4); 00254 } 00255 00256 return 0; 00257 } 00258 00276 static int parse_key_value_pair(void *ctx, const char **buf, 00277 const char *key_val_sep, const char *pairs_sep) 00278 { 00279 char *key = av_get_token(buf, key_val_sep); 00280 char *val; 00281 int ret; 00282 00283 if (*key && strspn(*buf, key_val_sep)) { 00284 (*buf)++; 00285 val = av_get_token(buf, pairs_sep); 00286 } else { 00287 av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key); 00288 av_free(key); 00289 return AVERROR(EINVAL); 00290 } 00291 00292 av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key); 00293 00294 ret = av_set_string3(ctx, key, val, 1, NULL); 00295 if (ret == AVERROR(ENOENT)) 00296 av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key); 00297 00298 av_free(key); 00299 av_free(val); 00300 return ret; 00301 } 00302 00303 int av_set_options_string(void *ctx, const char *opts, 00304 const char *key_val_sep, const char *pairs_sep) 00305 { 00306 int ret, count = 0; 00307 00308 while (*opts) { 00309 if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) 00310 return ret; 00311 count++; 00312 00313 if (*opts) 00314 opts++; 00315 } 00316 00317 return count; 00318 } 00319 00320 #ifdef TEST 00321 00322 #undef printf 00323 00324 typedef struct TestContext 00325 { 00326 const AVClass *class; 00327 int num; 00328 int toggle; 00329 char *string; 00330 int flags; 00331 AVRational rational; 00332 } TestContext; 00333 00334 #define OFFSET(x) offsetof(TestContext, x) 00335 00336 #define TEST_FLAG_COOL 01 00337 #define TEST_FLAG_LAME 02 00338 #define TEST_FLAG_MU 04 00339 00340 static const AVOption test_options[]= { 00341 {"num", "set num", OFFSET(num), FF_OPT_TYPE_INT, 0, 0, 100 }, 00342 {"toggle", "set toggle", OFFSET(toggle), FF_OPT_TYPE_INT, 0, 0, 1 }, 00343 {"rational", "set rational", OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0, 0, 10 }, 00344 {"string", "set string", OFFSET(string), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX }, 00345 {"flags", "set flags", OFFSET(flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, 0, "flags" }, 00346 {"cool", "set cool flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_COOL, INT_MIN, INT_MAX, 0, "flags" }, 00347 {"lame", "set lame flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_LAME, INT_MIN, INT_MAX, 0, "flags" }, 00348 {"mu", "set mu flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_MU, INT_MIN, INT_MAX, 0, "flags" }, 00349 {NULL}, 00350 }; 00351 00352 static const char *test_get_name(void *ctx) 00353 { 00354 return "test"; 00355 } 00356 00357 static const AVClass test_class = { 00358 "TestContext", 00359 test_get_name, 00360 test_options 00361 }; 00362 00363 int main(void) 00364 { 00365 int i; 00366 00367 const char *strings[] = { 00368 "''", 00369 "", 00370 ":", 00371 "\\", 00372 "'", 00373 " '' :", 00374 " '' '' :", 00375 "foo '' :", 00376 "'foo'", 00377 "foo ", 00378 "foo\\", 00379 "foo': blah:blah", 00380 "foo\\: blah:blah", 00381 "foo\'", 00382 "'foo : ' :blahblah", 00383 "\\ :blah", 00384 " foo", 00385 " foo ", 00386 " foo \\ ", 00387 "foo ':blah", 00388 " foo bar : blahblah", 00389 "\\f\\o\\o", 00390 "'foo : \\ \\ ' : blahblah", 00391 "'\\fo\\o:': blahblah", 00392 "\\'fo\\o\\:': foo ' :blahblah" 00393 }; 00394 00395 for (i=0; i < FF_ARRAY_ELEMS(strings); i++) { 00396 const char *p= strings[i]; 00397 printf("|%s|", p); 00398 printf(" -> |%s|", av_get_token(&p, ":")); 00399 printf(" + |%s|\n", p); 00400 } 00401 00402 printf("\nTesting av_parse_color()\n"); 00403 { 00404 uint8_t rgba[4]; 00405 const char *color_names[] = { 00406 "bikeshed", 00407 "RaNdOm", 00408 "foo", 00409 "red", 00410 "Red ", 00411 "RED", 00412 "Violet", 00413 "Yellow", 00414 "Red", 00415 "0x000000", 00416 "0x0000000", 00417 "0xff000000", 00418 "0x3e34ff", 00419 "0x3e34ffaa", 00420 "0xffXXee", 00421 "0xfoobar", 00422 "0xffffeeeeeeee", 00423 }; 00424 00425 av_log_set_level(AV_LOG_DEBUG); 00426 00427 for (int i = 0; i < FF_ARRAY_ELEMS(color_names); i++) { 00428 if (av_parse_color(rgba, color_names[i], NULL) >= 0) 00429 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]); 00430 } 00431 } 00432 00433 printf("\nTesting av_set_options_string()\n"); 00434 { 00435 TestContext test_ctx; 00436 const char *options[] = { 00437 "", 00438 ":", 00439 "=", 00440 "foo=:", 00441 ":=foo", 00442 "=foo", 00443 "foo=", 00444 "foo", 00445 "foo=val", 00446 "foo==val", 00447 "toggle=:", 00448 "string=:", 00449 "toggle=1 : foo", 00450 "toggle=100", 00451 "toggle==1", 00452 "flags=+mu-lame : num=42: toggle=0", 00453 "num=42 : string=blahblah", 00454 "rational=0 : rational=1/2 : rational=1/-1", 00455 "rational=-1/0", 00456 }; 00457 00458 test_ctx.class = &test_class; 00459 av_opt_set_defaults2(&test_ctx, 0, 0); 00460 test_ctx.string = av_strdup("default"); 00461 00462 av_log_set_level(AV_LOG_DEBUG); 00463 00464 for (i=0; i < FF_ARRAY_ELEMS(options); i++) { 00465 av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]); 00466 if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0) 00467 av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]); 00468 printf("\n"); 00469 } 00470 } 00471 00472 return 0; 00473 } 00474 00475 #endif