opt.c 24.5 KB
Newer Older
1 2 3 4
/*
 * AVOptions
 * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19 20 21 22 23 24 25 26 27 28
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * AVOptions
 * @author Michael Niedermayer <michaelni@gmx.at>
 */

#include "avutil.h"
29
#include "avstring.h"
30
#include "common.h"
31
#include "opt.h"
32
#include "eval.h"
33
#include "dict.h"
34
#include "log.h"
35
#include "mathematics.h"
36

37
const AVOption *av_opt_next(void *obj, const AVOption *last)
38
{
39
    AVClass *class = *(AVClass**)obj;
40 41 42 43
    if (!last && class->option && class->option[0].name)
        return class->option;
    if (last && last[1].name)
        return ++last;
44
    return NULL;
45 46
}

47 48 49
static int read_number(const AVOption *o, void *dst, double *num, int *den, int64_t *intnum)
{
    switch (o->type) {
50 51 52 53 54 55
    case AV_OPT_TYPE_FLAGS:     *intnum = *(unsigned int*)dst;return 0;
    case AV_OPT_TYPE_INT:       *intnum = *(int         *)dst;return 0;
    case AV_OPT_TYPE_INT64:     *intnum = *(int64_t     *)dst;return 0;
    case AV_OPT_TYPE_FLOAT:     *num    = *(float       *)dst;return 0;
    case AV_OPT_TYPE_DOUBLE:    *num    = *(double      *)dst;return 0;
    case AV_OPT_TYPE_RATIONAL:  *intnum = ((AVRational*)dst)->num;
56 57 58 59 60 61
                                *den    = ((AVRational*)dst)->den;
                                                        return 0;
    }
    return AVERROR(EINVAL);
}

62
static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
63 64
{
    if (o->max*den < num*intnum || o->min*den > num*intnum) {
65
        av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range\n",
66
               num*intnum/den, o->name);
67 68 69
        return AVERROR(ERANGE);
    }

70
    switch (o->type) {
71 72 73 74 75 76
    case AV_OPT_TYPE_FLAGS:
    case AV_OPT_TYPE_INT:   *(int       *)dst= llrint(num/den)*intnum; break;
    case AV_OPT_TYPE_INT64: *(int64_t   *)dst= llrint(num/den)*intnum; break;
    case AV_OPT_TYPE_FLOAT: *(float     *)dst= num*intnum/den;         break;
    case AV_OPT_TYPE_DOUBLE:*(double    *)dst= num*intnum/den;         break;
    case AV_OPT_TYPE_RATIONAL:
77 78
        if ((int)num == num) *(AVRational*)dst= (AVRational){num*intnum, den};
        else                 *(AVRational*)dst= av_d2q(num*intnum/den, 1<<24);
79 80 81 82 83 84 85
        break;
    default:
        return AVERROR(EINVAL);
    }
    return 0;
}

86
static const double const_values[] = {
87 88 89 90 91 92
    M_PI,
    M_E,
    FF_QP2LAMBDA,
    0
};

93
static const char * const const_names[] = {
94 95 96 97 98 99 100 101 102 103 104 105 106
    "PI",
    "E",
    "QP2LAMBDA",
    0
};

static int hexchar2int(char c) {
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    return -1;
}

107
static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst)
108
{
109 110 111 112 113 114 115 116
    int *lendst = (int *)(dst + 1);
    uint8_t *bin, *ptr;
    int len = strlen(val);

    av_freep(dst);
    *lendst = 0;

    if (len & 1)
117
        return AVERROR(EINVAL);
118
    len /= 2;
119

120 121 122 123 124 125 126
    ptr = bin = av_malloc(len);
    while (*val) {
        int a = hexchar2int(*val++);
        int b = hexchar2int(*val++);
        if (a < 0 || b < 0) {
            av_free(bin);
            return AVERROR(EINVAL);
127
        }
128
        *ptr++ = (a << 4) | b;
129
    }
130 131 132 133 134 135 136 137 138 139 140 141 142
    *dst = bin;
    *lendst = len;

    return 0;
}

static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst)
{
    av_freep(dst);
    *dst = av_strdup(val);
    return 0;
}

143
#define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \
144
                              opt->type == AV_OPT_TYPE_CONST || \
145 146
                              opt->type == AV_OPT_TYPE_FLAGS || \
                              opt->type == AV_OPT_TYPE_INT) ? \
147 148
                             opt->default_val.i64 : opt->default_val.dbl)

149
static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
150 151 152
{
    int ret = 0, notfirst = 0;
    for (;;) {
153
        int i, den = 1;
154 155
        char buf[256];
        int cmd = 0;
156 157
        double d, num = 1;
        int64_t intnum = 1;
158

159 160 161 162 163 164 165
        i = 0;
        if (*val == '+' || *val == '-') {
            if (o->type == AV_OPT_TYPE_FLAGS)
                cmd = *(val++);
            else if (!notfirst)
                buf[i++] = *val;
        }
166

167
        for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
168 169 170 171
            buf[i] = val[i];
        buf[i] = 0;

        {
172
            const AVOption *o_named = av_opt_find(target_obj, buf, o->unit, 0, 0);
173
            if (o_named && o_named->type == AV_OPT_TYPE_CONST)
174 175
                d = DEFAULT_NUMVAL(o_named);
            else if (!strcmp(buf, "default")) d = DEFAULT_NUMVAL(o);
176 177 178 179 180 181 182 183 184
            else if (!strcmp(buf, "max"    )) d = o->max;
            else if (!strcmp(buf, "min"    )) d = o->min;
            else if (!strcmp(buf, "none"   )) d = 0;
            else if (!strcmp(buf, "all"    )) d = ~0;
            else {
                int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
                if (res < 0) {
                    av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val);
                    return res;
185 186 187
                }
            }
        }
188
        if (o->type == AV_OPT_TYPE_FLAGS) {
189 190 191
            read_number(o, dst, NULL, NULL, &intnum);
            if      (cmd == '+') d = intnum | (int64_t)d;
            else if (cmd == '-') d = intnum &~(int64_t)d;
192
        } else {
193 194 195
            read_number(o, dst, &num, &den, &intnum);
            if      (cmd == '+') d = notfirst*num*intnum/den + d;
            else if (cmd == '-') d = notfirst*num*intnum/den - d;
196
        }
197

198
        if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0)
199 200 201 202 203
            return ret;
        val += i;
        if (!*val)
            return 0;
        notfirst = 1;
204 205 206 207 208
    }

    return 0;
}

209 210 211 212 213
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
    void *dst, *target_obj;
    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
    if (!o || !target_obj)
214 215 216 217
        return AVERROR_OPTION_NOT_FOUND;
    if (!val)
        return AVERROR(EINVAL);

218
    dst = ((uint8_t*)target_obj) + o->offset;
219
    switch (o->type) {
220 221 222 223 224 225 226
    case AV_OPT_TYPE_STRING:   return set_string(obj, o, val, dst);
    case AV_OPT_TYPE_BINARY:   return set_string_binary(obj, o, val, dst);
    case AV_OPT_TYPE_FLAGS:
    case AV_OPT_TYPE_INT:
    case AV_OPT_TYPE_INT64:
    case AV_OPT_TYPE_FLOAT:
    case AV_OPT_TYPE_DOUBLE:
227
    case AV_OPT_TYPE_RATIONAL: return set_string_number(obj, target_obj, o, val, dst);
228 229 230 231 232 233
    }

    av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");
    return AVERROR(EINVAL);
}

234 235 236 237 238
#define OPT_EVAL_NUMBER(name, opttype, vartype)\
    int av_opt_eval_ ## name(void *obj, const AVOption *o, const char *val, vartype *name ## _out)\
    {\
        if (!o || o->type != opttype)\
            return AVERROR(EINVAL);\
239
        return set_string_number(obj, obj, o, val, name ## _out);\
240 241
    }

242 243 244 245 246 247
OPT_EVAL_NUMBER(flags,  AV_OPT_TYPE_FLAGS,    int)
OPT_EVAL_NUMBER(int,    AV_OPT_TYPE_INT,      int)
OPT_EVAL_NUMBER(int64,  AV_OPT_TYPE_INT64,    int64_t)
OPT_EVAL_NUMBER(float,  AV_OPT_TYPE_FLOAT,    float)
OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE,   double)
OPT_EVAL_NUMBER(q,      AV_OPT_TYPE_RATIONAL, AVRational)
248

249 250
static int set_number(void *obj, const char *name, double num, int den, int64_t intnum,
                                  int search_flags)
251
{
252 253
    void *dst, *target_obj;
    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
254

255 256
    if (!o || !target_obj)
        return AVERROR_OPTION_NOT_FOUND;
257

258 259
    dst = ((uint8_t*)target_obj) + o->offset;
    return write_number(obj, o, dst, num, den, intnum);
260 261
}

262 263 264 265 266 267 268 269 270 271 272 273 274
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
{
    return set_number(obj, name, 1, 1, val, search_flags);
}

int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
{
    return set_number(obj, name, val, 1, 1, search_flags);
}

int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags)
{
    return set_number(obj, name, val.num, val.den, 1, search_flags);
275 276
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags)
{
    void *target_obj;
    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
    uint8_t *ptr;
    uint8_t **dst;
    int *lendst;

    if (!o || !target_obj)
        return AVERROR_OPTION_NOT_FOUND;

    if (o->type != AV_OPT_TYPE_BINARY)
        return AVERROR(EINVAL);

    ptr = av_malloc(len);
    if (!ptr)
        return AVERROR(ENOMEM);

    dst = (uint8_t **)(((uint8_t *)target_obj) + o->offset);
    lendst = (int *)(dst + 1);

    av_free(*dst);
    *dst = ptr;
    *lendst = len;
    memcpy(ptr, val, len);

    return 0;
}

306
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
307
{
308 309 310 311 312 313 314 315 316 317 318 319
    void *dst, *target_obj;
    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
    uint8_t *bin, buf[128];
    int len, i, ret;

    if (!o || !target_obj)
        return AVERROR_OPTION_NOT_FOUND;

    dst = (uint8_t*)target_obj + o->offset;

    buf[0] = 0;
    switch (o->type) {
320 321 322 323 324 325 326
    case AV_OPT_TYPE_FLAGS:     ret = snprintf(buf, sizeof(buf), "0x%08X",  *(int    *)dst);break;
    case AV_OPT_TYPE_INT:       ret = snprintf(buf, sizeof(buf), "%d" ,     *(int    *)dst);break;
    case AV_OPT_TYPE_INT64:     ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t*)dst);break;
    case AV_OPT_TYPE_FLOAT:     ret = snprintf(buf, sizeof(buf), "%f" ,     *(float  *)dst);break;
    case AV_OPT_TYPE_DOUBLE:    ret = snprintf(buf, sizeof(buf), "%f" ,     *(double *)dst);break;
    case AV_OPT_TYPE_RATIONAL:  ret = snprintf(buf, sizeof(buf), "%d/%d",   ((AVRational*)dst)->num, ((AVRational*)dst)->den);break;
    case AV_OPT_TYPE_STRING:
327 328 329 330 331
        if (*(uint8_t**)dst)
            *out_val = av_strdup(*(uint8_t**)dst);
        else
            *out_val = av_strdup("");
        return 0;
332
    case AV_OPT_TYPE_BINARY:
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        len = *(int*)(((uint8_t *)dst) + sizeof(uint8_t *));
        if ((uint64_t)len*2 + 1 > INT_MAX)
            return AVERROR(EINVAL);
        if (!(*out_val = av_malloc(len*2 + 1)))
            return AVERROR(ENOMEM);
        bin = *(uint8_t**)dst;
        for (i = 0; i < len; i++)
            snprintf(*out_val + i*2, 3, "%02X", bin[i]);
        return 0;
    default:
        return AVERROR(EINVAL);
    }

    if (ret >= sizeof(buf))
        return AVERROR(EINVAL);
    *out_val = av_strdup(buf);
    return 0;
}

352
static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum,
353 354 355 356 357
                      int search_flags)
{
    void *dst, *target_obj;
    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
    if (!o || !target_obj)
358 359
        goto error;

360
    dst = ((uint8_t*)target_obj) + o->offset;
361

362 363
    return read_number(o, dst, num, den, intnum);

364 365 366 367 368
error:
    *den=*intnum=0;
    return -1;
}

369 370 371 372 373 374
int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val)
{
    int64_t intnum = 1;
    double     num = 1;
    int   ret, den = 1;

375
    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
376 377 378 379 380 381 382 383 384 385 386
        return ret;
    *out_val = num*intnum/den;
    return 0;
}

int av_opt_get_double(void *obj, const char *name, int search_flags, double *out_val)
{
    int64_t intnum = 1;
    double     num = 1;
    int   ret, den = 1;

387
    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
388 389 390 391 392 393 394 395 396 397 398
        return ret;
    *out_val = num*intnum/den;
    return 0;
}

int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_val)
{
    int64_t intnum = 1;
    double     num = 1;
    int   ret, den = 1;

399
    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
400 401 402 403 404 405 406 407
        return ret;

    if (num == 1.0 && (int)intnum == intnum)
        *out_val = (AVRational){intnum, den};
    else
        *out_val = av_d2q(num*intnum/den, 1<<24);
    return 0;
}
408

409 410
int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name)
{
411
    const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0);
412 413
    const AVOption *flag  = av_opt_find(obj, flag_name,
                                        field ? field->unit : NULL, 0, 0);
414
    int64_t res;
415

416
    if (!field || !flag || flag->type != AV_OPT_TYPE_CONST ||
417
        av_opt_get_int(obj, field_name, 0, &res) < 0)
418
        return 0;
419
    return res & flag->default_val.i64;
420 421
}

422 423 424 425 426
static void opt_list(void *obj, void *av_log_obj, const char *unit,
                     int req_flags, int rej_flags)
{
    const AVOption *opt=NULL;

427
    while ((opt = av_opt_next(obj, opt))) {
428 429 430 431 432 433 434
        if (!(opt->flags & req_flags) || (opt->flags & rej_flags))
            continue;

        /* Don't print CONST's on level one.
         * Don't print anything but CONST's on level two.
         * Only print items from the requested unit.
         */
435
        if (!unit && opt->type==AV_OPT_TYPE_CONST)
436
            continue;
437
        else if (unit && opt->type!=AV_OPT_TYPE_CONST)
438
            continue;
439
        else if (unit && opt->type==AV_OPT_TYPE_CONST && strcmp(unit, opt->unit))
440
            continue;
441
        else if (unit && opt->type == AV_OPT_TYPE_CONST)
442 443 444 445
            av_log(av_log_obj, AV_LOG_INFO, "   %-15s ", opt->name);
        else
            av_log(av_log_obj, AV_LOG_INFO, "-%-17s ", opt->name);

446
        switch (opt->type) {
447
            case AV_OPT_TYPE_FLAGS:
448
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<flags>");
449
                break;
450
            case AV_OPT_TYPE_INT:
451
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int>");
452
                break;
453
            case AV_OPT_TYPE_INT64:
454
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int64>");
455
                break;
456
            case AV_OPT_TYPE_DOUBLE:
457
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<double>");
458
                break;
459
            case AV_OPT_TYPE_FLOAT:
460
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<float>");
461
                break;
462
            case AV_OPT_TYPE_STRING:
463
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<string>");
464
                break;
465
            case AV_OPT_TYPE_RATIONAL:
466
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<rational>");
467
                break;
468
            case AV_OPT_TYPE_BINARY:
469
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<binary>");
470
                break;
471
            case AV_OPT_TYPE_CONST:
472
            default:
473
                av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "");
474 475 476 477 478 479 480 481
                break;
        }
        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.');
        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.');
        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM   ) ? 'V' : '.');
        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM   ) ? 'A' : '.');
        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.');

482
        if (opt->help)
483 484
            av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help);
        av_log(av_log_obj, AV_LOG_INFO, "\n");
485
        if (opt->unit && opt->type != AV_OPT_TYPE_CONST) {
486 487 488 489 490 491 492
            opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags);
        }
    }
}

int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags)
{
493
    if (!obj)
494 495 496 497 498 499 500 501 502
        return -1;

    av_log(av_log_obj, AV_LOG_INFO, "%s AVOptions:\n", (*(AVClass**)obj)->class_name);

    opt_list(obj, av_log_obj, NULL, req_flags, rej_flags);

    return 0;
}

503 504
void av_opt_set_defaults(void *s)
{
505
    const AVOption *opt = NULL;
506
    while ((opt = av_opt_next(s, opt)) != NULL) {
507
        switch (opt->type) {
508
            case AV_OPT_TYPE_CONST:
509 510
                /* Nothing to be done here */
            break;
511
            case AV_OPT_TYPE_FLAGS:
512
            case AV_OPT_TYPE_INT:
513
            case AV_OPT_TYPE_INT64:
514
                av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
515
            break;
516 517
            case AV_OPT_TYPE_DOUBLE:
            case AV_OPT_TYPE_FLOAT: {
518
                double val;
519
                val = opt->default_val.dbl;
520
                av_opt_set_double(s, opt->name, val, 0);
521 522
            }
            break;
523
            case AV_OPT_TYPE_RATIONAL: {
524
                AVRational val;
525
                val = av_d2q(opt->default_val.dbl, INT_MAX);
526
                av_opt_set_q(s, opt->name, val, 0);
527 528
            }
            break;
529
            case AV_OPT_TYPE_STRING:
530
                av_opt_set(s, opt->name, opt->default_val.str, 0);
531
                break;
532
            case AV_OPT_TYPE_BINARY:
533
                /* Cannot set default for binary */
534 535 536 537 538 539 540
            break;
            default:
                av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", opt->type, opt->name);
        }
    }
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554
/**
 * Store the value in the field in ctx that is named like key.
 * ctx must be an AVClass context, storing is done using AVOptions.
 *
 * @param buf the string to parse, buf will be updated to point at the
 * separator just after the parsed key/value pair
 * @param key_val_sep a 0-terminated list of characters used to
 * separate key from value
 * @param pairs_sep a 0-terminated list of characters used to separate
 * two pairs from each other
 * @return 0 if the key/value pair has been successfully parsed and
 * set, or a negative value corresponding to an AVERROR code in case
 * of error:
 * AVERROR(EINVAL) if the key/value pair cannot be parsed,
555
 * the error code issued by av_opt_set() if the key/value pair
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
 * cannot be set
 */
static int parse_key_value_pair(void *ctx, const char **buf,
                                const char *key_val_sep, const char *pairs_sep)
{
    char *key = av_get_token(buf, key_val_sep);
    char *val;
    int ret;

    if (*key && strspn(*buf, key_val_sep)) {
        (*buf)++;
        val = av_get_token(buf, pairs_sep);
    } else {
        av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
        av_free(key);
        return AVERROR(EINVAL);
    }

    av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);

576
    ret = av_opt_set(ctx, key, val, 0);
577
    if (ret == AVERROR_OPTION_NOT_FOUND)
578 579 580 581 582 583 584 585 586 587 588 589
        av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key);

    av_free(key);
    av_free(val);
    return ret;
}

int av_set_options_string(void *ctx, const char *opts,
                          const char *key_val_sep, const char *pairs_sep)
{
    int ret, count = 0;

590 591 592
    if (!opts)
        return 0;

593 594 595 596 597 598 599 600 601 602 603 604
    while (*opts) {
        if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
            return ret;
        count++;

        if (*opts)
            opts++;
    }

    return count;
}

605 606 607
void av_opt_free(void *obj)
{
    const AVOption *o = NULL;
608
    while ((o = av_opt_next(obj, o)))
609
        if (o->type == AV_OPT_TYPE_STRING || o->type == AV_OPT_TYPE_BINARY)
610 611 612
            av_freep((uint8_t *)obj + o->offset);
}

613 614 615 616 617 618 619
int av_opt_set_dict(void *obj, AVDictionary **options)
{
    AVDictionaryEntry *t = NULL;
    AVDictionary    *tmp = NULL;
    int ret = 0;

    while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) {
620
        ret = av_opt_set(obj, t->key, t->value, 0);
621 622 623 624 625 626 627 628 629 630 631 632 633
        if (ret == AVERROR_OPTION_NOT_FOUND)
            av_dict_set(&tmp, t->key, t->value, 0);
        else if (ret < 0) {
            av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value);
            break;
        }
        ret = 0;
    }
    av_dict_free(options);
    *options = tmp;
    return ret;
}

634 635 636
const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
                            int opt_flags, int search_flags)
{
637 638 639 640 641 642 643
    return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL);
}

const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
                             int opt_flags, int search_flags, void **target_obj)
{
    const AVClass  *c = *(AVClass**)obj;
644 645
    const AVOption *o = NULL;

646 647 648 649 650 651 652 653 654 655 656 657 658
    if (search_flags & AV_OPT_SEARCH_CHILDREN) {
        if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) {
            const AVClass *child = NULL;
            while (child = av_opt_child_class_next(c, child))
                if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL))
                    return o;
        } else {
            void *child = NULL;
            while (child = av_opt_child_next(obj, child))
                if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj))
                    return o;
        }
    }
659

660
    while (o = av_opt_next(obj, o)) {
661
        if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
662
            ((!unit && o->type != AV_OPT_TYPE_CONST) ||
663 664 665 666 667 668 669
             (unit  && o->unit && !strcmp(o->unit, unit)))) {
            if (target_obj) {
                if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))
                    *target_obj = obj;
                else
                    *target_obj = NULL;
            }
670
            return o;
671
        }
672 673 674 675
    }
    return NULL;
}

676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
void *av_opt_child_next(void *obj, void *prev)
{
    const AVClass *c = *(AVClass**)obj;
    if (c->child_next)
        return c->child_next(obj, prev);
    return NULL;
}

const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev)
{
    if (parent->child_class_next)
        return parent->child_class_next(prev);
    return NULL;
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
#ifdef TEST

typedef struct TestContext
{
    const AVClass *class;
    int num;
    int toggle;
    char *string;
    int flags;
    AVRational rational;
} TestContext;

#define OFFSET(x) offsetof(TestContext, x)

#define TEST_FLAG_COOL 01
#define TEST_FLAG_LAME 02
#define TEST_FLAG_MU   04

static const AVOption test_options[]= {
710 711
{"num",      "set num",        OFFSET(num),      AV_OPT_TYPE_INT,      {.i64 = 0},       0,        100                 },
{"toggle",   "set toggle",     OFFSET(toggle),   AV_OPT_TYPE_INT,      {.i64 = 0},       0,        1                   },
712
{"rational", "set rational",   OFFSET(rational), AV_OPT_TYPE_RATIONAL, {.dbl = 0},  0,        10                  },
713
{"string",   "set string",     OFFSET(string),   AV_OPT_TYPE_STRING,   {0},              CHAR_MIN, CHAR_MAX            },
714
{"flags",    "set flags",      OFFSET(flags),    AV_OPT_TYPE_FLAGS,    {.i64 = 0},       0,        INT_MAX, 0, "flags" },
715 716 717
{"cool",     "set cool flag ", 0,                AV_OPT_TYPE_CONST,    {.i64 = TEST_FLAG_COOL}, INT_MIN,  INT_MAX, 0, "flags" },
{"lame",     "set lame flag ", 0,                AV_OPT_TYPE_CONST,    {.i64 = TEST_FLAG_LAME}, INT_MIN,  INT_MAX, 0, "flags" },
{"mu",       "set mu flag ",   0,                AV_OPT_TYPE_CONST,    {.i64 = TEST_FLAG_MU},   INT_MIN,  INT_MAX, 0, "flags" },
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
{NULL},
};

static const char *test_get_name(void *ctx)
{
    return "test";
}

static const AVClass test_class = {
    "TestContext",
    test_get_name,
    test_options
};

int main(void)
{
    int i;

    printf("\nTesting av_set_options_string()\n");
    {
        TestContext test_ctx;
        const char *options[] = {
            "",
            ":",
            "=",
            "foo=:",
            ":=foo",
            "=foo",
            "foo=",
            "foo",
            "foo=val",
            "foo==val",
            "toggle=:",
            "string=:",
            "toggle=1 : foo",
            "toggle=100",
            "toggle==1",
            "flags=+mu-lame : num=42: toggle=0",
            "num=42 : string=blahblah",
            "rational=0 : rational=1/2 : rational=1/-1",
            "rational=-1/0",
        };

        test_ctx.class = &test_class;
762
        av_opt_set_defaults(&test_ctx);
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
        test_ctx.string = av_strdup("default");

        av_log_set_level(AV_LOG_DEBUG);

        for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
            av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
            if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
                av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
            printf("\n");
        }
    }

    return 0;
}

#endif