00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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