Line data Source code
1 : /*
2 : * AVOptions
3 : * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
4 : *
5 : * This file is part of Libav.
6 : *
7 : * Libav is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU Lesser General Public
9 : * License as published by the Free Software Foundation; either
10 : * version 2.1 of the License, or (at your option) any later version.
11 : *
12 : * Libav is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Lesser General Public License for more details.
16 : *
17 : * 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 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : /**
23 : * @file
24 : * AVOptions
25 : * @author Michael Niedermayer <michaelni@gmx.at>
26 : */
27 :
28 : #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 0 : const AVOption *av_opt_next(void *obj, const AVOption *last)
38 : {
39 0 : AVClass *class = *(AVClass**)obj;
40 0 : if (!last && class->option && class->option[0].name)
41 0 : return class->option;
42 0 : if (last && last[1].name)
43 0 : return ++last;
44 0 : return NULL;
45 : }
46 :
47 0 : static int read_number(const AVOption *o, void *dst, double *num, int *den, int64_t *intnum)
48 : {
49 0 : switch (o->type) {
50 0 : case AV_OPT_TYPE_FLAGS: *intnum = *(unsigned int*)dst;return 0;
51 0 : case AV_OPT_TYPE_INT: *intnum = *(int *)dst;return 0;
52 0 : case AV_OPT_TYPE_INT64: *intnum = *(int64_t *)dst;return 0;
53 0 : case AV_OPT_TYPE_FLOAT: *num = *(float *)dst;return 0;
54 0 : case AV_OPT_TYPE_DOUBLE: *num = *(double *)dst;return 0;
55 0 : case AV_OPT_TYPE_RATIONAL: *intnum = ((AVRational*)dst)->num;
56 0 : *den = ((AVRational*)dst)->den;
57 0 : return 0;
58 : }
59 0 : return AVERROR(EINVAL);
60 : }
61 :
62 0 : static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
63 : {
64 0 : if (o->type != AV_OPT_TYPE_FLAGS &&
65 0 : (o->max * den < num * intnum || o->min * den > num * intnum)) {
66 0 : av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range\n",
67 0 : num*intnum/den, o->name);
68 0 : return AVERROR(ERANGE);
69 : }
70 :
71 0 : switch (o->type) {
72 : case AV_OPT_TYPE_FLAGS:
73 0 : case AV_OPT_TYPE_INT: *(int *)dst= llrint(num/den)*intnum; break;
74 0 : case AV_OPT_TYPE_INT64: *(int64_t *)dst= llrint(num/den)*intnum; break;
75 0 : case AV_OPT_TYPE_FLOAT: *(float *)dst= num*intnum/den; break;
76 0 : case AV_OPT_TYPE_DOUBLE:*(double *)dst= num*intnum/den; break;
77 : case AV_OPT_TYPE_RATIONAL:
78 0 : if ((int)num == num) *(AVRational*)dst= (AVRational){num*intnum, den};
79 0 : else *(AVRational*)dst= av_d2q(num*intnum/den, 1<<24);
80 0 : break;
81 : default:
82 0 : return AVERROR(EINVAL);
83 : }
84 0 : return 0;
85 : }
86 :
87 : static const double const_values[] = {
88 : M_PI,
89 : M_E,
90 : FF_QP2LAMBDA,
91 : 0
92 : };
93 :
94 : static const char * const const_names[] = {
95 : "PI",
96 : "E",
97 : "QP2LAMBDA",
98 : 0
99 : };
100 :
101 0 : static int hexchar2int(char c) {
102 0 : if (c >= '0' && c <= '9') return c - '0';
103 0 : if (c >= 'a' && c <= 'f') return c - 'a' + 10;
104 0 : if (c >= 'A' && c <= 'F') return c - 'A' + 10;
105 0 : return -1;
106 : }
107 :
108 0 : static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst)
109 : {
110 0 : int *lendst = (int *)(dst + 1);
111 : uint8_t *bin, *ptr;
112 0 : int len = strlen(val);
113 :
114 0 : av_freep(dst);
115 0 : *lendst = 0;
116 :
117 0 : if (len & 1)
118 0 : return AVERROR(EINVAL);
119 0 : len /= 2;
120 :
121 0 : ptr = bin = av_malloc(len);
122 0 : if (!ptr)
123 0 : return AVERROR(ENOMEM);
124 0 : while (*val) {
125 0 : int a = hexchar2int(*val++);
126 0 : int b = hexchar2int(*val++);
127 0 : if (a < 0 || b < 0) {
128 0 : av_free(bin);
129 0 : return AVERROR(EINVAL);
130 : }
131 0 : *ptr++ = (a << 4) | b;
132 : }
133 0 : *dst = bin;
134 0 : *lendst = len;
135 :
136 0 : return 0;
137 : }
138 :
139 0 : static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst)
140 : {
141 0 : av_freep(dst);
142 0 : *dst = av_strdup(val);
143 0 : return 0;
144 : }
145 :
146 : #define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \
147 : opt->type == AV_OPT_TYPE_CONST || \
148 : opt->type == AV_OPT_TYPE_FLAGS || \
149 : opt->type == AV_OPT_TYPE_INT) ? \
150 : opt->default_val.i64 : opt->default_val.dbl)
151 :
152 0 : static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
153 : {
154 0 : int ret = 0, notfirst = 0;
155 0 : for (;;) {
156 0 : int i, den = 1;
157 : char buf[256];
158 0 : int cmd = 0;
159 0 : double d, num = 1;
160 0 : int64_t intnum = 1;
161 :
162 0 : i = 0;
163 0 : if (*val == '+' || *val == '-') {
164 0 : if (o->type == AV_OPT_TYPE_FLAGS)
165 0 : cmd = *(val++);
166 0 : else if (!notfirst)
167 0 : buf[i++] = *val;
168 : }
169 :
170 0 : for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
171 0 : buf[i] = val[i];
172 0 : buf[i] = 0;
173 :
174 : {
175 0 : const AVOption *o_named = av_opt_find(target_obj, buf, o->unit, 0, 0);
176 0 : if (o_named && o_named->type == AV_OPT_TYPE_CONST)
177 0 : d = DEFAULT_NUMVAL(o_named);
178 0 : else if (!strcmp(buf, "default")) d = DEFAULT_NUMVAL(o);
179 0 : else if (!strcmp(buf, "max" )) d = o->max;
180 0 : else if (!strcmp(buf, "min" )) d = o->min;
181 0 : else if (!strcmp(buf, "none" )) d = 0;
182 0 : else if (!strcmp(buf, "all" )) d = ~0;
183 : else {
184 0 : int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
185 0 : if (res < 0) {
186 0 : av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val);
187 0 : return res;
188 : }
189 : }
190 : }
191 0 : if (o->type == AV_OPT_TYPE_FLAGS) {
192 0 : read_number(o, dst, NULL, NULL, &intnum);
193 0 : if (cmd == '+') d = intnum | (int64_t)d;
194 0 : else if (cmd == '-') d = intnum &~(int64_t)d;
195 : } else {
196 0 : read_number(o, dst, &num, &den, &intnum);
197 0 : if (cmd == '+') d = notfirst*num*intnum/den + d;
198 0 : else if (cmd == '-') d = notfirst*num*intnum/den - d;
199 : }
200 :
201 0 : if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0)
202 0 : return ret;
203 0 : val += i;
204 0 : if (!*val)
205 0 : return 0;
206 0 : notfirst = 1;
207 : }
208 :
209 : return 0;
210 : }
211 :
212 0 : int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
213 : {
214 : void *dst, *target_obj;
215 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
216 0 : if (!o || !target_obj)
217 0 : return AVERROR_OPTION_NOT_FOUND;
218 0 : if (!val || o->flags & AV_OPT_FLAG_READONLY)
219 0 : return AVERROR(EINVAL);
220 :
221 0 : dst = ((uint8_t*)target_obj) + o->offset;
222 0 : switch (o->type) {
223 0 : case AV_OPT_TYPE_STRING: return set_string(obj, o, val, dst);
224 0 : case AV_OPT_TYPE_BINARY: return set_string_binary(obj, o, val, dst);
225 : case AV_OPT_TYPE_FLAGS:
226 : case AV_OPT_TYPE_INT:
227 : case AV_OPT_TYPE_INT64:
228 : case AV_OPT_TYPE_FLOAT:
229 : case AV_OPT_TYPE_DOUBLE:
230 0 : case AV_OPT_TYPE_RATIONAL: return set_string_number(obj, target_obj, o, val, dst);
231 : }
232 :
233 0 : av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");
234 0 : return AVERROR(EINVAL);
235 : }
236 :
237 : #define OPT_EVAL_NUMBER(name, opttype, vartype)\
238 : int av_opt_eval_ ## name(void *obj, const AVOption *o, const char *val, vartype *name ## _out)\
239 : {\
240 : if (!o || o->type != opttype || o->flags & AV_OPT_FLAG_READONLY)\
241 : return AVERROR(EINVAL);\
242 : return set_string_number(obj, obj, o, val, name ## _out);\
243 : }
244 :
245 0 : OPT_EVAL_NUMBER(flags, AV_OPT_TYPE_FLAGS, int)
246 0 : OPT_EVAL_NUMBER(int, AV_OPT_TYPE_INT, int)
247 0 : OPT_EVAL_NUMBER(int64, AV_OPT_TYPE_INT64, int64_t)
248 0 : OPT_EVAL_NUMBER(float, AV_OPT_TYPE_FLOAT, float)
249 0 : OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE, double)
250 0 : OPT_EVAL_NUMBER(q, AV_OPT_TYPE_RATIONAL, AVRational)
251 :
252 0 : static int set_number(void *obj, const char *name, double num, int den, int64_t intnum,
253 : int search_flags)
254 : {
255 : void *dst, *target_obj;
256 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
257 :
258 0 : if (!o || !target_obj)
259 0 : return AVERROR_OPTION_NOT_FOUND;
260 :
261 0 : if (o->flags & AV_OPT_FLAG_READONLY)
262 0 : return AVERROR(EINVAL);
263 :
264 0 : dst = ((uint8_t*)target_obj) + o->offset;
265 0 : return write_number(obj, o, dst, num, den, intnum);
266 : }
267 :
268 0 : int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
269 : {
270 0 : return set_number(obj, name, 1, 1, val, search_flags);
271 : }
272 :
273 0 : int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
274 : {
275 0 : return set_number(obj, name, val, 1, 1, search_flags);
276 : }
277 :
278 0 : int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags)
279 : {
280 0 : return set_number(obj, name, val.num, val.den, 1, search_flags);
281 : }
282 :
283 0 : int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags)
284 : {
285 : void *target_obj;
286 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
287 : uint8_t *ptr;
288 : uint8_t **dst;
289 : int *lendst;
290 :
291 0 : if (!o || !target_obj)
292 0 : return AVERROR_OPTION_NOT_FOUND;
293 :
294 0 : if (o->type != AV_OPT_TYPE_BINARY || o->flags & AV_OPT_FLAG_READONLY)
295 0 : return AVERROR(EINVAL);
296 :
297 0 : ptr = av_malloc(len);
298 0 : if (!ptr)
299 0 : return AVERROR(ENOMEM);
300 :
301 0 : dst = (uint8_t **)(((uint8_t *)target_obj) + o->offset);
302 0 : lendst = (int *)(dst + 1);
303 :
304 0 : av_free(*dst);
305 0 : *dst = ptr;
306 0 : *lendst = len;
307 0 : memcpy(ptr, val, len);
308 :
309 0 : return 0;
310 : }
311 :
312 0 : int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags)
313 : {
314 : void *target_obj;
315 : AVDictionary **dst;
316 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
317 :
318 0 : if (!o || !target_obj)
319 0 : return AVERROR_OPTION_NOT_FOUND;
320 0 : if (o->flags & AV_OPT_FLAG_READONLY)
321 0 : return AVERROR(EINVAL);
322 :
323 0 : dst = (AVDictionary **)(((uint8_t *)target_obj) + o->offset);
324 0 : av_dict_free(dst);
325 0 : av_dict_copy(dst, val, 0);
326 :
327 0 : return 0;
328 : }
329 :
330 0 : int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
331 : {
332 : void *dst, *target_obj;
333 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
334 : uint8_t *bin, buf[128];
335 : int len, i, ret;
336 :
337 0 : if (!o || !target_obj)
338 0 : return AVERROR_OPTION_NOT_FOUND;
339 :
340 0 : dst = (uint8_t*)target_obj + o->offset;
341 :
342 0 : buf[0] = 0;
343 0 : switch (o->type) {
344 0 : case AV_OPT_TYPE_FLAGS: ret = snprintf(buf, sizeof(buf), "0x%08X", *(int *)dst);break;
345 0 : case AV_OPT_TYPE_INT: ret = snprintf(buf, sizeof(buf), "%d" , *(int *)dst);break;
346 0 : case AV_OPT_TYPE_INT64: ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t*)dst);break;
347 0 : case AV_OPT_TYPE_FLOAT: ret = snprintf(buf, sizeof(buf), "%f" , *(float *)dst);break;
348 0 : case AV_OPT_TYPE_DOUBLE: ret = snprintf(buf, sizeof(buf), "%f" , *(double *)dst);break;
349 0 : case AV_OPT_TYPE_RATIONAL: ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational*)dst)->num, ((AVRational*)dst)->den);break;
350 : case AV_OPT_TYPE_STRING:
351 0 : if (*(uint8_t**)dst)
352 0 : *out_val = av_strdup(*(uint8_t**)dst);
353 : else
354 0 : *out_val = av_strdup("");
355 0 : return 0;
356 : case AV_OPT_TYPE_BINARY:
357 0 : len = *(int*)(((uint8_t *)dst) + sizeof(uint8_t *));
358 0 : if ((uint64_t)len*2 + 1 > INT_MAX)
359 0 : return AVERROR(EINVAL);
360 0 : if (!(*out_val = av_malloc(len*2 + 1)))
361 0 : return AVERROR(ENOMEM);
362 0 : bin = *(uint8_t**)dst;
363 0 : for (i = 0; i < len; i++)
364 0 : snprintf(*out_val + i*2, 3, "%02X", bin[i]);
365 0 : return 0;
366 : default:
367 0 : return AVERROR(EINVAL);
368 : }
369 :
370 0 : if (ret >= sizeof(buf))
371 0 : return AVERROR(EINVAL);
372 0 : *out_val = av_strdup(buf);
373 0 : return 0;
374 : }
375 :
376 0 : static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum,
377 : int search_flags)
378 : {
379 : void *dst, *target_obj;
380 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
381 0 : if (!o || !target_obj)
382 : goto error;
383 :
384 0 : dst = ((uint8_t*)target_obj) + o->offset;
385 :
386 0 : return read_number(o, dst, num, den, intnum);
387 :
388 : error:
389 0 : *den=*intnum=0;
390 0 : return -1;
391 : }
392 :
393 0 : int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val)
394 : {
395 0 : int64_t intnum = 1;
396 0 : double num = 1;
397 0 : int ret, den = 1;
398 :
399 0 : if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
400 0 : return ret;
401 0 : *out_val = num*intnum/den;
402 0 : return 0;
403 : }
404 :
405 0 : int av_opt_get_double(void *obj, const char *name, int search_flags, double *out_val)
406 : {
407 0 : int64_t intnum = 1;
408 0 : double num = 1;
409 0 : int ret, den = 1;
410 :
411 0 : if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
412 0 : return ret;
413 0 : *out_val = num*intnum/den;
414 0 : return 0;
415 : }
416 :
417 0 : int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_val)
418 : {
419 0 : int64_t intnum = 1;
420 0 : double num = 1;
421 0 : int ret, den = 1;
422 :
423 0 : if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
424 0 : return ret;
425 :
426 0 : if (num == 1.0 && (int)intnum == intnum)
427 0 : *out_val = (AVRational){intnum, den};
428 : else
429 0 : *out_val = av_d2q(num*intnum/den, 1<<24);
430 0 : return 0;
431 : }
432 :
433 0 : int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val)
434 : {
435 : void *target_obj;
436 : AVDictionary *src;
437 0 : const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
438 :
439 0 : if (!o || !target_obj)
440 0 : return AVERROR_OPTION_NOT_FOUND;
441 0 : if (o->type != AV_OPT_TYPE_DICT)
442 0 : return AVERROR(EINVAL);
443 :
444 0 : src = *(AVDictionary **)(((uint8_t *)target_obj) + o->offset);
445 0 : av_dict_copy(out_val, src, 0);
446 :
447 0 : return 0;
448 : }
449 :
450 0 : int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name)
451 : {
452 0 : const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0);
453 0 : const AVOption *flag = av_opt_find(obj, flag_name,
454 : field ? field->unit : NULL, 0, 0);
455 : int64_t res;
456 :
457 0 : if (!field || !flag || flag->type != AV_OPT_TYPE_CONST ||
458 0 : av_opt_get_int(obj, field_name, 0, &res) < 0)
459 0 : return 0;
460 0 : return res & flag->default_val.i64;
461 : }
462 :
463 0 : static void opt_list(void *obj, void *av_log_obj, const char *unit,
464 : int req_flags, int rej_flags)
465 : {
466 0 : const AVOption *opt=NULL;
467 :
468 0 : while ((opt = av_opt_next(obj, opt))) {
469 0 : if (!(opt->flags & req_flags) || (opt->flags & rej_flags))
470 0 : continue;
471 :
472 : /* Don't print CONST's on level one.
473 : * Don't print anything but CONST's on level two.
474 : * Only print items from the requested unit.
475 : */
476 0 : if (!unit && opt->type==AV_OPT_TYPE_CONST)
477 0 : continue;
478 0 : else if (unit && opt->type!=AV_OPT_TYPE_CONST)
479 0 : continue;
480 0 : else if (unit && opt->type==AV_OPT_TYPE_CONST && strcmp(unit, opt->unit))
481 0 : continue;
482 0 : else if (unit && opt->type == AV_OPT_TYPE_CONST)
483 0 : av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name);
484 : else
485 0 : av_log(av_log_obj, AV_LOG_INFO, "-%-17s ", opt->name);
486 :
487 0 : switch (opt->type) {
488 : case AV_OPT_TYPE_FLAGS:
489 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<flags>");
490 0 : break;
491 : case AV_OPT_TYPE_INT:
492 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int>");
493 0 : break;
494 : case AV_OPT_TYPE_INT64:
495 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int64>");
496 0 : break;
497 : case AV_OPT_TYPE_DOUBLE:
498 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<double>");
499 0 : break;
500 : case AV_OPT_TYPE_FLOAT:
501 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<float>");
502 0 : break;
503 : case AV_OPT_TYPE_STRING:
504 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<string>");
505 0 : break;
506 : case AV_OPT_TYPE_RATIONAL:
507 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<rational>");
508 0 : break;
509 : case AV_OPT_TYPE_BINARY:
510 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<binary>");
511 0 : break;
512 : case AV_OPT_TYPE_CONST:
513 : default:
514 0 : av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "");
515 0 : break;
516 : }
517 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.');
518 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.');
519 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM ) ? 'V' : '.');
520 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM ) ? 'A' : '.');
521 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.');
522 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_EXPORT) ? 'X' : '.');
523 0 : av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_READONLY) ? 'R' : '.');
524 :
525 0 : if (opt->help)
526 0 : av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help);
527 0 : av_log(av_log_obj, AV_LOG_INFO, "\n");
528 0 : if (opt->unit && opt->type != AV_OPT_TYPE_CONST) {
529 0 : opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags);
530 : }
531 : }
532 0 : }
533 :
534 0 : int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags)
535 : {
536 0 : if (!obj)
537 0 : return -1;
538 :
539 0 : av_log(av_log_obj, AV_LOG_INFO, "%s AVOptions:\n", (*(AVClass**)obj)->class_name);
540 :
541 0 : opt_list(obj, av_log_obj, NULL, req_flags, rej_flags);
542 :
543 0 : return 0;
544 : }
545 :
546 0 : void av_opt_set_defaults(void *s)
547 : {
548 0 : const AVOption *opt = NULL;
549 0 : while ((opt = av_opt_next(s, opt))) {
550 0 : if (opt->flags & AV_OPT_FLAG_READONLY)
551 0 : continue;
552 :
553 0 : switch (opt->type) {
554 : case AV_OPT_TYPE_CONST:
555 : /* Nothing to be done here */
556 0 : break;
557 : case AV_OPT_TYPE_FLAGS:
558 : case AV_OPT_TYPE_INT:
559 : case AV_OPT_TYPE_INT64:
560 0 : av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
561 0 : break;
562 : case AV_OPT_TYPE_DOUBLE:
563 : case AV_OPT_TYPE_FLOAT: {
564 : double val;
565 0 : val = opt->default_val.dbl;
566 0 : av_opt_set_double(s, opt->name, val, 0);
567 : }
568 0 : break;
569 : case AV_OPT_TYPE_RATIONAL: {
570 : AVRational val;
571 0 : val = av_d2q(opt->default_val.dbl, INT_MAX);
572 0 : av_opt_set_q(s, opt->name, val, 0);
573 : }
574 0 : break;
575 : case AV_OPT_TYPE_STRING:
576 0 : av_opt_set(s, opt->name, opt->default_val.str, 0);
577 0 : break;
578 : case AV_OPT_TYPE_BINARY:
579 : case AV_OPT_TYPE_DICT:
580 : /* Cannot set defaults for these types */
581 0 : break;
582 : default:
583 0 : av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", opt->type, opt->name);
584 : }
585 : }
586 0 : }
587 :
588 : /**
589 : * Store the value in the field in ctx that is named like key.
590 : * ctx must be an AVClass context, storing is done using AVOptions.
591 : *
592 : * @param buf the string to parse, buf will be updated to point at the
593 : * separator just after the parsed key/value pair
594 : * @param key_val_sep a 0-terminated list of characters used to
595 : * separate key from value
596 : * @param pairs_sep a 0-terminated list of characters used to separate
597 : * two pairs from each other
598 : * @return 0 if the key/value pair has been successfully parsed and
599 : * set, or a negative value corresponding to an AVERROR code in case
600 : * of error:
601 : * AVERROR(EINVAL) if the key/value pair cannot be parsed,
602 : * the error code issued by av_opt_set() if the key/value pair
603 : * cannot be set
604 : */
605 0 : static int parse_key_value_pair(void *ctx, const char **buf,
606 : const char *key_val_sep, const char *pairs_sep)
607 : {
608 0 : char *key = av_get_token(buf, key_val_sep);
609 : char *val;
610 : int ret;
611 :
612 0 : if (!key)
613 0 : return AVERROR(ENOMEM);
614 :
615 0 : if (*key && strspn(*buf, key_val_sep)) {
616 0 : (*buf)++;
617 0 : val = av_get_token(buf, pairs_sep);
618 0 : if (!val) {
619 0 : av_freep(&key);
620 0 : return AVERROR(ENOMEM);
621 : }
622 : } else {
623 0 : av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
624 0 : av_free(key);
625 0 : return AVERROR(EINVAL);
626 : }
627 :
628 0 : av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
629 :
630 0 : ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN);
631 0 : if (ret == AVERROR_OPTION_NOT_FOUND)
632 0 : av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key);
633 :
634 0 : av_free(key);
635 0 : av_free(val);
636 0 : return ret;
637 : }
638 :
639 0 : int av_set_options_string(void *ctx, const char *opts,
640 : const char *key_val_sep, const char *pairs_sep)
641 : {
642 0 : int ret, count = 0;
643 :
644 0 : if (!opts)
645 0 : return 0;
646 :
647 0 : while (*opts) {
648 0 : if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
649 0 : return ret;
650 0 : count++;
651 :
652 0 : if (*opts)
653 0 : opts++;
654 : }
655 :
656 0 : return count;
657 : }
658 :
659 0 : void av_opt_free(void *obj)
660 : {
661 0 : const AVOption *o = NULL;
662 0 : while ((o = av_opt_next(obj, o))) {
663 0 : switch (o->type) {
664 : case AV_OPT_TYPE_STRING:
665 : case AV_OPT_TYPE_BINARY:
666 0 : av_freep((uint8_t *)obj + o->offset);
667 0 : break;
668 :
669 : case AV_OPT_TYPE_DICT:
670 0 : av_dict_free((AVDictionary **)(((uint8_t *)obj) + o->offset));
671 0 : break;
672 :
673 : default:
674 0 : break;
675 : }
676 : }
677 0 : }
678 :
679 0 : int av_opt_set_dict(void *obj, AVDictionary **options)
680 : {
681 0 : AVDictionaryEntry *t = NULL;
682 0 : AVDictionary *tmp = NULL;
683 0 : int ret = 0;
684 :
685 0 : while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) {
686 0 : ret = av_opt_set(obj, t->key, t->value, 0);
687 0 : if (ret == AVERROR_OPTION_NOT_FOUND)
688 0 : av_dict_set(&tmp, t->key, t->value, 0);
689 0 : else if (ret < 0) {
690 0 : av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value);
691 0 : break;
692 : }
693 0 : ret = 0;
694 : }
695 0 : av_dict_free(options);
696 0 : *options = tmp;
697 0 : return ret;
698 : }
699 :
700 0 : const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
701 : int opt_flags, int search_flags)
702 : {
703 0 : return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL);
704 : }
705 :
706 0 : const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
707 : int opt_flags, int search_flags, void **target_obj)
708 : {
709 0 : const AVClass *c = *(AVClass**)obj;
710 0 : const AVOption *o = NULL;
711 :
712 0 : if (!c)
713 0 : return NULL;
714 :
715 0 : if (search_flags & AV_OPT_SEARCH_CHILDREN) {
716 0 : if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) {
717 0 : const AVClass *child = NULL;
718 0 : while (child = av_opt_child_class_next(c, child))
719 0 : if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL))
720 0 : return o;
721 : } else {
722 0 : void *child = NULL;
723 0 : while (child = av_opt_child_next(obj, child))
724 0 : if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj))
725 0 : return o;
726 : }
727 : }
728 :
729 0 : while (o = av_opt_next(obj, o)) {
730 0 : if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
731 0 : ((!unit && o->type != AV_OPT_TYPE_CONST) ||
732 0 : (unit && o->unit && !strcmp(o->unit, unit)))) {
733 0 : if (target_obj) {
734 0 : if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))
735 0 : *target_obj = obj;
736 : else
737 0 : *target_obj = NULL;
738 : }
739 0 : return o;
740 : }
741 : }
742 0 : return NULL;
743 : }
744 :
745 0 : void *av_opt_child_next(void *obj, void *prev)
746 : {
747 0 : const AVClass *c = *(AVClass**)obj;
748 0 : if (c->child_next)
749 0 : return c->child_next(obj, prev);
750 0 : return NULL;
751 : }
752 :
753 0 : const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev)
754 : {
755 0 : if (parent->child_class_next)
756 0 : return parent->child_class_next(prev);
757 0 : return NULL;
758 : }
759 :
760 : #ifdef TEST
761 :
762 : typedef struct TestContext
763 : {
764 : const AVClass *class;
765 : int num;
766 : int toggle;
767 : char *string;
768 : int flags;
769 : AVRational rational;
770 : } TestContext;
771 :
772 : #define OFFSET(x) offsetof(TestContext, x)
773 :
774 : #define TEST_FLAG_COOL 01
775 : #define TEST_FLAG_LAME 02
776 : #define TEST_FLAG_MU 04
777 :
778 : static const AVOption test_options[]= {
779 : {"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100 },
780 : {"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1 },
781 : {"rational", "set rational", OFFSET(rational), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, 10 },
782 : {"string", "set string", OFFSET(string), AV_OPT_TYPE_STRING, {0}, CHAR_MIN, CHAR_MAX },
783 : {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
784 : {"cool", "set cool flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_COOL}, INT_MIN, INT_MAX, 0, "flags" },
785 : {"lame", "set lame flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_LAME}, INT_MIN, INT_MAX, 0, "flags" },
786 : {"mu", "set mu flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_MU}, INT_MIN, INT_MAX, 0, "flags" },
787 : {NULL},
788 : };
789 :
790 : static const char *test_get_name(void *ctx)
791 : {
792 : return "test";
793 : }
794 :
795 : static const AVClass test_class = {
796 : "TestContext",
797 : test_get_name,
798 : test_options
799 : };
800 :
801 : int main(void)
802 : {
803 : int i;
804 :
805 : printf("\nTesting av_set_options_string()\n");
806 : {
807 : TestContext test_ctx;
808 : const char *options[] = {
809 : "",
810 : ":",
811 : "=",
812 : "foo=:",
813 : ":=foo",
814 : "=foo",
815 : "foo=",
816 : "foo",
817 : "foo=val",
818 : "foo==val",
819 : "toggle=:",
820 : "string=:",
821 : "toggle=1 : foo",
822 : "toggle=100",
823 : "toggle==1",
824 : "flags=+mu-lame : num=42: toggle=0",
825 : "num=42 : string=blahblah",
826 : "rational=0 : rational=1/2 : rational=1/-1",
827 : "rational=-1/0",
828 : };
829 :
830 : test_ctx.class = &test_class;
831 : av_opt_set_defaults(&test_ctx);
832 : test_ctx.string = av_strdup("default");
833 :
834 : av_log_set_level(AV_LOG_DEBUG);
835 :
836 : for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
837 : av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
838 : if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
839 : av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
840 : printf("\n");
841 : }
842 : }
843 :
844 : return 0;
845 : }
846 :
847 : #endif
|