Originally committed as revision 18832 to svn://svn.ffmpeg.org/ffmpeg/trunk
Unified · Split
| @@ -256,10 +256,108 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx) · 255 unmodified lines | ||
| 256 | 256 | return 0; |
| 257 | 257 | } |
| 258 | 258 | |
| 259 | +/** | |
| 260 | + * Stores the value in the field in ctx that is named like key. | |
| 261 | + * ctx must be an AVClass context, storing is done using AVOptions. | |
| 262 | + * | |
| 263 | + * @param buf the string to parse, buf will be updated to point at the | |
| 264 | + * separator just after the parsed key/value pair | |
| 265 | + * @param key_val_sep a 0-terminated list of characters used to | |
| 266 | + * separate key from value | |
| 267 | + * @param pairs_sep a 0-terminated list of characters used to separate | |
| 268 | + * two pairs from each other | |
| 269 | + * @return 0 if the key/value pair has been successfully parsed and | |
| 270 | + * set, or a negative value corresponding to an AVERROR code in case | |
| 271 | + * of error: | |
| 272 | + * AVERROR(EINVAL) if the key/value pair cannot be parsed, | |
| 273 | + * the error code issued by av_set_string3() if the key/value pair | |
| 274 | + * cannot be set | |
| 275 | + */ | |
| 276 | +static int parse_key_value_pair(void *ctx, const char **buf, | |
| 277 | + const char *key_val_sep, const char *pairs_sep) | |
| 278 | +{ | |
| 279 | + char *key = av_get_token(buf, key_val_sep); | |
| 280 | + char *val; | |
| 281 | + int ret; | |
| 282 | + | |
| 283 | + if (*key && strspn(*buf, key_val_sep)) { | |
| 284 | + (*buf)++; | |
| 285 | + val = av_get_token(buf, pairs_sep); | |
| 286 | + } else { | |
| 287 | + av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key); | |
| 288 | + av_free(key); | |
| 289 | + return AVERROR(EINVAL); | |
| 290 | + } | |
| 291 | + | |
| 292 | + av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key); | |
| 293 | + | |
| 294 | + ret = av_set_string3(ctx, key, val, 1, NULL); | |
| 295 | + | |
| 296 | + av_free(key); | |
| 297 | + av_free(val); | |
| 298 | + return ret; | |
| 299 | +} | |
| 300 | + | |
| 301 | +int av_set_options_string(void *ctx, const char *opts, | |
| 302 | + const char *key_val_sep, const char *pairs_sep) | |
| 303 | +{ | |
| 304 | + int ret, count = 0; | |
| 305 | + | |
| 306 | + while (*opts) { | |
| 307 | + if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) | |
| 308 | + return ret; | |
| 309 | + count++; | |
| 310 | + | |
| 311 | + if (*opts) | |
| 312 | + opts++; | |
| 313 | + } | |
| 314 | + | |
| 315 | + return count; | |
| 316 | +} | |
| 317 | + | |
| 259 | 318 | #ifdef TEST |
| 260 | 319 | |
| 261 | 320 | #undef printf |
| 262 | 321 | |
| 322 | +typedef struct TestContext | |
| 323 | +{ | |
| 324 | + const AVClass *class; | |
| 325 | + int num; | |
| 326 | + int toggle; | |
| 327 | + char *string; | |
| 328 | + int flags; | |
| 329 | + AVRational rational; | |
| 330 | +} TestContext; | |
| 331 | + | |
| 332 | +#define OFFSET(x) offsetof(TestContext, x) | |
| 333 | + | |
| 334 | +#define TEST_FLAG_COOL 01 | |
| 335 | +#define TEST_FLAG_LAME 02 | |
| 336 | +#define TEST_FLAG_MU 04 | |
| 337 | + | |
| 338 | +static const AVOption test_options[]= { | |
| 339 | +{"num", "set num", OFFSET(num), FF_OPT_TYPE_INT, 0, 0, 100 }, | |
| 340 | +{"toggle", "set toggle", OFFSET(toggle), FF_OPT_TYPE_INT, 0, 0, 1 }, | |
| 341 | +{"rational", "set rational", OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0, 0, 10 }, | |
| 342 | +{"string", "set string", OFFSET(string), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX }, | |
| 343 | +{"flags", "set flags", OFFSET(flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, 0, "flags" }, | |
| 344 | +{"cool", "set cool flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_COOL, INT_MIN, INT_MAX, 0, "flags" }, | |
| 345 | +{"lame", "set lame flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_LAME, INT_MIN, INT_MAX, 0, "flags" }, | |
| 346 | +{"mu", "set mu flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_MU, INT_MIN, INT_MAX, 0, "flags" }, | |
| 347 | +{NULL}, | |
| 348 | +}; | |
| 349 | + | |
| 350 | +static const char *test_get_name(void *ctx) | |
| 351 | +{ | |
| 352 | + return "test"; | |
| 353 | +} | |
| 354 | + | |
| 355 | +static const AVClass test_class = { | |
| 356 | + "TestContext", | |
| 357 | + test_get_name, | |
| 358 | + test_options | |
| 359 | +}; | |
| 360 | + | |
| 263 | 361 | int main(void) |
| 264 | 362 | { |
| 265 | 363 | int i; |
| @@ -329,6 +427,45 @@ int main(void) · 63 unmodified lines | ||
| 329 | 427 | } |
| 330 | 428 | } |
| 331 | 429 | |
| 430 | + printf("\nTesting av_set_options_string()\n"); | |
| 431 | + { | |
| 432 | + TestContext test_ctx; | |
| 433 | + const char *options[] = { | |
| 434 | + "", | |
| 435 | + ":", | |
| 436 | + "=", | |
| 437 | + "foo=:", | |
| 438 | + ":=foo", | |
| 439 | + "=foo", | |
| 440 | + "foo=", | |
| 441 | + "foo", | |
| 442 | + "foo=val", | |
| 443 | + "foo==val", | |
| 444 | + "toggle=:", | |
| 445 | + "string=:", | |
| 446 | + "toggle=1 : foo", | |
| 447 | + "toggle=100", | |
| 448 | + "toggle==1", | |
| 449 | + "flags=+mu-lame : num=42: toggle=0", | |
| 450 | + "num=42 : string=blahblah", | |
| 451 | + "rational=0 : rational=1/2 : rational=1/-1", | |
| 452 | + "rational=-1/0", | |
| 453 | + }; | |
| 454 | + | |
| 455 | + test_ctx.class = &test_class; | |
| 456 | + av_opt_set_defaults2(&test_ctx, 0, 0); | |
| 457 | + test_ctx.string = av_strdup("default"); | |
| 458 | + | |
| 459 | + av_log_set_level(AV_LOG_DEBUG); | |
| 460 | + | |
| 461 | + for (i=0; i < FF_ARRAY_ELEMS(options); i++) { | |
| 462 | + av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]); | |
| 463 | + if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0) | |
| 464 | + av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]); | |
| 465 | + printf("\n"); | |
| 466 | + } | |
| 467 | + } | |
| 468 | + | |
| 332 | 469 | return 0; |
| 333 | 470 | } |
| 334 | 471 | |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | ||
| 25 | 25 | #ifndef AVFILTER_PARSEUTILS_H |
| 26 | 26 | #define AVFILTER_PARSEUTILS_H |
| 27 | 27 | |
| 28 | +#include "libavcodec/opt.h" | |
| 29 | + | |
| 28 | 30 | /** |
| 29 | 31 | * Unescapes the given string until a non escaped terminating char, |
| 30 | 32 | * and returns the token corresponding to the unescaped string. |
| @@ -51,4 +53,23 @@ char *av_get_token(const char **buf, const char *term); · 20 unmodified lines | ||
| 51 | 53 | */ |
| 52 | 54 | int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx); |
| 53 | 55 | |
| 56 | +/** | |
| 57 | + * Parses the key/value pairs list in opts. For each key/value pair | |
| 58 | + * found, stores the value in the field in ctx that is named like the | |
| 59 | + * key. ctx must be an AVClass context, storing is done using | |
| 60 | + * AVOptions. | |
| 61 | + * | |
| 62 | + * @param key_val_sep a 0-terminated list of characters used to | |
| 63 | + * separate key from value | |
| 64 | + * @param pairs_sep a 0-terminated list of characters used to separate | |
| 65 | + * two pairs from each other | |
| 66 | + * @return the number of successfully set key/value pairs, or a negative | |
| 67 | + * value corresponding to an AVERROR code in case of error: | |
| 68 | + * AVERROR(EINVAL) if opts cannot be parsed, | |
| 69 | + * the error code issued by av_set_string3() if a key/value pair | |
| 70 | + * cannot be set | |
| 71 | + */ | |
| 72 | +int av_set_options_string(void *ctx, const char *opts, | |
| 73 | + const char *key_val_sep, const char *pairs_sep); | |
| 74 | + | |
| 54 | 75 | #endif /* AVFILTER_PARSEUTILS_H */ |