/src/ffmpeg/libavutil/opt.c
Line | Count | Source |
1 | | /* |
2 | | * AVOptions |
3 | | * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg 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 | | * FFmpeg 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 FFmpeg; 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 "avassert.h" |
30 | | #include "avstring.h" |
31 | | #include "channel_layout.h" |
32 | | #include "dict.h" |
33 | | #include "eval.h" |
34 | | #include "log.h" |
35 | | #include "mem.h" |
36 | | #include "parseutils.h" |
37 | | #include "pixdesc.h" |
38 | | #include "mathematics.h" |
39 | | #include "opt.h" |
40 | | #include "samplefmt.h" |
41 | | #include "bprint.h" |
42 | | #include "version.h" |
43 | | |
44 | | #include <float.h> |
45 | | |
46 | 140k | #define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY) |
47 | | |
48 | | const AVOption *av_opt_next(const void *obj, const AVOption *last) |
49 | 193k | { |
50 | 193k | const AVClass *class; |
51 | 193k | if (!obj) |
52 | 0 | return NULL; |
53 | 193k | class = *(const AVClass**)obj; |
54 | 193k | if (!last && class && class->option && class->option[0].name) |
55 | 2.72k | return class->option; |
56 | 190k | if (last && last[1].name) |
57 | 188k | return ++last; |
58 | 2.72k | return NULL; |
59 | 190k | } |
60 | | |
61 | | static const struct { |
62 | | size_t size; |
63 | | const char *name; |
64 | | } opt_type_desc[] = { |
65 | | [AV_OPT_TYPE_FLAGS] = { sizeof(unsigned), "<flags>" }, |
66 | | [AV_OPT_TYPE_INT] = { sizeof(int), "<int>" }, |
67 | | [AV_OPT_TYPE_INT64] = { sizeof(int64_t), "<int64>" }, |
68 | | [AV_OPT_TYPE_UINT] = { sizeof(unsigned), "<unsigned>" }, |
69 | | [AV_OPT_TYPE_UINT64] = { sizeof(uint64_t), "<uint64>" }, |
70 | | [AV_OPT_TYPE_DOUBLE] = { sizeof(double), "<double>" }, |
71 | | [AV_OPT_TYPE_FLOAT] = { sizeof(float), "<float>" }, |
72 | | [AV_OPT_TYPE_STRING] = { sizeof(char *), "<string>" }, |
73 | | [AV_OPT_TYPE_RATIONAL] = { sizeof(AVRational), "<rational>" }, |
74 | | [AV_OPT_TYPE_BINARY] = { sizeof(uint8_t *), "<binary>" }, |
75 | | [AV_OPT_TYPE_DICT] = { sizeof(AVDictionary *), "<dictionary>" }, |
76 | | [AV_OPT_TYPE_IMAGE_SIZE] = { sizeof(int[2]), "<image_size>" }, |
77 | | [AV_OPT_TYPE_VIDEO_RATE] = { sizeof(AVRational), "<video_rate>" }, |
78 | | [AV_OPT_TYPE_PIXEL_FMT] = { sizeof(int), "<pix_fmt>" }, |
79 | | [AV_OPT_TYPE_SAMPLE_FMT] = { sizeof(int), "<sample_fmt>" }, |
80 | | [AV_OPT_TYPE_DURATION] = { sizeof(int64_t), "<duration>" }, |
81 | | [AV_OPT_TYPE_COLOR] = { sizeof(uint8_t[4]), "<color>" }, |
82 | | [AV_OPT_TYPE_CHLAYOUT] = { sizeof(AVChannelLayout),"<channel_layout>" }, |
83 | | [AV_OPT_TYPE_BOOL] = { sizeof(int), "<boolean>" }, |
84 | | }; |
85 | | |
86 | | // option is plain old data |
87 | | static int opt_is_pod(enum AVOptionType type) |
88 | 0 | { |
89 | 0 | switch (type) { |
90 | 0 | case AV_OPT_TYPE_FLAGS: |
91 | 0 | case AV_OPT_TYPE_INT: |
92 | 0 | case AV_OPT_TYPE_INT64: |
93 | 0 | case AV_OPT_TYPE_DOUBLE: |
94 | 0 | case AV_OPT_TYPE_FLOAT: |
95 | 0 | case AV_OPT_TYPE_RATIONAL: |
96 | 0 | case AV_OPT_TYPE_UINT64: |
97 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
98 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
99 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
100 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
101 | 0 | case AV_OPT_TYPE_DURATION: |
102 | 0 | case AV_OPT_TYPE_COLOR: |
103 | 0 | case AV_OPT_TYPE_BOOL: |
104 | 0 | case AV_OPT_TYPE_UINT: |
105 | 0 | return 1; |
106 | 0 | } |
107 | 0 | return 0; |
108 | 0 | } |
109 | | |
110 | | static uint8_t opt_array_sep(const AVOption *o) |
111 | 0 | { |
112 | 0 | const AVOptionArrayDef *d = o->default_val.arr; |
113 | 0 | av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); |
114 | 0 | return (d && d->sep) ? d->sep : ','; |
115 | 0 | } |
116 | | |
117 | | static void *opt_array_pelem(const AVOption *o, void *array, unsigned idx) |
118 | 0 | { |
119 | 0 | av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); |
120 | 0 | return (uint8_t *)array + idx * opt_type_desc[TYPE_BASE(o->type)].size; |
121 | 0 | } |
122 | | |
123 | | static unsigned *opt_array_pcount(const void *parray) |
124 | 0 | { |
125 | 0 | return (unsigned *)((const void * const *)parray + 1); |
126 | 0 | } |
127 | | |
128 | | static void opt_free_elem(enum AVOptionType type, void *ptr) |
129 | 95.4k | { |
130 | 95.4k | switch (TYPE_BASE(type)) { |
131 | 6.82k | case AV_OPT_TYPE_STRING: |
132 | 8.18k | case AV_OPT_TYPE_BINARY: |
133 | 8.18k | av_freep(ptr); |
134 | 8.18k | break; |
135 | | |
136 | 0 | case AV_OPT_TYPE_DICT: |
137 | 0 | av_dict_free((AVDictionary **)ptr); |
138 | 0 | break; |
139 | | |
140 | 0 | case AV_OPT_TYPE_CHLAYOUT: |
141 | 0 | av_channel_layout_uninit((AVChannelLayout *)ptr); |
142 | 0 | break; |
143 | | |
144 | 87.2k | default: |
145 | 87.2k | break; |
146 | 95.4k | } |
147 | 95.4k | } |
148 | | |
149 | | static void opt_free_array(const AVOption *o, void *parray, unsigned *count) |
150 | 0 | { |
151 | 0 | for (unsigned i = 0; i < *count; i++) |
152 | 0 | opt_free_elem(o->type, opt_array_pelem(o, *(void **)parray, i)); |
153 | |
|
154 | 0 | av_freep(parray); |
155 | 0 | *count = 0; |
156 | 0 | } |
157 | | |
158 | | /** |
159 | | * Perform common setup for option-setting functions. |
160 | | * |
161 | | * @param require_type when non-0, require the option to be of this type |
162 | | * @param ptgt target object is written here |
163 | | * @param po the option is written here |
164 | | * @param pdst pointer to option value is written here |
165 | | */ |
166 | | static int opt_set_init(void *obj, const char *name, int search_flags, |
167 | | int require_type, |
168 | | void **ptgt, const AVOption **po, void **pdst) |
169 | 0 | { |
170 | 0 | const AVOption *o; |
171 | 0 | void *tgt; |
172 | |
|
173 | 0 | o = av_opt_find2(obj, name, NULL, 0, search_flags, &tgt); |
174 | 0 | if (!o || !tgt) |
175 | 0 | return AVERROR_OPTION_NOT_FOUND; |
176 | | |
177 | 0 | if (o->flags & AV_OPT_FLAG_READONLY) |
178 | 0 | return AVERROR(EINVAL); |
179 | | |
180 | 0 | if (require_type && (o->type != require_type)) { |
181 | 0 | av_log(obj, AV_LOG_ERROR, |
182 | 0 | "Tried to set option '%s' of type %s from value of type %s, " |
183 | 0 | "this is not supported\n", o->name, opt_type_desc[o->type].name, |
184 | 0 | opt_type_desc[require_type].name); |
185 | 0 | return AVERROR(EINVAL); |
186 | 0 | } |
187 | | |
188 | 0 | if (!(o->flags & AV_OPT_FLAG_RUNTIME_PARAM)) { |
189 | 0 | unsigned *state_flags = NULL; |
190 | 0 | const AVClass *class; |
191 | | |
192 | | // try state flags first from the target (child), then from its parent |
193 | 0 | class = *(const AVClass**)tgt; |
194 | 0 | if ( |
195 | | #if LIBAVUTIL_VERSION_MAJOR < 60 |
196 | | class->version >= AV_VERSION_INT(59, 41, 100) && |
197 | | #endif |
198 | 0 | class->state_flags_offset) |
199 | 0 | state_flags = (unsigned*)((uint8_t*)tgt + class->state_flags_offset); |
200 | |
|
201 | 0 | if (!state_flags && obj != tgt) { |
202 | 0 | class = *(const AVClass**)obj; |
203 | 0 | if ( |
204 | | #if LIBAVUTIL_VERSION_MAJOR < 60 |
205 | | class->version >= AV_VERSION_INT(59, 41, 100) && |
206 | | #endif |
207 | 0 | class->state_flags_offset) |
208 | 0 | state_flags = (unsigned*)((uint8_t*)obj + class->state_flags_offset); |
209 | 0 | } |
210 | |
|
211 | 0 | if (state_flags && (*state_flags & AV_CLASS_STATE_INITIALIZED)) { |
212 | 0 | av_log(obj, AV_LOG_ERROR, "Option '%s' is not a runtime option and " |
213 | 0 | "so cannot be set after the object has been initialized\n", |
214 | 0 | o->name); |
215 | 0 | #if LIBAVUTIL_VERSION_MAJOR >= 60 |
216 | 0 | return AVERROR(EINVAL); |
217 | 0 | #endif |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | 0 | if (o->flags & AV_OPT_FLAG_DEPRECATED) |
222 | 0 | av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); |
223 | |
|
224 | 0 | if (po) |
225 | 0 | *po = o; |
226 | 0 | if (ptgt) |
227 | 0 | *ptgt = tgt; |
228 | 0 | if (pdst) |
229 | 0 | *pdst = ((uint8_t *)tgt) + o->offset; |
230 | |
|
231 | 0 | return 0; |
232 | 0 | } |
233 | | |
234 | | static AVRational double_to_rational(double d) |
235 | 0 | { |
236 | 0 | AVRational r = av_d2q(d, 1 << 24); |
237 | 0 | if ((!r.num || !r.den) && d) |
238 | 0 | r = av_d2q(d, INT_MAX); |
239 | 0 | return r; |
240 | 0 | } |
241 | | |
242 | | static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum) |
243 | 0 | { |
244 | 0 | switch (TYPE_BASE(o->type)) { |
245 | 0 | case AV_OPT_TYPE_FLAGS: |
246 | 0 | *intnum = *(unsigned int*)dst; |
247 | 0 | return 0; |
248 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
249 | 0 | *intnum = *(enum AVPixelFormat *)dst; |
250 | 0 | return 0; |
251 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
252 | 0 | *intnum = *(enum AVSampleFormat *)dst; |
253 | 0 | return 0; |
254 | 0 | case AV_OPT_TYPE_BOOL: |
255 | 0 | case AV_OPT_TYPE_INT: |
256 | 0 | *intnum = *(int *)dst; |
257 | 0 | return 0; |
258 | 0 | case AV_OPT_TYPE_UINT: |
259 | 0 | *intnum = *(unsigned int *)dst; |
260 | 0 | return 0; |
261 | 0 | case AV_OPT_TYPE_DURATION: |
262 | 0 | case AV_OPT_TYPE_INT64: |
263 | 0 | case AV_OPT_TYPE_UINT64: |
264 | 0 | *intnum = *(int64_t *)dst; |
265 | 0 | return 0; |
266 | 0 | case AV_OPT_TYPE_FLOAT: |
267 | 0 | *num = *(float *)dst; |
268 | 0 | return 0; |
269 | 0 | case AV_OPT_TYPE_DOUBLE: |
270 | 0 | *num = *(double *)dst; |
271 | 0 | return 0; |
272 | 0 | case AV_OPT_TYPE_RATIONAL: |
273 | 0 | *intnum = ((AVRational *)dst)->num; |
274 | 0 | *den = ((AVRational *)dst)->den; |
275 | 0 | return 0; |
276 | 0 | case AV_OPT_TYPE_CONST: |
277 | 0 | *intnum = o->default_val.i64; |
278 | 0 | return 0; |
279 | 0 | } |
280 | 0 | return AVERROR(EINVAL); |
281 | 0 | } |
282 | | |
283 | | static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) |
284 | 45.0k | { |
285 | 45.0k | const enum AVOptionType type = TYPE_BASE(o->type); |
286 | | |
287 | 45.0k | if (type != AV_OPT_TYPE_FLAGS && |
288 | 38.1k | (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { |
289 | 0 | num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); |
290 | 0 | av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", |
291 | 0 | num, o->name, o->min, o->max); |
292 | 0 | return AVERROR(ERANGE); |
293 | 0 | } |
294 | 45.0k | if (type == AV_OPT_TYPE_FLAGS) { |
295 | 6.82k | double d = num*intnum/den; |
296 | 6.82k | if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) { |
297 | 0 | av_log(obj, AV_LOG_ERROR, |
298 | 0 | "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n", |
299 | 0 | num*intnum/den, o->name); |
300 | 0 | return AVERROR(ERANGE); |
301 | 0 | } |
302 | 6.82k | } |
303 | | |
304 | 45.0k | switch (type) { |
305 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
306 | 0 | *(enum AVPixelFormat *)dst = llrint(num / den) * intnum; |
307 | 0 | break; |
308 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
309 | 0 | *(enum AVSampleFormat *)dst = llrint(num / den) * intnum; |
310 | 0 | break; |
311 | 5.45k | case AV_OPT_TYPE_BOOL: |
312 | 12.2k | case AV_OPT_TYPE_FLAGS: |
313 | 35.4k | case AV_OPT_TYPE_INT: |
314 | 35.4k | case AV_OPT_TYPE_UINT: |
315 | 35.4k | *(int *)dst = llrint(num / den) * intnum; |
316 | 35.4k | break; |
317 | 1.36k | case AV_OPT_TYPE_DURATION: |
318 | 9.54k | case AV_OPT_TYPE_INT64:{ |
319 | 9.54k | double d = num / den; |
320 | 9.54k | if (intnum == 1 && d == (double)INT64_MAX) { |
321 | 0 | *(int64_t *)dst = INT64_MAX; |
322 | 0 | } else |
323 | 9.54k | *(int64_t *)dst = llrint(d) * intnum; |
324 | 9.54k | break;} |
325 | 0 | case AV_OPT_TYPE_UINT64:{ |
326 | 0 | double d = num / den; |
327 | | // We must special case uint64_t here as llrint() does not support values |
328 | | // outside the int64_t range and there is no portable function which does |
329 | | // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double |
330 | | // while INT64_MAX is not |
331 | 0 | if (intnum == 1 && d == (double)UINT64_MAX) { |
332 | 0 | *(uint64_t *)dst = UINT64_MAX; |
333 | 0 | } else if (d > INT64_MAX + 1ULL) { |
334 | 0 | *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum; |
335 | 0 | } else { |
336 | 0 | *(uint64_t *)dst = llrint(d) * intnum; |
337 | 0 | } |
338 | 0 | break;} |
339 | 0 | case AV_OPT_TYPE_FLOAT: |
340 | 0 | *(float *)dst = num * intnum / den; |
341 | 0 | break; |
342 | 0 | case AV_OPT_TYPE_DOUBLE: |
343 | 0 | *(double *)dst = num * intnum / den; |
344 | 0 | break; |
345 | 0 | case AV_OPT_TYPE_RATIONAL: |
346 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
347 | 0 | if ((int) num == num) |
348 | 0 | *(AVRational *)dst = (AVRational) { num *intnum, den }; |
349 | 0 | else |
350 | 0 | *(AVRational *)dst = double_to_rational(num * intnum / den); |
351 | 0 | break; |
352 | 0 | default: |
353 | 0 | return AVERROR(EINVAL); |
354 | 45.0k | } |
355 | 45.0k | return 0; |
356 | 45.0k | } |
357 | | |
358 | 0 | static int hexchar2int(char c) { |
359 | 0 | if (c >= '0' && c <= '9') |
360 | 0 | return c - '0'; |
361 | 0 | if (c >= 'a' && c <= 'f') |
362 | 0 | return c - 'a' + 10; |
363 | 0 | if (c >= 'A' && c <= 'F') |
364 | 0 | return c - 'A' + 10; |
365 | 0 | return -1; |
366 | 0 | } |
367 | | |
368 | | static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst) |
369 | 1.36k | { |
370 | 1.36k | int *lendst = (int *)(dst + 1); |
371 | 1.36k | uint8_t *bin, *ptr; |
372 | 1.36k | int len; |
373 | | |
374 | 1.36k | av_freep(dst); |
375 | 1.36k | *lendst = 0; |
376 | | |
377 | 1.36k | if (!val || !(len = strlen(val))) |
378 | 1.36k | return 0; |
379 | | |
380 | 0 | if (len & 1) |
381 | 0 | return AVERROR(EINVAL); |
382 | 0 | len /= 2; |
383 | |
|
384 | 0 | ptr = bin = av_malloc(len); |
385 | 0 | if (!ptr) |
386 | 0 | return AVERROR(ENOMEM); |
387 | 0 | while (*val) { |
388 | 0 | int a = hexchar2int(*val++); |
389 | 0 | int b = hexchar2int(*val++); |
390 | 0 | if (a < 0 || b < 0) { |
391 | 0 | av_free(bin); |
392 | 0 | return AVERROR(EINVAL); |
393 | 0 | } |
394 | 0 | *ptr++ = (a << 4) | b; |
395 | 0 | } |
396 | 0 | *dst = bin; |
397 | 0 | *lendst = len; |
398 | |
|
399 | 0 | return 0; |
400 | 0 | } |
401 | | |
402 | | static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) |
403 | 6.82k | { |
404 | 6.82k | av_freep(dst); |
405 | 6.82k | if (!val) |
406 | 5.45k | return 0; |
407 | 1.36k | *dst = av_strdup(val); |
408 | 1.36k | return *dst ? 0 : AVERROR(ENOMEM); |
409 | 6.82k | } |
410 | | |
411 | 0 | #define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \ |
412 | 0 | opt->type == AV_OPT_TYPE_UINT64 || \ |
413 | 0 | opt->type == AV_OPT_TYPE_CONST || \ |
414 | 0 | opt->type == AV_OPT_TYPE_FLAGS || \ |
415 | 0 | opt->type == AV_OPT_TYPE_UINT || \ |
416 | 0 | opt->type == AV_OPT_TYPE_INT) \ |
417 | 0 | ? opt->default_val.i64 \ |
418 | 0 | : opt->default_val.dbl) |
419 | | |
420 | | static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) |
421 | 0 | { |
422 | 0 | const enum AVOptionType type = TYPE_BASE(o->type); |
423 | 0 | int ret = 0; |
424 | |
|
425 | 0 | if (type == AV_OPT_TYPE_RATIONAL || type == AV_OPT_TYPE_VIDEO_RATE) { |
426 | 0 | int num, den; |
427 | 0 | char c; |
428 | 0 | if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) { |
429 | 0 | if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0) |
430 | 0 | return ret; |
431 | 0 | ret = 0; |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | 0 | for (;;) { |
436 | 0 | int i = 0; |
437 | 0 | char buf[256]; |
438 | 0 | int cmd = 0; |
439 | 0 | double d; |
440 | 0 | int64_t intnum = 1; |
441 | |
|
442 | 0 | if (type == AV_OPT_TYPE_FLAGS) { |
443 | 0 | if (*val == '+' || *val == '-') |
444 | 0 | cmd = *(val++); |
445 | 0 | for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++) |
446 | 0 | buf[i] = val[i]; |
447 | 0 | buf[i] = 0; |
448 | 0 | } |
449 | |
|
450 | 0 | { |
451 | 0 | int res; |
452 | 0 | int ci = 0; |
453 | 0 | double const_values[64]; |
454 | 0 | const char * const_names[64]; |
455 | 0 | int search_flags = (o->flags & AV_OPT_FLAG_CHILD_CONSTS) ? AV_OPT_SEARCH_CHILDREN : 0; |
456 | 0 | const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, search_flags); |
457 | 0 | if (o_named && o_named->type == AV_OPT_TYPE_CONST) { |
458 | 0 | d = DEFAULT_NUMVAL(o_named); |
459 | 0 | if (o_named->flags & AV_OPT_FLAG_DEPRECATED) |
460 | 0 | av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", |
461 | 0 | o_named->name, o_named->help); |
462 | 0 | } else { |
463 | 0 | if (o->unit) { |
464 | 0 | for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) { |
465 | 0 | if (o_named->type == AV_OPT_TYPE_CONST && |
466 | 0 | o_named->unit && |
467 | 0 | !strcmp(o_named->unit, o->unit)) { |
468 | 0 | if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) { |
469 | 0 | av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); |
470 | 0 | return AVERROR_PATCHWELCOME; |
471 | 0 | } |
472 | 0 | const_names [ci ] = o_named->name; |
473 | 0 | const_values[ci++] = DEFAULT_NUMVAL(o_named); |
474 | 0 | } |
475 | 0 | } |
476 | 0 | } |
477 | 0 | const_names [ci ] = "default"; |
478 | 0 | const_values[ci++] = DEFAULT_NUMVAL(o); |
479 | 0 | const_names [ci ] = "max"; |
480 | 0 | const_values[ci++] = o->max; |
481 | 0 | const_names [ci ] = "min"; |
482 | 0 | const_values[ci++] = o->min; |
483 | 0 | const_names [ci ] = "none"; |
484 | 0 | const_values[ci++] = 0; |
485 | 0 | const_names [ci ] = "all"; |
486 | 0 | const_values[ci++] = ~0; |
487 | 0 | const_names [ci] = NULL; |
488 | 0 | const_values[ci] = 0; |
489 | |
|
490 | 0 | res = av_expr_parse_and_eval(&d, i ? buf : val, const_names, |
491 | 0 | const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); |
492 | 0 | if (res < 0) { |
493 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\"\n", o->name, val); |
494 | 0 | return res; |
495 | 0 | } |
496 | 0 | } |
497 | 0 | } |
498 | 0 | if (type == AV_OPT_TYPE_FLAGS) { |
499 | 0 | intnum = *(unsigned int*)dst; |
500 | 0 | if (cmd == '+') |
501 | 0 | d = intnum | (int64_t)d; |
502 | 0 | else if (cmd == '-') |
503 | 0 | d = intnum &~(int64_t)d; |
504 | 0 | } |
505 | |
|
506 | 0 | if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0) |
507 | 0 | return ret; |
508 | 0 | val += i; |
509 | 0 | if (!i || !*val) |
510 | 0 | return 0; |
511 | 0 | } |
512 | 0 | } |
513 | | |
514 | | static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst) |
515 | 0 | { |
516 | 0 | int ret; |
517 | |
|
518 | 0 | if (!val || !strcmp(val, "none")) { |
519 | 0 | dst[0] = |
520 | 0 | dst[1] = 0; |
521 | 0 | return 0; |
522 | 0 | } |
523 | 0 | ret = av_parse_video_size(dst, dst + 1, val); |
524 | 0 | if (ret < 0) |
525 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as image size\n", o->name, val); |
526 | 0 | return ret; |
527 | 0 | } |
528 | | |
529 | | static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst) |
530 | 0 | { |
531 | 0 | int ret = av_parse_video_rate(dst, val); |
532 | 0 | if (ret < 0) |
533 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as video rate\n", o->name, val); |
534 | 0 | return ret; |
535 | 0 | } |
536 | | |
537 | | static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst) |
538 | 0 | { |
539 | 0 | int ret; |
540 | |
|
541 | 0 | if (!val) { |
542 | 0 | return 0; |
543 | 0 | } else { |
544 | 0 | ret = av_parse_color(dst, val, -1, obj); |
545 | 0 | if (ret < 0) |
546 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as color\n", o->name, val); |
547 | 0 | return ret; |
548 | 0 | } |
549 | 0 | return 0; |
550 | 0 | } |
551 | | |
552 | | static const char *get_bool_name(int val) |
553 | 0 | { |
554 | 0 | if (val < 0) |
555 | 0 | return "auto"; |
556 | 0 | return val ? "true" : "false"; |
557 | 0 | } |
558 | | |
559 | | static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst) |
560 | 0 | { |
561 | 0 | int n; |
562 | |
|
563 | 0 | if (!val) |
564 | 0 | return 0; |
565 | | |
566 | 0 | if (!strcmp(val, "auto")) { |
567 | 0 | n = -1; |
568 | 0 | } else if (av_match_name(val, "true,y,yes,enable,enabled,on")) { |
569 | 0 | n = 1; |
570 | 0 | } else if (av_match_name(val, "false,n,no,disable,disabled,off")) { |
571 | 0 | n = 0; |
572 | 0 | } else { |
573 | 0 | char *end = NULL; |
574 | 0 | n = strtol(val, &end, 10); |
575 | 0 | if (val + strlen(val) != end) |
576 | 0 | goto fail; |
577 | 0 | } |
578 | | |
579 | 0 | if (n < o->min || n > o->max) |
580 | 0 | goto fail; |
581 | | |
582 | 0 | *dst = n; |
583 | 0 | return 0; |
584 | | |
585 | 0 | fail: |
586 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as boolean\n", o->name, val); |
587 | 0 | return AVERROR(EINVAL); |
588 | 0 | } |
589 | | |
590 | | static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst, |
591 | | int fmt_nb, int ((*get_fmt)(const char *)), const char *desc) |
592 | 0 | { |
593 | 0 | int fmt, min, max; |
594 | |
|
595 | 0 | if (!val || !strcmp(val, "none")) { |
596 | 0 | fmt = -1; |
597 | 0 | } else { |
598 | 0 | fmt = get_fmt(val); |
599 | 0 | if (fmt == -1) { |
600 | 0 | char *tail; |
601 | 0 | fmt = strtol(val, &tail, 0); |
602 | 0 | if (*tail || (unsigned)fmt >= fmt_nb) { |
603 | 0 | av_log(obj, AV_LOG_ERROR, |
604 | 0 | "Unable to parse \"%s\" option value \"%s\" as %s\n", o->name, val, desc); |
605 | 0 | return AVERROR(EINVAL); |
606 | 0 | } |
607 | 0 | } |
608 | 0 | } |
609 | | |
610 | 0 | min = FFMAX(o->min, -1); |
611 | 0 | max = FFMIN(o->max, fmt_nb-1); |
612 | | |
613 | | // hack for compatibility with old ffmpeg |
614 | 0 | if(min == 0 && max == 0) { |
615 | 0 | min = -1; |
616 | 0 | max = fmt_nb-1; |
617 | 0 | } |
618 | |
|
619 | 0 | if (fmt < min || fmt > max) { |
620 | 0 | av_log(obj, AV_LOG_ERROR, |
621 | 0 | "Value %d for parameter '%s' out of %s format range [%d - %d]\n", |
622 | 0 | fmt, o->name, desc, min, max); |
623 | 0 | return AVERROR(ERANGE); |
624 | 0 | } |
625 | | |
626 | 0 | *(int *)dst = fmt; |
627 | 0 | return 0; |
628 | 0 | } |
629 | | |
630 | | static int get_pix_fmt(const char *name) |
631 | 0 | { |
632 | 0 | return av_get_pix_fmt(name); |
633 | 0 | } |
634 | | |
635 | | static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) |
636 | 0 | { |
637 | 0 | return set_string_fmt(obj, o, val, dst, |
638 | 0 | AV_PIX_FMT_NB, get_pix_fmt, "pixel format"); |
639 | 0 | } |
640 | | |
641 | | static int get_sample_fmt(const char *name) |
642 | 0 | { |
643 | 0 | return av_get_sample_fmt(name); |
644 | 0 | } |
645 | | |
646 | | static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) |
647 | 0 | { |
648 | 0 | return set_string_fmt(obj, o, val, dst, |
649 | 0 | AV_SAMPLE_FMT_NB, get_sample_fmt, "sample format"); |
650 | 0 | } |
651 | | |
652 | | static int set_string_dict(void *obj, const AVOption *o, const char *val, uint8_t **dst) |
653 | 0 | { |
654 | 0 | AVDictionary *options = NULL; |
655 | |
|
656 | 0 | if (val) { |
657 | 0 | int ret = av_dict_parse_string(&options, val, "=", ":", 0); |
658 | 0 | if (ret < 0) { |
659 | 0 | av_dict_free(&options); |
660 | 0 | return ret; |
661 | 0 | } |
662 | 0 | } |
663 | | |
664 | 0 | av_dict_free((AVDictionary **)dst); |
665 | 0 | *dst = (uint8_t *)options; |
666 | |
|
667 | 0 | return 0; |
668 | 0 | } |
669 | | |
670 | | static int set_string_channel_layout(void *obj, const AVOption *o, |
671 | | const char *val, void *dst) |
672 | 0 | { |
673 | 0 | AVChannelLayout *channel_layout = dst; |
674 | 0 | av_channel_layout_uninit(channel_layout); |
675 | 0 | if (!val) |
676 | 0 | return 0; |
677 | 0 | return av_channel_layout_from_string(channel_layout, val); |
678 | 0 | } |
679 | | |
680 | | static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, |
681 | | const char *val, void *dst) |
682 | 0 | { |
683 | 0 | const enum AVOptionType type = TYPE_BASE(o->type); |
684 | 0 | int ret; |
685 | |
|
686 | 0 | if (!val && (type != AV_OPT_TYPE_STRING && |
687 | 0 | type != AV_OPT_TYPE_PIXEL_FMT && type != AV_OPT_TYPE_SAMPLE_FMT && |
688 | 0 | type != AV_OPT_TYPE_IMAGE_SIZE && |
689 | 0 | type != AV_OPT_TYPE_DURATION && type != AV_OPT_TYPE_COLOR && |
690 | 0 | type != AV_OPT_TYPE_BOOL)) |
691 | 0 | return AVERROR(EINVAL); |
692 | | |
693 | 0 | switch (type) { |
694 | 0 | case AV_OPT_TYPE_BOOL: |
695 | 0 | return set_string_bool(obj, o, val, dst); |
696 | 0 | case AV_OPT_TYPE_STRING: |
697 | 0 | return set_string(obj, o, val, dst); |
698 | 0 | case AV_OPT_TYPE_BINARY: |
699 | 0 | return set_string_binary(obj, o, val, dst); |
700 | 0 | case AV_OPT_TYPE_FLAGS: |
701 | 0 | case AV_OPT_TYPE_INT: |
702 | 0 | case AV_OPT_TYPE_UINT: |
703 | 0 | case AV_OPT_TYPE_INT64: |
704 | 0 | case AV_OPT_TYPE_UINT64: |
705 | 0 | case AV_OPT_TYPE_FLOAT: |
706 | 0 | case AV_OPT_TYPE_DOUBLE: |
707 | 0 | case AV_OPT_TYPE_RATIONAL: |
708 | 0 | return set_string_number(obj, target_obj, o, val, dst); |
709 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
710 | 0 | return set_string_image_size(obj, o, val, dst); |
711 | 0 | case AV_OPT_TYPE_VIDEO_RATE: { |
712 | 0 | AVRational tmp; |
713 | 0 | ret = set_string_video_rate(obj, o, val, &tmp); |
714 | 0 | if (ret < 0) |
715 | 0 | return ret; |
716 | 0 | return write_number(obj, o, dst, 1, tmp.den, tmp.num); |
717 | 0 | } |
718 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
719 | 0 | return set_string_pixel_fmt(obj, o, val, dst); |
720 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
721 | 0 | return set_string_sample_fmt(obj, o, val, dst); |
722 | 0 | case AV_OPT_TYPE_DURATION: |
723 | 0 | { |
724 | 0 | int64_t usecs = 0; |
725 | 0 | if (val) { |
726 | 0 | if ((ret = av_parse_time(&usecs, val, 1)) < 0) { |
727 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as duration\n", o->name, val); |
728 | 0 | return ret; |
729 | 0 | } |
730 | 0 | } |
731 | 0 | if (usecs < o->min || usecs > o->max) { |
732 | 0 | av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", |
733 | 0 | usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); |
734 | 0 | return AVERROR(ERANGE); |
735 | 0 | } |
736 | 0 | *(int64_t *)dst = usecs; |
737 | 0 | return 0; |
738 | 0 | } |
739 | 0 | case AV_OPT_TYPE_COLOR: |
740 | 0 | return set_string_color(obj, o, val, dst); |
741 | 0 | case AV_OPT_TYPE_CHLAYOUT: |
742 | 0 | ret = set_string_channel_layout(obj, o, val, dst); |
743 | 0 | if (ret < 0) { |
744 | 0 | av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as channel layout\n", o->name, val); |
745 | 0 | ret = AVERROR(EINVAL); |
746 | 0 | } |
747 | 0 | return ret; |
748 | 0 | case AV_OPT_TYPE_DICT: |
749 | 0 | return set_string_dict(obj, o, val, dst); |
750 | 0 | } |
751 | | |
752 | 0 | av_log(obj, AV_LOG_ERROR, "Invalid option type.\n"); |
753 | 0 | return AVERROR(EINVAL); |
754 | 0 | } |
755 | | |
756 | | static int opt_set_array(void *obj, void *target_obj, const AVOption *o, |
757 | | const char *val, void *dst) |
758 | 0 | { |
759 | 0 | const AVOptionArrayDef *arr = o->default_val.arr; |
760 | 0 | const size_t elem_size = opt_type_desc[TYPE_BASE(o->type)].size; |
761 | 0 | const uint8_t sep = opt_array_sep(o); |
762 | 0 | uint8_t *str = NULL; |
763 | |
|
764 | 0 | void *elems = NULL; |
765 | 0 | unsigned nb_elems = 0; |
766 | 0 | int ret; |
767 | |
|
768 | 0 | if (val && *val) { |
769 | 0 | str = av_malloc(strlen(val) + 1); |
770 | 0 | if (!str) |
771 | 0 | return AVERROR(ENOMEM); |
772 | 0 | } |
773 | | |
774 | | // split and unescape the string |
775 | 0 | while (val && *val) { |
776 | 0 | uint8_t *p = str; |
777 | 0 | void *tmp; |
778 | |
|
779 | 0 | if (arr && arr->size_max && nb_elems >= arr->size_max) { |
780 | 0 | av_log(obj, AV_LOG_ERROR, |
781 | 0 | "Cannot assign more than %u elements to array option %s\n", |
782 | 0 | arr->size_max, o->name); |
783 | 0 | ret = AVERROR(EINVAL); |
784 | 0 | goto fail; |
785 | 0 | } |
786 | | |
787 | 0 | for (; *val; val++, p++) { |
788 | 0 | if (*val == '\\' && val[1]) |
789 | 0 | val++; |
790 | 0 | else if (*val == sep) { |
791 | 0 | val++; |
792 | 0 | break; |
793 | 0 | } |
794 | 0 | *p = *val; |
795 | 0 | } |
796 | 0 | *p = 0; |
797 | |
|
798 | 0 | tmp = av_realloc_array(elems, nb_elems + 1, elem_size); |
799 | 0 | if (!tmp) { |
800 | 0 | ret = AVERROR(ENOMEM); |
801 | 0 | goto fail; |
802 | 0 | } |
803 | 0 | elems = tmp; |
804 | |
|
805 | 0 | tmp = opt_array_pelem(o, elems, nb_elems); |
806 | 0 | memset(tmp, 0, elem_size); |
807 | |
|
808 | 0 | ret = opt_set_elem(obj, target_obj, o, str, tmp); |
809 | 0 | if (ret < 0) |
810 | 0 | goto fail; |
811 | 0 | nb_elems++; |
812 | 0 | } |
813 | 0 | av_freep(&str); |
814 | |
|
815 | 0 | opt_free_array(o, dst, opt_array_pcount(dst)); |
816 | |
|
817 | 0 | if (arr && nb_elems < arr->size_min) { |
818 | 0 | av_log(obj, AV_LOG_ERROR, |
819 | 0 | "Cannot assign fewer than %u elements to array option %s\n", |
820 | 0 | arr->size_min, o->name); |
821 | 0 | ret = AVERROR(EINVAL); |
822 | 0 | goto fail; |
823 | 0 | } |
824 | | |
825 | 0 | *((void **)dst) = elems; |
826 | 0 | *opt_array_pcount(dst) = nb_elems; |
827 | |
|
828 | 0 | return 0; |
829 | 0 | fail: |
830 | 0 | av_freep(&str); |
831 | 0 | opt_free_array(o, &elems, &nb_elems); |
832 | 0 | return ret; |
833 | 0 | } |
834 | | |
835 | | int av_opt_set(void *obj, const char *name, const char *val, int search_flags) |
836 | 0 | { |
837 | 0 | void *dst, *target_obj; |
838 | 0 | const AVOption *o; |
839 | 0 | int ret; |
840 | |
|
841 | 0 | ret = opt_set_init(obj, name, search_flags, 0, &target_obj, &o, &dst); |
842 | 0 | if (ret < 0) |
843 | 0 | return ret; |
844 | | |
845 | 0 | return ((o->type & AV_OPT_TYPE_FLAG_ARRAY) ? |
846 | 0 | opt_set_array : opt_set_elem)(obj, target_obj, o, val, dst); |
847 | 0 | } |
848 | | |
849 | | #define OPT_EVAL_NUMBER(name, opttype, vartype) \ |
850 | | int av_opt_eval_ ## name(void *obj, const AVOption *o, \ |
851 | 0 | const char *val, vartype *name ## _out) \ |
852 | 0 | { \ |
853 | 0 | if (!o || o->type != opttype || o->flags & AV_OPT_FLAG_READONLY) \ |
854 | 0 | return AVERROR(EINVAL); \ |
855 | 0 | return set_string_number(obj, obj, o, val, name ## _out); \ |
856 | 0 | } Unexecuted instantiation: av_opt_eval_flags Unexecuted instantiation: av_opt_eval_int Unexecuted instantiation: av_opt_eval_uint Unexecuted instantiation: av_opt_eval_int64 Unexecuted instantiation: av_opt_eval_float Unexecuted instantiation: av_opt_eval_double Unexecuted instantiation: av_opt_eval_q |
857 | | |
858 | | OPT_EVAL_NUMBER(flags, AV_OPT_TYPE_FLAGS, int) |
859 | | OPT_EVAL_NUMBER(int, AV_OPT_TYPE_INT, int) |
860 | | OPT_EVAL_NUMBER(uint, AV_OPT_TYPE_UINT, unsigned) |
861 | | OPT_EVAL_NUMBER(int64, AV_OPT_TYPE_INT64, int64_t) |
862 | | OPT_EVAL_NUMBER(float, AV_OPT_TYPE_FLOAT, float) |
863 | | OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE, double) |
864 | | OPT_EVAL_NUMBER(q, AV_OPT_TYPE_RATIONAL, AVRational) |
865 | | |
866 | | static int set_number(void *obj, const char *name, double num, int den, int64_t intnum, |
867 | | int search_flags, int require_type) |
868 | 0 | { |
869 | 0 | void *dst; |
870 | 0 | const AVOption *o; |
871 | 0 | int ret; |
872 | |
|
873 | 0 | ret = opt_set_init(obj, name, search_flags, require_type, NULL, &o, &dst); |
874 | 0 | if (ret < 0) |
875 | 0 | return ret; |
876 | | |
877 | 0 | return write_number(obj, o, dst, num, den, intnum); |
878 | 0 | } |
879 | | |
880 | | int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags) |
881 | 0 | { |
882 | 0 | return set_number(obj, name, 1, 1, val, search_flags, 0); |
883 | 0 | } |
884 | | |
885 | | int av_opt_set_double(void *obj, const char *name, double val, int search_flags) |
886 | 0 | { |
887 | 0 | return set_number(obj, name, val, 1, 1, search_flags, 0); |
888 | 0 | } |
889 | | |
890 | | int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags) |
891 | 0 | { |
892 | 0 | return set_number(obj, name, val.num, val.den, 1, search_flags, 0); |
893 | 0 | } |
894 | | |
895 | | int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags) |
896 | 0 | { |
897 | 0 | uint8_t *ptr; |
898 | 0 | uint8_t **dst; |
899 | 0 | int *lendst; |
900 | 0 | int ret; |
901 | |
|
902 | 0 | ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_BINARY, |
903 | 0 | NULL, NULL, (void**)&dst); |
904 | 0 | if (ret < 0) |
905 | 0 | return ret; |
906 | | |
907 | 0 | ptr = len ? av_malloc(len) : NULL; |
908 | 0 | if (len && !ptr) |
909 | 0 | return AVERROR(ENOMEM); |
910 | | |
911 | 0 | lendst = (int *)(dst + 1); |
912 | |
|
913 | 0 | av_free(*dst); |
914 | 0 | *dst = ptr; |
915 | 0 | *lendst = len; |
916 | 0 | if (len) |
917 | 0 | memcpy(ptr, val, len); |
918 | |
|
919 | 0 | return 0; |
920 | 0 | } |
921 | | |
922 | | int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags) |
923 | 0 | { |
924 | 0 | const AVOption *o; |
925 | 0 | int *dst; |
926 | 0 | int ret; |
927 | |
|
928 | 0 | ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_IMAGE_SIZE, |
929 | 0 | NULL, &o, (void**)&dst); |
930 | 0 | if (ret < 0) |
931 | 0 | return ret; |
932 | | |
933 | 0 | if (w<0 || h<0) { |
934 | 0 | av_log(obj, AV_LOG_ERROR, |
935 | 0 | "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name); |
936 | 0 | return AVERROR(EINVAL); |
937 | 0 | } |
938 | | |
939 | 0 | dst[0] = w; |
940 | 0 | dst[1] = h; |
941 | |
|
942 | 0 | return 0; |
943 | 0 | } |
944 | | |
945 | | int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags) |
946 | 0 | { |
947 | 0 | return set_number(obj, name, val.num, val.den, 1, search_flags, AV_OPT_TYPE_VIDEO_RATE); |
948 | 0 | } |
949 | | |
950 | | static int set_format(void *obj, const char *name, int fmt, int search_flags, |
951 | | enum AVOptionType type, const char *desc, int nb_fmts) |
952 | 0 | { |
953 | 0 | const AVOption *o; |
954 | 0 | int *dst; |
955 | 0 | int min, max, ret; |
956 | |
|
957 | 0 | ret = opt_set_init(obj, name, search_flags, type, NULL, &o, (void**)&dst); |
958 | 0 | if (ret < 0) |
959 | 0 | return ret; |
960 | | |
961 | 0 | min = FFMAX(o->min, -1); |
962 | 0 | max = FFMIN(o->max, nb_fmts-1); |
963 | |
|
964 | 0 | if (fmt < min || fmt > max) { |
965 | 0 | av_log(obj, AV_LOG_ERROR, |
966 | 0 | "Value %d for parameter '%s' out of %s format range [%d - %d]\n", |
967 | 0 | fmt, name, desc, min, max); |
968 | 0 | return AVERROR(ERANGE); |
969 | 0 | } |
970 | 0 | *dst = fmt; |
971 | 0 | return 0; |
972 | 0 | } |
973 | | |
974 | | int av_opt_set_pixel_fmt(void *obj, const char *name, enum AVPixelFormat fmt, int search_flags) |
975 | 0 | { |
976 | 0 | return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_PIXEL_FMT, "pixel", AV_PIX_FMT_NB); |
977 | 0 | } |
978 | | |
979 | | int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags) |
980 | 0 | { |
981 | 0 | return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB); |
982 | 0 | } |
983 | | |
984 | | int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, |
985 | | int search_flags) |
986 | 0 | { |
987 | 0 | AVDictionary **dst; |
988 | 0 | int ret; |
989 | |
|
990 | 0 | ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_DICT, NULL, NULL, |
991 | 0 | (void**)&dst); |
992 | 0 | if (ret < 0) |
993 | 0 | return ret; |
994 | | |
995 | 0 | av_dict_free(dst); |
996 | |
|
997 | 0 | return av_dict_copy(dst, val, 0); |
998 | 0 | } |
999 | | |
1000 | | int av_opt_set_chlayout(void *obj, const char *name, |
1001 | | const AVChannelLayout *channel_layout, |
1002 | | int search_flags) |
1003 | 0 | { |
1004 | 0 | AVChannelLayout *dst; |
1005 | 0 | int ret; |
1006 | |
|
1007 | 0 | ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_CHLAYOUT, NULL, NULL, |
1008 | 0 | (void**)&dst); |
1009 | 0 | if (ret < 0) |
1010 | 0 | return ret; |
1011 | | |
1012 | 0 | return av_channel_layout_copy(dst, channel_layout); |
1013 | 0 | } |
1014 | | |
1015 | | static void format_duration(char *buf, size_t size, int64_t d) |
1016 | 0 | { |
1017 | 0 | char *e; |
1018 | |
|
1019 | 0 | av_assert0(size >= 25); |
1020 | 0 | if (d < 0 && d != INT64_MIN) { |
1021 | 0 | *(buf++) = '-'; |
1022 | 0 | size--; |
1023 | 0 | d = -d; |
1024 | 0 | } |
1025 | 0 | if (d == INT64_MAX) |
1026 | 0 | snprintf(buf, size, "INT64_MAX"); |
1027 | 0 | else if (d == INT64_MIN) |
1028 | 0 | snprintf(buf, size, "INT64_MIN"); |
1029 | 0 | else if (d > (int64_t)3600*1000000) |
1030 | 0 | snprintf(buf, size, "%"PRId64":%02d:%02d.%06d", d / 3600000000, |
1031 | 0 | (int)((d / 60000000) % 60), |
1032 | 0 | (int)((d / 1000000) % 60), |
1033 | 0 | (int)(d % 1000000)); |
1034 | 0 | else if (d > 60*1000000) |
1035 | 0 | snprintf(buf, size, "%d:%02d.%06d", |
1036 | 0 | (int)(d / 60000000), |
1037 | 0 | (int)((d / 1000000) % 60), |
1038 | 0 | (int)(d % 1000000)); |
1039 | 0 | else |
1040 | 0 | snprintf(buf, size, "%d.%06d", |
1041 | 0 | (int)(d / 1000000), |
1042 | 0 | (int)(d % 1000000)); |
1043 | 0 | e = buf + strlen(buf); |
1044 | 0 | while (e > buf && e[-1] == '0') |
1045 | 0 | *(--e) = 0; |
1046 | 0 | if (e > buf && e[-1] == '.') |
1047 | 0 | *(--e) = 0; |
1048 | 0 | } |
1049 | | |
1050 | | static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len, |
1051 | | const void *dst, int search_flags) |
1052 | 0 | { |
1053 | 0 | int ret; |
1054 | |
|
1055 | 0 | switch (TYPE_BASE(o->type)) { |
1056 | 0 | case AV_OPT_TYPE_BOOL: |
1057 | 0 | ret = snprintf(*pbuf, buf_len, "%s", get_bool_name(*(int *)dst)); |
1058 | 0 | break; |
1059 | 0 | case AV_OPT_TYPE_FLAGS: |
1060 | 0 | ret = snprintf(*pbuf, buf_len, "0x%08X", *(int *)dst); |
1061 | 0 | break; |
1062 | 0 | case AV_OPT_TYPE_INT: |
1063 | 0 | ret = snprintf(*pbuf, buf_len, "%d", *(int *)dst); |
1064 | 0 | break; |
1065 | 0 | case AV_OPT_TYPE_UINT: |
1066 | 0 | ret = snprintf(*pbuf, buf_len, "%u", *(unsigned *)dst); |
1067 | 0 | break; |
1068 | 0 | case AV_OPT_TYPE_INT64: |
1069 | 0 | ret = snprintf(*pbuf, buf_len, "%"PRId64, *(int64_t *)dst); |
1070 | 0 | break; |
1071 | 0 | case AV_OPT_TYPE_UINT64: |
1072 | 0 | ret = snprintf(*pbuf, buf_len, "%"PRIu64, *(uint64_t *)dst); |
1073 | 0 | break; |
1074 | 0 | case AV_OPT_TYPE_FLOAT: |
1075 | 0 | ret = snprintf(*pbuf, buf_len, "%f", *(float *)dst); |
1076 | 0 | break; |
1077 | 0 | case AV_OPT_TYPE_DOUBLE: |
1078 | 0 | ret = snprintf(*pbuf, buf_len, "%f", *(double *)dst); |
1079 | 0 | break; |
1080 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
1081 | 0 | case AV_OPT_TYPE_RATIONAL: |
1082 | 0 | ret = snprintf(*pbuf, buf_len, "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den); |
1083 | 0 | break; |
1084 | 0 | case AV_OPT_TYPE_CONST: |
1085 | 0 | ret = snprintf(*pbuf, buf_len, "%"PRId64, o->default_val.i64); |
1086 | 0 | break; |
1087 | 0 | case AV_OPT_TYPE_STRING: |
1088 | 0 | if (*(uint8_t **)dst) { |
1089 | 0 | *pbuf = av_strdup(*(uint8_t **)dst); |
1090 | 0 | } else if (search_flags & AV_OPT_ALLOW_NULL) { |
1091 | 0 | *pbuf = NULL; |
1092 | 0 | return 0; |
1093 | 0 | } else { |
1094 | 0 | *pbuf = av_strdup(""); |
1095 | 0 | } |
1096 | 0 | return *pbuf ? 0 : AVERROR(ENOMEM); |
1097 | 0 | case AV_OPT_TYPE_BINARY: { |
1098 | 0 | const uint8_t *bin; |
1099 | 0 | int len; |
1100 | |
|
1101 | 0 | if (!*(uint8_t **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { |
1102 | 0 | *pbuf = NULL; |
1103 | 0 | return 0; |
1104 | 0 | } |
1105 | 0 | len = *(int *)(((uint8_t *)dst) + sizeof(uint8_t *)); |
1106 | 0 | if ((uint64_t)len * 2 + 1 > INT_MAX) |
1107 | 0 | return AVERROR(EINVAL); |
1108 | 0 | if (!(*pbuf = av_malloc(len * 2 + 1))) |
1109 | 0 | return AVERROR(ENOMEM); |
1110 | 0 | if (!len) { |
1111 | 0 | *pbuf[0] = '\0'; |
1112 | 0 | return 0; |
1113 | 0 | } |
1114 | 0 | bin = *(uint8_t **)dst; |
1115 | 0 | for (int i = 0; i < len; i++) |
1116 | 0 | snprintf(*pbuf + i * 2, 3, "%02X", bin[i]); |
1117 | 0 | return 0; |
1118 | 0 | } |
1119 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
1120 | 0 | ret = snprintf(*pbuf, buf_len, "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); |
1121 | 0 | break; |
1122 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
1123 | 0 | ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none")); |
1124 | 0 | break; |
1125 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
1126 | 0 | ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none")); |
1127 | 0 | break; |
1128 | 0 | case AV_OPT_TYPE_DURATION: { |
1129 | 0 | int64_t i64 = *(int64_t *)dst; |
1130 | 0 | format_duration(*pbuf, buf_len, i64); |
1131 | 0 | ret = strlen(*pbuf); // no overflow possible, checked by an assert |
1132 | 0 | break; |
1133 | 0 | } |
1134 | 0 | case AV_OPT_TYPE_COLOR: |
1135 | 0 | ret = snprintf(*pbuf, buf_len, "0x%02x%02x%02x%02x", |
1136 | 0 | (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1], |
1137 | 0 | (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]); |
1138 | 0 | break; |
1139 | 0 | case AV_OPT_TYPE_CHLAYOUT: |
1140 | 0 | ret = av_channel_layout_describe(dst, *pbuf, buf_len); |
1141 | 0 | break; |
1142 | 0 | case AV_OPT_TYPE_DICT: |
1143 | 0 | if (!*(AVDictionary **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { |
1144 | 0 | *pbuf = NULL; |
1145 | 0 | return 0; |
1146 | 0 | } |
1147 | 0 | return av_dict_get_string(*(AVDictionary **)dst, (char **)pbuf, '=', ':'); |
1148 | 0 | default: |
1149 | 0 | return AVERROR(EINVAL); |
1150 | 0 | } |
1151 | | |
1152 | 0 | return ret; |
1153 | 0 | } |
1154 | | |
1155 | | static int opt_get_array(const AVOption *o, void *dst, uint8_t **out_val) |
1156 | 0 | { |
1157 | 0 | const unsigned count = *opt_array_pcount(dst); |
1158 | 0 | const uint8_t sep = opt_array_sep(o); |
1159 | |
|
1160 | 0 | uint8_t *str = NULL; |
1161 | 0 | size_t str_len = 0; |
1162 | 0 | int ret; |
1163 | |
|
1164 | 0 | *out_val = NULL; |
1165 | |
|
1166 | 0 | for (unsigned i = 0; i < count; i++) { |
1167 | 0 | uint8_t buf[128], *out = buf; |
1168 | 0 | size_t out_len; |
1169 | |
|
1170 | 0 | ret = opt_get_elem(o, &out, sizeof(buf), |
1171 | 0 | opt_array_pelem(o, *(void **)dst, i), 0); |
1172 | 0 | if (ret < 0) |
1173 | 0 | goto fail; |
1174 | | |
1175 | 0 | out_len = strlen(out); |
1176 | 0 | if (out_len > SIZE_MAX / 2 - !!i || |
1177 | 0 | !!i + out_len * 2 > SIZE_MAX - str_len - 1) { |
1178 | 0 | ret = AVERROR(ERANGE); |
1179 | 0 | goto fail; |
1180 | 0 | } |
1181 | | |
1182 | | // terminator escaping separator |
1183 | | // ↓ ↓ ↓ |
1184 | 0 | ret = av_reallocp(&str, str_len + 1 + out_len * 2 + !!i); |
1185 | 0 | if (ret < 0) |
1186 | 0 | goto fail; |
1187 | | |
1188 | | // add separator if needed |
1189 | 0 | if (i) |
1190 | 0 | str[str_len++] = sep; |
1191 | | |
1192 | | // escape the element |
1193 | 0 | for (unsigned j = 0; j < out_len; j++) { |
1194 | 0 | uint8_t val = out[j]; |
1195 | 0 | if (val == sep || val == '\\') |
1196 | 0 | str[str_len++] = '\\'; |
1197 | 0 | str[str_len++] = val; |
1198 | 0 | } |
1199 | 0 | str[str_len] = 0; |
1200 | |
|
1201 | 0 | fail: |
1202 | 0 | if (out != buf) |
1203 | 0 | av_freep(&out); |
1204 | 0 | if (ret < 0) { |
1205 | 0 | av_freep(&str); |
1206 | 0 | return ret; |
1207 | 0 | } |
1208 | 0 | } |
1209 | | |
1210 | 0 | *out_val = str; |
1211 | |
|
1212 | 0 | return 0; |
1213 | 0 | } |
1214 | | |
1215 | | int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) |
1216 | 0 | { |
1217 | 0 | void *dst, *target_obj; |
1218 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1219 | 0 | uint8_t *out, buf[128]; |
1220 | 0 | int ret; |
1221 | |
|
1222 | 0 | if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) |
1223 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1224 | | |
1225 | 0 | if (o->flags & AV_OPT_FLAG_DEPRECATED) |
1226 | 0 | av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); |
1227 | |
|
1228 | 0 | dst = (uint8_t *)target_obj + o->offset; |
1229 | |
|
1230 | 0 | if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { |
1231 | 0 | ret = opt_get_array(o, dst, out_val); |
1232 | 0 | if (ret < 0) |
1233 | 0 | return ret; |
1234 | 0 | if (!*out_val && !(search_flags & AV_OPT_ALLOW_NULL)) { |
1235 | 0 | *out_val = av_strdup(""); |
1236 | 0 | if (!*out_val) |
1237 | 0 | return AVERROR(ENOMEM); |
1238 | 0 | } |
1239 | 0 | return 0; |
1240 | 0 | } |
1241 | | |
1242 | 0 | buf[0] = 0; |
1243 | 0 | out = buf; |
1244 | 0 | ret = opt_get_elem(o, &out, sizeof(buf), dst, search_flags); |
1245 | 0 | if (ret < 0) |
1246 | 0 | return ret; |
1247 | 0 | if (out != buf) { |
1248 | 0 | *out_val = out; |
1249 | 0 | return 0; |
1250 | 0 | } |
1251 | | |
1252 | 0 | if (ret >= sizeof(buf)) |
1253 | 0 | return AVERROR(EINVAL); |
1254 | 0 | *out_val = av_strdup(out); |
1255 | 0 | return *out_val ? 0 : AVERROR(ENOMEM); |
1256 | 0 | } |
1257 | | |
1258 | | static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum, |
1259 | | int search_flags) |
1260 | 0 | { |
1261 | 0 | void *dst, *target_obj; |
1262 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1263 | 0 | if (!o || !target_obj) |
1264 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1265 | 0 | if (o->type & AV_OPT_TYPE_FLAG_ARRAY) |
1266 | 0 | return AVERROR(EINVAL); |
1267 | | |
1268 | 0 | dst = ((uint8_t *)target_obj) + o->offset; |
1269 | |
|
1270 | 0 | return read_number(o, dst, num, den, intnum); |
1271 | 0 | } |
1272 | | |
1273 | | int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val) |
1274 | 0 | { |
1275 | 0 | int64_t intnum = 1; |
1276 | 0 | double num = 1; |
1277 | 0 | int ret, den = 1; |
1278 | |
|
1279 | 0 | if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) |
1280 | 0 | return ret; |
1281 | 0 | if (num == den) |
1282 | 0 | *out_val = intnum; |
1283 | 0 | else |
1284 | 0 | *out_val = num * intnum / den; |
1285 | 0 | return 0; |
1286 | 0 | } |
1287 | | |
1288 | | int av_opt_get_double(void *obj, const char *name, int search_flags, double *out_val) |
1289 | 0 | { |
1290 | 0 | int64_t intnum = 1; |
1291 | 0 | double num = 1; |
1292 | 0 | int ret, den = 1; |
1293 | |
|
1294 | 0 | if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) |
1295 | 0 | return ret; |
1296 | 0 | *out_val = num * intnum / den; |
1297 | 0 | return 0; |
1298 | 0 | } |
1299 | | |
1300 | | int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_val) |
1301 | 0 | { |
1302 | 0 | int64_t intnum = 1; |
1303 | 0 | double num = 1; |
1304 | 0 | int ret, den = 1; |
1305 | |
|
1306 | 0 | if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) |
1307 | 0 | return ret; |
1308 | | |
1309 | 0 | if (num == 1.0 && (int)intnum == intnum) |
1310 | 0 | *out_val = (AVRational){intnum, den}; |
1311 | 0 | else |
1312 | 0 | *out_val = double_to_rational(num*intnum/den); |
1313 | 0 | return 0; |
1314 | 0 | } |
1315 | | |
1316 | | int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out) |
1317 | 0 | { |
1318 | 0 | void *dst, *target_obj; |
1319 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1320 | 0 | if (!o || !target_obj) |
1321 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1322 | 0 | if (o->type != AV_OPT_TYPE_IMAGE_SIZE) { |
1323 | 0 | av_log(obj, AV_LOG_ERROR, |
1324 | 0 | "The value for option '%s' is not a image size.\n", name); |
1325 | 0 | return AVERROR(EINVAL); |
1326 | 0 | } |
1327 | | |
1328 | 0 | dst = ((uint8_t*)target_obj) + o->offset; |
1329 | 0 | if (w_out) *w_out = *(int *)dst; |
1330 | 0 | if (h_out) *h_out = *((int *)dst+1); |
1331 | 0 | return 0; |
1332 | 0 | } |
1333 | | |
1334 | | int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val) |
1335 | 0 | { |
1336 | 0 | return av_opt_get_q(obj, name, search_flags, out_val); |
1337 | 0 | } |
1338 | | |
1339 | | static int get_format(void *obj, const char *name, int search_flags, int *out_fmt, |
1340 | | enum AVOptionType type, const char *desc) |
1341 | 0 | { |
1342 | 0 | void *dst, *target_obj; |
1343 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1344 | 0 | if (!o || !target_obj) |
1345 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1346 | 0 | if (o->type != type) { |
1347 | 0 | av_log(obj, AV_LOG_ERROR, |
1348 | 0 | "The value for option '%s' is not a %s format.\n", desc, name); |
1349 | 0 | return AVERROR(EINVAL); |
1350 | 0 | } |
1351 | | |
1352 | 0 | dst = ((uint8_t*)target_obj) + o->offset; |
1353 | 0 | *out_fmt = *(int *)dst; |
1354 | 0 | return 0; |
1355 | 0 | } |
1356 | | |
1357 | | int av_opt_get_pixel_fmt(void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt) |
1358 | 0 | { |
1359 | 0 | return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel"); |
1360 | 0 | } |
1361 | | |
1362 | | int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt) |
1363 | 0 | { |
1364 | 0 | return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample"); |
1365 | 0 | } |
1366 | | |
1367 | | int av_opt_get_chlayout(void *obj, const char *name, int search_flags, AVChannelLayout *cl) |
1368 | 0 | { |
1369 | 0 | void *dst, *target_obj; |
1370 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1371 | 0 | if (!o || !target_obj) |
1372 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1373 | 0 | if (o->type != AV_OPT_TYPE_CHLAYOUT) { |
1374 | 0 | av_log(obj, AV_LOG_ERROR, |
1375 | 0 | "The value for option '%s' is not a channel layout.\n", name); |
1376 | 0 | return AVERROR(EINVAL); |
1377 | 0 | } |
1378 | | |
1379 | 0 | dst = ((uint8_t*)target_obj) + o->offset; |
1380 | 0 | return av_channel_layout_copy(cl, dst); |
1381 | 0 | } |
1382 | | |
1383 | | int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val) |
1384 | 0 | { |
1385 | 0 | void *target_obj; |
1386 | 0 | AVDictionary *src; |
1387 | 0 | const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
1388 | |
|
1389 | 0 | if (!o || !target_obj) |
1390 | 0 | return AVERROR_OPTION_NOT_FOUND; |
1391 | 0 | if (o->type != AV_OPT_TYPE_DICT) |
1392 | 0 | return AVERROR(EINVAL); |
1393 | | |
1394 | 0 | src = *(AVDictionary **)(((uint8_t *)target_obj) + o->offset); |
1395 | |
|
1396 | 0 | return av_dict_copy(out_val, src, 0); |
1397 | 0 | } |
1398 | | |
1399 | | int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) |
1400 | 0 | { |
1401 | 0 | const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0); |
1402 | 0 | const AVOption *flag = av_opt_find(obj, flag_name, |
1403 | 0 | field ? field->unit : NULL, 0, 0); |
1404 | 0 | int64_t res; |
1405 | |
|
1406 | 0 | if (!field || !flag || flag->type != AV_OPT_TYPE_CONST || |
1407 | 0 | av_opt_get_int(obj, field_name, 0, &res) < 0) |
1408 | 0 | return 0; |
1409 | 0 | return res & flag->default_val.i64; |
1410 | 0 | } |
1411 | | |
1412 | | static void log_int_value(void *av_log_obj, int level, int64_t i) |
1413 | 0 | { |
1414 | 0 | if (i == INT_MAX) { |
1415 | 0 | av_log(av_log_obj, level, "INT_MAX"); |
1416 | 0 | } else if (i == INT_MIN) { |
1417 | 0 | av_log(av_log_obj, level, "INT_MIN"); |
1418 | 0 | } else if (i == UINT32_MAX) { |
1419 | 0 | av_log(av_log_obj, level, "UINT32_MAX"); |
1420 | 0 | } else if (i == INT64_MAX) { |
1421 | 0 | av_log(av_log_obj, level, "I64_MAX"); |
1422 | 0 | } else if (i == INT64_MIN) { |
1423 | 0 | av_log(av_log_obj, level, "I64_MIN"); |
1424 | 0 | } else { |
1425 | 0 | av_log(av_log_obj, level, "%"PRId64, i); |
1426 | 0 | } |
1427 | 0 | } |
1428 | | |
1429 | | static void log_value(void *av_log_obj, int level, double d) |
1430 | 0 | { |
1431 | 0 | if (d == INT_MAX) { |
1432 | 0 | av_log(av_log_obj, level, "INT_MAX"); |
1433 | 0 | } else if (d == INT_MIN) { |
1434 | 0 | av_log(av_log_obj, level, "INT_MIN"); |
1435 | 0 | } else if (d == UINT32_MAX) { |
1436 | 0 | av_log(av_log_obj, level, "UINT32_MAX"); |
1437 | 0 | } else if (d == (double)INT64_MAX) { |
1438 | 0 | av_log(av_log_obj, level, "I64_MAX"); |
1439 | 0 | } else if (d == INT64_MIN) { |
1440 | 0 | av_log(av_log_obj, level, "I64_MIN"); |
1441 | 0 | } else if (d == FLT_MAX) { |
1442 | 0 | av_log(av_log_obj, level, "FLT_MAX"); |
1443 | 0 | } else if (d == FLT_MIN) { |
1444 | 0 | av_log(av_log_obj, level, "FLT_MIN"); |
1445 | 0 | } else if (d == -FLT_MAX) { |
1446 | 0 | av_log(av_log_obj, level, "-FLT_MAX"); |
1447 | 0 | } else if (d == -FLT_MIN) { |
1448 | 0 | av_log(av_log_obj, level, "-FLT_MIN"); |
1449 | 0 | } else if (d == DBL_MAX) { |
1450 | 0 | av_log(av_log_obj, level, "DBL_MAX"); |
1451 | 0 | } else if (d == DBL_MIN) { |
1452 | 0 | av_log(av_log_obj, level, "DBL_MIN"); |
1453 | 0 | } else if (d == -DBL_MAX) { |
1454 | 0 | av_log(av_log_obj, level, "-DBL_MAX"); |
1455 | 0 | } else if (d == -DBL_MIN) { |
1456 | 0 | av_log(av_log_obj, level, "-DBL_MIN"); |
1457 | 0 | } else { |
1458 | 0 | av_log(av_log_obj, level, "%g", d); |
1459 | 0 | } |
1460 | 0 | } |
1461 | | |
1462 | | static const char *get_opt_const_name(void *obj, const char *unit, int64_t value) |
1463 | 0 | { |
1464 | 0 | const AVOption *opt = NULL; |
1465 | |
|
1466 | 0 | if (!unit) |
1467 | 0 | return NULL; |
1468 | 0 | while ((opt = av_opt_next(obj, opt))) |
1469 | 0 | if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && |
1470 | 0 | opt->default_val.i64 == value) |
1471 | 0 | return opt->name; |
1472 | 0 | return NULL; |
1473 | 0 | } |
1474 | | |
1475 | | static char *get_opt_flags_string(void *obj, const char *unit, int64_t value) |
1476 | 0 | { |
1477 | 0 | const AVOption *opt = NULL; |
1478 | 0 | char flags[512]; |
1479 | |
|
1480 | 0 | flags[0] = 0; |
1481 | 0 | if (!unit) |
1482 | 0 | return NULL; |
1483 | 0 | while ((opt = av_opt_next(obj, opt))) { |
1484 | 0 | if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && |
1485 | 0 | opt->default_val.i64 & value) { |
1486 | 0 | if (flags[0]) |
1487 | 0 | av_strlcatf(flags, sizeof(flags), "+"); |
1488 | 0 | av_strlcatf(flags, sizeof(flags), "%s", opt->name); |
1489 | 0 | } |
1490 | 0 | } |
1491 | 0 | if (flags[0]) |
1492 | 0 | return av_strdup(flags); |
1493 | 0 | return NULL; |
1494 | 0 | } |
1495 | | |
1496 | | static void log_type(void *av_log_obj, const AVOption *o, |
1497 | | enum AVOptionType parent_type) |
1498 | 0 | { |
1499 | 0 | const enum AVOptionType type = TYPE_BASE(o->type); |
1500 | |
|
1501 | 0 | if (o->type == AV_OPT_TYPE_CONST && (TYPE_BASE(parent_type) == AV_OPT_TYPE_INT || TYPE_BASE(parent_type) == AV_OPT_TYPE_INT64)) |
1502 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", o->default_val.i64); |
1503 | 0 | else if (type < FF_ARRAY_ELEMS(opt_type_desc) && opt_type_desc[type].name) { |
1504 | 0 | if (o->type & AV_OPT_TYPE_FLAG_ARRAY) |
1505 | 0 | av_log(av_log_obj, AV_LOG_INFO, "[%-10s]", opt_type_desc[type].name); |
1506 | 0 | else |
1507 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%-12s ", opt_type_desc[type].name); |
1508 | 0 | } |
1509 | 0 | else |
1510 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); |
1511 | 0 | } |
1512 | | |
1513 | | static void log_default(void *obj, void *av_log_obj, const AVOption *opt) |
1514 | 0 | { |
1515 | 0 | if (opt->type == AV_OPT_TYPE_CONST || opt->type == AV_OPT_TYPE_BINARY) |
1516 | 0 | return; |
1517 | 0 | if ((opt->type == AV_OPT_TYPE_COLOR || |
1518 | 0 | opt->type == AV_OPT_TYPE_IMAGE_SIZE || |
1519 | 0 | opt->type == AV_OPT_TYPE_STRING || |
1520 | 0 | opt->type == AV_OPT_TYPE_DICT || |
1521 | 0 | opt->type == AV_OPT_TYPE_CHLAYOUT || |
1522 | 0 | opt->type == AV_OPT_TYPE_VIDEO_RATE) && |
1523 | 0 | !opt->default_val.str) |
1524 | 0 | return; |
1525 | | |
1526 | 0 | if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { |
1527 | 0 | const AVOptionArrayDef *arr = opt->default_val.arr; |
1528 | 0 | if (arr && arr->def) |
1529 | 0 | av_log(av_log_obj, AV_LOG_INFO, " (default %s)", arr->def); |
1530 | 0 | return; |
1531 | 0 | } |
1532 | | |
1533 | 0 | av_log(av_log_obj, AV_LOG_INFO, " (default "); |
1534 | 0 | switch (opt->type) { |
1535 | 0 | case AV_OPT_TYPE_BOOL: |
1536 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", get_bool_name(opt->default_val.i64)); |
1537 | 0 | break; |
1538 | 0 | case AV_OPT_TYPE_FLAGS: { |
1539 | 0 | char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64); |
1540 | 0 | if (def_flags) { |
1541 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags); |
1542 | 0 | av_freep(&def_flags); |
1543 | 0 | } else { |
1544 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64); |
1545 | 0 | } |
1546 | 0 | break; |
1547 | 0 | } |
1548 | 0 | case AV_OPT_TYPE_DURATION: { |
1549 | 0 | char buf[25]; |
1550 | 0 | format_duration(buf, sizeof(buf), opt->default_val.i64); |
1551 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", buf); |
1552 | 0 | break; |
1553 | 0 | } |
1554 | 0 | case AV_OPT_TYPE_UINT: |
1555 | 0 | case AV_OPT_TYPE_INT: |
1556 | 0 | case AV_OPT_TYPE_UINT64: |
1557 | 0 | case AV_OPT_TYPE_INT64: { |
1558 | 0 | const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); |
1559 | 0 | if (def_const) |
1560 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", def_const); |
1561 | 0 | else |
1562 | 0 | log_int_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64); |
1563 | 0 | break; |
1564 | 0 | } |
1565 | 0 | case AV_OPT_TYPE_DOUBLE: |
1566 | 0 | case AV_OPT_TYPE_FLOAT: |
1567 | 0 | log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl); |
1568 | 0 | break; |
1569 | 0 | case AV_OPT_TYPE_RATIONAL: { |
1570 | 0 | AVRational q = av_d2q(opt->default_val.dbl, INT_MAX); |
1571 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); } |
1572 | 0 | break; |
1573 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
1574 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none")); |
1575 | 0 | break; |
1576 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
1577 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none")); |
1578 | 0 | break; |
1579 | 0 | case AV_OPT_TYPE_COLOR: |
1580 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
1581 | 0 | case AV_OPT_TYPE_STRING: |
1582 | 0 | case AV_OPT_TYPE_DICT: |
1583 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
1584 | 0 | case AV_OPT_TYPE_CHLAYOUT: |
1585 | 0 | av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str); |
1586 | 0 | break; |
1587 | 0 | } |
1588 | 0 | av_log(av_log_obj, AV_LOG_INFO, ")"); |
1589 | 0 | } |
1590 | | |
1591 | | static void opt_list(void *obj, void *av_log_obj, const char *unit, |
1592 | | int req_flags, int rej_flags, enum AVOptionType parent_type) |
1593 | 0 | { |
1594 | 0 | const AVOption *opt = NULL; |
1595 | 0 | AVOptionRanges *r; |
1596 | 0 | int i; |
1597 | |
|
1598 | 0 | while ((opt = av_opt_next(obj, opt))) { |
1599 | 0 | if (!(opt->flags & req_flags) || (opt->flags & rej_flags)) |
1600 | 0 | continue; |
1601 | | |
1602 | | /* Don't print CONST's on level one. |
1603 | | * Don't print anything but CONST's on level two. |
1604 | | * Only print items from the requested unit. |
1605 | | */ |
1606 | 0 | if (!unit && opt->type == AV_OPT_TYPE_CONST) |
1607 | 0 | continue; |
1608 | 0 | else if (unit && opt->type != AV_OPT_TYPE_CONST) |
1609 | 0 | continue; |
1610 | 0 | else if (unit && opt->type == AV_OPT_TYPE_CONST && strcmp(unit, opt->unit)) |
1611 | 0 | continue; |
1612 | 0 | else if (unit && opt->type == AV_OPT_TYPE_CONST) |
1613 | 0 | av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name); |
1614 | 0 | else |
1615 | 0 | av_log(av_log_obj, AV_LOG_INFO, " %s%-17s ", |
1616 | 0 | (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? " " : "-", |
1617 | 0 | opt->name); |
1618 | | |
1619 | 0 | log_type(av_log_obj, opt, parent_type); |
1620 | |
|
1621 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%c%c%c%c%c%c%c%c%c%c%c", |
1622 | 0 | (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.', |
1623 | 0 | (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.', |
1624 | 0 | (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? 'F' : '.', |
1625 | 0 | (opt->flags & AV_OPT_FLAG_VIDEO_PARAM) ? 'V' : '.', |
1626 | 0 | (opt->flags & AV_OPT_FLAG_AUDIO_PARAM) ? 'A' : '.', |
1627 | 0 | (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.', |
1628 | 0 | (opt->flags & AV_OPT_FLAG_EXPORT) ? 'X' : '.', |
1629 | 0 | (opt->flags & AV_OPT_FLAG_READONLY) ? 'R' : '.', |
1630 | 0 | (opt->flags & AV_OPT_FLAG_BSF_PARAM) ? 'B' : '.', |
1631 | 0 | (opt->flags & AV_OPT_FLAG_RUNTIME_PARAM) ? 'T' : '.', |
1632 | 0 | (opt->flags & AV_OPT_FLAG_DEPRECATED) ? 'P' : '.'); |
1633 | |
|
1634 | 0 | if (opt->help) |
1635 | 0 | av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help); |
1636 | |
|
1637 | 0 | if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { |
1638 | 0 | switch (opt->type) { |
1639 | 0 | case AV_OPT_TYPE_INT: |
1640 | 0 | case AV_OPT_TYPE_UINT: |
1641 | 0 | case AV_OPT_TYPE_INT64: |
1642 | 0 | case AV_OPT_TYPE_UINT64: |
1643 | 0 | case AV_OPT_TYPE_DOUBLE: |
1644 | 0 | case AV_OPT_TYPE_FLOAT: |
1645 | 0 | case AV_OPT_TYPE_RATIONAL: |
1646 | 0 | for (i = 0; i < r->nb_ranges; i++) { |
1647 | 0 | av_log(av_log_obj, AV_LOG_INFO, " (from "); |
1648 | 0 | log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min); |
1649 | 0 | av_log(av_log_obj, AV_LOG_INFO, " to "); |
1650 | 0 | log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max); |
1651 | 0 | av_log(av_log_obj, AV_LOG_INFO, ")"); |
1652 | 0 | } |
1653 | 0 | break; |
1654 | 0 | } |
1655 | 0 | av_opt_freep_ranges(&r); |
1656 | 0 | } |
1657 | | |
1658 | 0 | log_default(obj, av_log_obj, opt); |
1659 | |
|
1660 | 0 | av_log(av_log_obj, AV_LOG_INFO, "\n"); |
1661 | 0 | if (opt->unit && opt->type != AV_OPT_TYPE_CONST) |
1662 | 0 | opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags, opt->type); |
1663 | 0 | } |
1664 | 0 | } |
1665 | | |
1666 | | int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags) |
1667 | 0 | { |
1668 | 0 | if (!obj) |
1669 | 0 | return -1; |
1670 | | |
1671 | 0 | av_log(av_log_obj, AV_LOG_INFO, "%s AVOptions:\n", (*(AVClass **)obj)->class_name); |
1672 | |
|
1673 | 0 | opt_list(obj, av_log_obj, NULL, req_flags, rej_flags, -1); |
1674 | |
|
1675 | 0 | return 0; |
1676 | 0 | } |
1677 | | |
1678 | | void av_opt_set_defaults(void *s) |
1679 | 1.36k | { |
1680 | 1.36k | av_opt_set_defaults2(s, 0, 0); |
1681 | 1.36k | } |
1682 | | |
1683 | | void av_opt_set_defaults2(void *s, int mask, int flags) |
1684 | 1.36k | { |
1685 | 1.36k | const AVOption *opt = NULL; |
1686 | 96.8k | while ((opt = av_opt_next(s, opt))) { |
1687 | 95.4k | void *dst = ((uint8_t*)s) + opt->offset; |
1688 | | |
1689 | 95.4k | if ((opt->flags & mask) != flags) |
1690 | 0 | continue; |
1691 | | |
1692 | 95.4k | if (opt->flags & AV_OPT_FLAG_READONLY) |
1693 | 0 | continue; |
1694 | | |
1695 | 95.4k | if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { |
1696 | 0 | const AVOptionArrayDef *arr = opt->default_val.arr; |
1697 | 0 | const char sep = opt_array_sep(opt); |
1698 | |
|
1699 | 0 | av_assert0(sep && sep != '\\' && |
1700 | 0 | (sep < 'a' || sep > 'z') && |
1701 | 0 | (sep < 'A' || sep > 'Z') && |
1702 | 0 | (sep < '0' || sep > '9')); |
1703 | | |
1704 | 0 | if (arr && arr->def) |
1705 | 0 | opt_set_array(s, s, opt, arr->def, dst); |
1706 | |
|
1707 | 0 | continue; |
1708 | 0 | } |
1709 | | |
1710 | 95.4k | switch (opt->type) { |
1711 | 42.2k | case AV_OPT_TYPE_CONST: |
1712 | | /* Nothing to be done here */ |
1713 | 42.2k | break; |
1714 | 5.45k | case AV_OPT_TYPE_BOOL: |
1715 | 12.2k | case AV_OPT_TYPE_FLAGS: |
1716 | 35.4k | case AV_OPT_TYPE_INT: |
1717 | 35.4k | case AV_OPT_TYPE_UINT: |
1718 | 43.6k | case AV_OPT_TYPE_INT64: |
1719 | 43.6k | case AV_OPT_TYPE_UINT64: |
1720 | 45.0k | case AV_OPT_TYPE_DURATION: |
1721 | 45.0k | case AV_OPT_TYPE_PIXEL_FMT: |
1722 | 45.0k | case AV_OPT_TYPE_SAMPLE_FMT: |
1723 | 45.0k | write_number(s, opt, dst, 1, 1, opt->default_val.i64); |
1724 | 45.0k | break; |
1725 | 0 | case AV_OPT_TYPE_DOUBLE: |
1726 | 0 | case AV_OPT_TYPE_FLOAT: { |
1727 | 0 | double val; |
1728 | 0 | val = opt->default_val.dbl; |
1729 | 0 | write_number(s, opt, dst, val, 1, 1); |
1730 | 0 | } |
1731 | 0 | break; |
1732 | 0 | case AV_OPT_TYPE_RATIONAL: { |
1733 | 0 | AVRational val; |
1734 | 0 | val = av_d2q(opt->default_val.dbl, INT_MAX); |
1735 | 0 | write_number(s, opt, dst, 1, val.den, val.num); |
1736 | 0 | } |
1737 | 0 | break; |
1738 | 0 | case AV_OPT_TYPE_COLOR: |
1739 | 0 | set_string_color(s, opt, opt->default_val.str, dst); |
1740 | 0 | break; |
1741 | 6.82k | case AV_OPT_TYPE_STRING: |
1742 | 6.82k | set_string(s, opt, opt->default_val.str, dst); |
1743 | 6.82k | break; |
1744 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
1745 | 0 | set_string_image_size(s, opt, opt->default_val.str, dst); |
1746 | 0 | break; |
1747 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
1748 | 0 | set_string_video_rate(s, opt, opt->default_val.str, dst); |
1749 | 0 | break; |
1750 | 1.36k | case AV_OPT_TYPE_BINARY: |
1751 | 1.36k | set_string_binary(s, opt, opt->default_val.str, dst); |
1752 | 1.36k | break; |
1753 | 0 | case AV_OPT_TYPE_CHLAYOUT: |
1754 | 0 | set_string_channel_layout(s, opt, opt->default_val.str, dst); |
1755 | 0 | break; |
1756 | 0 | case AV_OPT_TYPE_DICT: |
1757 | 0 | set_string_dict(s, opt, opt->default_val.str, dst); |
1758 | 0 | break; |
1759 | 0 | default: |
1760 | 0 | av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", |
1761 | 0 | opt->type, opt->name); |
1762 | 95.4k | } |
1763 | 95.4k | } |
1764 | 1.36k | } |
1765 | | |
1766 | | /** |
1767 | | * Store the value in the field in ctx that is named like key. |
1768 | | * ctx must be an AVClass context, storing is done using AVOptions. |
1769 | | * |
1770 | | * @param buf the string to parse, buf will be updated to point at the |
1771 | | * separator just after the parsed key/value pair |
1772 | | * @param key_val_sep a 0-terminated list of characters used to |
1773 | | * separate key from value |
1774 | | * @param pairs_sep a 0-terminated list of characters used to separate |
1775 | | * two pairs from each other |
1776 | | * @return 0 if the key/value pair has been successfully parsed and |
1777 | | * set, or a negative value corresponding to an AVERROR code in case |
1778 | | * of error: |
1779 | | * AVERROR(EINVAL) if the key/value pair cannot be parsed, |
1780 | | * the error code issued by av_opt_set() if the key/value pair |
1781 | | * cannot be set |
1782 | | */ |
1783 | | static int parse_key_value_pair(void *ctx, const char **buf, |
1784 | | const char *key_val_sep, const char *pairs_sep) |
1785 | 0 | { |
1786 | 0 | char *key = av_get_token(buf, key_val_sep); |
1787 | 0 | char *val; |
1788 | 0 | int ret; |
1789 | |
|
1790 | 0 | if (!key) |
1791 | 0 | return AVERROR(ENOMEM); |
1792 | | |
1793 | 0 | if (*key && strspn(*buf, key_val_sep)) { |
1794 | 0 | (*buf)++; |
1795 | 0 | val = av_get_token(buf, pairs_sep); |
1796 | 0 | if (!val) { |
1797 | 0 | av_freep(&key); |
1798 | 0 | return AVERROR(ENOMEM); |
1799 | 0 | } |
1800 | 0 | } else { |
1801 | 0 | av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key); |
1802 | 0 | av_free(key); |
1803 | 0 | return AVERROR(EINVAL); |
1804 | 0 | } |
1805 | | |
1806 | 0 | av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val); |
1807 | |
|
1808 | 0 | ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN); |
1809 | 0 | if (ret == AVERROR_OPTION_NOT_FOUND) |
1810 | 0 | av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key); |
1811 | |
|
1812 | 0 | av_free(key); |
1813 | 0 | av_free(val); |
1814 | 0 | return ret; |
1815 | 0 | } |
1816 | | |
1817 | | int av_set_options_string(void *ctx, const char *opts, |
1818 | | const char *key_val_sep, const char *pairs_sep) |
1819 | 0 | { |
1820 | 0 | int ret, count = 0; |
1821 | |
|
1822 | 0 | if (!opts) |
1823 | 0 | return 0; |
1824 | | |
1825 | 0 | while (*opts) { |
1826 | 0 | if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) |
1827 | 0 | return ret; |
1828 | 0 | count++; |
1829 | |
|
1830 | 0 | if (*opts) |
1831 | 0 | opts++; |
1832 | 0 | } |
1833 | | |
1834 | 0 | return count; |
1835 | 0 | } |
1836 | | |
1837 | 0 | #define WHITESPACES " \n\t\r" |
1838 | | |
1839 | | static int is_key_char(char c) |
1840 | 0 | { |
1841 | 0 | return (unsigned)((c | 32) - 'a') < 26 || |
1842 | 0 | (unsigned)(c - '0') < 10 || |
1843 | 0 | c == '-' || c == '_' || c == '/' || c == '.'; |
1844 | 0 | } |
1845 | | |
1846 | | /** |
1847 | | * Read a key from a string. |
1848 | | * |
1849 | | * The key consists of is_key_char characters and must be terminated by a |
1850 | | * character from the delim string; spaces are ignored. |
1851 | | * |
1852 | | * @return 0 for success (even with ellipsis), <0 for failure |
1853 | | */ |
1854 | | static int get_key(const char **ropts, const char *delim, char **rkey) |
1855 | 0 | { |
1856 | 0 | const char *opts = *ropts; |
1857 | 0 | const char *key_start, *key_end; |
1858 | |
|
1859 | 0 | key_start = opts += strspn(opts, WHITESPACES); |
1860 | 0 | while (is_key_char(*opts)) |
1861 | 0 | opts++; |
1862 | 0 | key_end = opts; |
1863 | 0 | opts += strspn(opts, WHITESPACES); |
1864 | 0 | if (!*opts || !strchr(delim, *opts)) |
1865 | 0 | return AVERROR(EINVAL); |
1866 | 0 | opts++; |
1867 | 0 | if (!(*rkey = av_malloc(key_end - key_start + 1))) |
1868 | 0 | return AVERROR(ENOMEM); |
1869 | 0 | memcpy(*rkey, key_start, key_end - key_start); |
1870 | 0 | (*rkey)[key_end - key_start] = 0; |
1871 | 0 | *ropts = opts; |
1872 | 0 | return 0; |
1873 | 0 | } |
1874 | | |
1875 | | int av_opt_get_key_value(const char **ropts, |
1876 | | const char *key_val_sep, const char *pairs_sep, |
1877 | | unsigned flags, |
1878 | | char **rkey, char **rval) |
1879 | 0 | { |
1880 | 0 | int ret; |
1881 | 0 | char *key = NULL, *val; |
1882 | 0 | const char *opts = *ropts; |
1883 | |
|
1884 | 0 | if ((ret = get_key(&opts, key_val_sep, &key)) < 0 && |
1885 | 0 | !(flags & AV_OPT_FLAG_IMPLICIT_KEY)) |
1886 | 0 | return AVERROR(EINVAL); |
1887 | 0 | if (!(val = av_get_token(&opts, pairs_sep))) { |
1888 | 0 | av_free(key); |
1889 | 0 | return AVERROR(ENOMEM); |
1890 | 0 | } |
1891 | 0 | *ropts = opts; |
1892 | 0 | *rkey = key; |
1893 | 0 | *rval = val; |
1894 | 0 | return 0; |
1895 | 0 | } |
1896 | | |
1897 | | int av_opt_set_from_string(void *ctx, const char *opts, |
1898 | | const char *const *shorthand, |
1899 | | const char *key_val_sep, const char *pairs_sep) |
1900 | 0 | { |
1901 | 0 | int ret, count = 0; |
1902 | 0 | const char *dummy_shorthand = NULL; |
1903 | 0 | const char *key; |
1904 | |
|
1905 | 0 | if (!opts) |
1906 | 0 | return 0; |
1907 | 0 | if (!shorthand) |
1908 | 0 | shorthand = &dummy_shorthand; |
1909 | |
|
1910 | 0 | while (*opts) { |
1911 | 0 | char *parsed_key, *value; |
1912 | 0 | ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep, |
1913 | 0 | *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, |
1914 | 0 | &parsed_key, &value); |
1915 | 0 | if (ret < 0) { |
1916 | 0 | if (ret == AVERROR(EINVAL)) |
1917 | 0 | av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts); |
1918 | 0 | else |
1919 | 0 | av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", opts, |
1920 | 0 | av_err2str(ret)); |
1921 | 0 | return ret; |
1922 | 0 | } |
1923 | 0 | if (*opts) |
1924 | 0 | opts++; |
1925 | 0 | if (parsed_key) { |
1926 | 0 | key = parsed_key; |
1927 | 0 | while (*shorthand) /* discard all remaining shorthand */ |
1928 | 0 | shorthand++; |
1929 | 0 | } else { |
1930 | 0 | key = *(shorthand++); |
1931 | 0 | } |
1932 | |
|
1933 | 0 | av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); |
1934 | 0 | if ((ret = av_opt_set(ctx, key, value, 0)) < 0) { |
1935 | 0 | if (ret == AVERROR_OPTION_NOT_FOUND) |
1936 | 0 | av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); |
1937 | 0 | av_free(value); |
1938 | 0 | av_free(parsed_key); |
1939 | 0 | return ret; |
1940 | 0 | } |
1941 | | |
1942 | 0 | av_free(value); |
1943 | 0 | av_free(parsed_key); |
1944 | 0 | count++; |
1945 | 0 | } |
1946 | 0 | return count; |
1947 | 0 | } |
1948 | | |
1949 | | void av_opt_free(void *obj) |
1950 | 1.36k | { |
1951 | 1.36k | const AVOption *o = NULL; |
1952 | 96.8k | while ((o = av_opt_next(obj, o))) { |
1953 | 95.4k | void *pitem = (uint8_t *)obj + o->offset; |
1954 | | |
1955 | 95.4k | if (o->type & AV_OPT_TYPE_FLAG_ARRAY) |
1956 | 0 | opt_free_array(o, pitem, opt_array_pcount(pitem)); |
1957 | 95.4k | else |
1958 | 95.4k | opt_free_elem(o->type, pitem); |
1959 | 95.4k | } |
1960 | 1.36k | } |
1961 | | |
1962 | | int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags) |
1963 | 1.36k | { |
1964 | 1.36k | const AVDictionaryEntry *t = NULL; |
1965 | 1.36k | AVDictionary *tmp = NULL; |
1966 | 1.36k | int ret; |
1967 | | |
1968 | 1.36k | if (!options) |
1969 | 0 | return 0; |
1970 | | |
1971 | 1.36k | while ((t = av_dict_iterate(*options, t))) { |
1972 | 0 | ret = av_opt_set(obj, t->key, t->value, search_flags); |
1973 | 0 | if (ret == AVERROR_OPTION_NOT_FOUND) |
1974 | 0 | ret = av_dict_set(&tmp, t->key, t->value, AV_DICT_MULTIKEY); |
1975 | 0 | if (ret < 0) { |
1976 | 0 | av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value); |
1977 | 0 | av_dict_free(&tmp); |
1978 | 0 | return ret; |
1979 | 0 | } |
1980 | 0 | } |
1981 | 1.36k | av_dict_free(options); |
1982 | 1.36k | *options = tmp; |
1983 | 1.36k | return 0; |
1984 | 1.36k | } |
1985 | | |
1986 | | int av_opt_set_dict(void *obj, AVDictionary **options) |
1987 | 1.36k | { |
1988 | 1.36k | return av_opt_set_dict2(obj, options, 0); |
1989 | 1.36k | } |
1990 | | |
1991 | | const AVOption *av_opt_find(void *obj, const char *name, const char *unit, |
1992 | | int opt_flags, int search_flags) |
1993 | 0 | { |
1994 | 0 | return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL); |
1995 | 0 | } |
1996 | | |
1997 | | const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, |
1998 | | int opt_flags, int search_flags, void **target_obj) |
1999 | 0 | { |
2000 | 0 | const AVClass *c; |
2001 | 0 | const AVOption *o = NULL; |
2002 | |
|
2003 | 0 | if(!obj) |
2004 | 0 | return NULL; |
2005 | | |
2006 | 0 | c= *(AVClass**)obj; |
2007 | |
|
2008 | 0 | if (!c) |
2009 | 0 | return NULL; |
2010 | | |
2011 | 0 | if (search_flags & AV_OPT_SEARCH_CHILDREN) { |
2012 | 0 | if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) { |
2013 | 0 | void *iter = NULL; |
2014 | 0 | const AVClass *child; |
2015 | 0 | while (child = av_opt_child_class_iterate(c, &iter)) |
2016 | 0 | if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL)) |
2017 | 0 | return o; |
2018 | 0 | } else { |
2019 | 0 | void *child = NULL; |
2020 | 0 | while (child = av_opt_child_next(obj, child)) |
2021 | 0 | if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj)) |
2022 | 0 | return o; |
2023 | 0 | } |
2024 | 0 | } |
2025 | | |
2026 | 0 | while (o = av_opt_next(obj, o)) { |
2027 | 0 | if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags && |
2028 | 0 | ((!unit && o->type != AV_OPT_TYPE_CONST) || |
2029 | 0 | (unit && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) { |
2030 | 0 | if (target_obj) { |
2031 | 0 | if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ)) |
2032 | 0 | *target_obj = obj; |
2033 | 0 | else |
2034 | 0 | *target_obj = NULL; |
2035 | 0 | } |
2036 | 0 | return o; |
2037 | 0 | } |
2038 | 0 | } |
2039 | 0 | return NULL; |
2040 | 0 | } |
2041 | | |
2042 | | void *av_opt_child_next(void *obj, void *prev) |
2043 | 0 | { |
2044 | 0 | const AVClass *c = *(AVClass **)obj; |
2045 | 0 | if (c->child_next) |
2046 | 0 | return c->child_next(obj, prev); |
2047 | 0 | return NULL; |
2048 | 0 | } |
2049 | | |
2050 | | const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter) |
2051 | 0 | { |
2052 | 0 | if (parent->child_class_iterate) |
2053 | 0 | return parent->child_class_iterate(iter); |
2054 | 0 | return NULL; |
2055 | 0 | } |
2056 | | |
2057 | | #if FF_API_OPT_PTR |
2058 | | void *av_opt_ptr(const AVClass *class, void *obj, const char *name) |
2059 | 0 | { |
2060 | 0 | const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL); |
2061 | | |
2062 | | // no direct access to array-type options |
2063 | 0 | if (!opt || (opt->type & AV_OPT_TYPE_FLAG_ARRAY)) |
2064 | 0 | return NULL; |
2065 | 0 | return (uint8_t*)obj + opt->offset; |
2066 | 0 | } |
2067 | | #endif |
2068 | | |
2069 | | static int opt_copy_elem(void *logctx, enum AVOptionType type, |
2070 | | void *dst, const void *src) |
2071 | 0 | { |
2072 | 0 | if (type == AV_OPT_TYPE_STRING) { |
2073 | 0 | const char *src_str = *(const char *const *)src; |
2074 | 0 | char **dstp = (char **)dst; |
2075 | 0 | if (*dstp != src_str) |
2076 | 0 | av_freep(dstp); |
2077 | 0 | if (src_str) { |
2078 | 0 | *dstp = av_strdup(src_str); |
2079 | 0 | if (!*dstp) |
2080 | 0 | return AVERROR(ENOMEM); |
2081 | 0 | } |
2082 | 0 | } else if (type == AV_OPT_TYPE_BINARY) { |
2083 | 0 | const uint8_t *const *src8 = (const uint8_t *const *)src; |
2084 | 0 | uint8_t **dst8 = (uint8_t **)dst; |
2085 | 0 | int len = *(const int *)(src8 + 1); |
2086 | 0 | if (*dst8 != *src8) |
2087 | 0 | av_freep(dst8); |
2088 | 0 | *dst8 = av_memdup(*src8, len); |
2089 | 0 | if (len && !*dst8) { |
2090 | 0 | *(int *)(dst8 + 1) = 0; |
2091 | 0 | return AVERROR(ENOMEM); |
2092 | 0 | } |
2093 | 0 | *(int *)(dst8 + 1) = len; |
2094 | 0 | } else if (type == AV_OPT_TYPE_CONST) { |
2095 | | // do nothing |
2096 | 0 | } else if (type == AV_OPT_TYPE_DICT) { |
2097 | 0 | const AVDictionary *sdict = *(const AVDictionary * const *)src; |
2098 | 0 | AVDictionary **ddictp = (AVDictionary **)dst; |
2099 | 0 | if (sdict != *ddictp) |
2100 | 0 | av_dict_free(ddictp); |
2101 | 0 | *ddictp = NULL; |
2102 | 0 | return av_dict_copy(ddictp, sdict, 0); |
2103 | 0 | } else if (type == AV_OPT_TYPE_CHLAYOUT) { |
2104 | 0 | if (dst != src) |
2105 | 0 | return av_channel_layout_copy(dst, src); |
2106 | 0 | } else if (opt_is_pod(type)) { |
2107 | 0 | size_t size = opt_type_desc[type].size; |
2108 | 0 | memcpy(dst, src, size); |
2109 | 0 | } else { |
2110 | 0 | av_log(logctx, AV_LOG_ERROR, "Unhandled option type: %d\n", type); |
2111 | 0 | return AVERROR(EINVAL); |
2112 | 0 | } |
2113 | | |
2114 | 0 | return 0; |
2115 | 0 | } |
2116 | | |
2117 | | static int opt_copy_array(void *logctx, const AVOption *o, |
2118 | | void **pdst, const void * const *psrc) |
2119 | 0 | { |
2120 | 0 | unsigned nb_elems = *opt_array_pcount(psrc); |
2121 | 0 | void *dst = NULL; |
2122 | 0 | int ret; |
2123 | |
|
2124 | 0 | if (*pdst == *psrc) { |
2125 | 0 | *pdst = NULL; |
2126 | 0 | *opt_array_pcount(pdst) = 0; |
2127 | 0 | } |
2128 | |
|
2129 | 0 | opt_free_array(o, pdst, opt_array_pcount(pdst)); |
2130 | |
|
2131 | 0 | dst = av_calloc(nb_elems, opt_type_desc[TYPE_BASE(o->type)].size); |
2132 | 0 | if (!dst) |
2133 | 0 | return AVERROR(ENOMEM); |
2134 | | |
2135 | 0 | for (unsigned i = 0; i < nb_elems; i++) { |
2136 | 0 | ret = opt_copy_elem(logctx, TYPE_BASE(o->type), |
2137 | 0 | opt_array_pelem(o, dst, i), |
2138 | 0 | opt_array_pelem(o, *(void**)psrc, i)); |
2139 | 0 | if (ret < 0) { |
2140 | 0 | opt_free_array(o, &dst, &nb_elems); |
2141 | 0 | return ret; |
2142 | 0 | } |
2143 | 0 | } |
2144 | | |
2145 | 0 | *pdst = dst; |
2146 | 0 | *opt_array_pcount(pdst) = nb_elems; |
2147 | |
|
2148 | 0 | return 0; |
2149 | 0 | } |
2150 | | |
2151 | | int av_opt_copy(void *dst, const void *src) |
2152 | 0 | { |
2153 | 0 | const AVOption *o = NULL; |
2154 | 0 | const AVClass *c; |
2155 | 0 | int ret = 0; |
2156 | |
|
2157 | 0 | if (!src) |
2158 | 0 | return AVERROR(EINVAL); |
2159 | | |
2160 | 0 | c = *(AVClass **)src; |
2161 | 0 | if (!c || c != *(AVClass **)dst) |
2162 | 0 | return AVERROR(EINVAL); |
2163 | | |
2164 | 0 | while ((o = av_opt_next(src, o))) { |
2165 | 0 | void *field_dst = (uint8_t *)dst + o->offset; |
2166 | 0 | void *field_src = (uint8_t *)src + o->offset; |
2167 | |
|
2168 | 0 | int err = (o->type & AV_OPT_TYPE_FLAG_ARRAY) ? |
2169 | 0 | opt_copy_array(dst, o, field_dst, field_src) : |
2170 | 0 | opt_copy_elem (dst, o->type, field_dst, field_src); |
2171 | 0 | if (err < 0) |
2172 | 0 | ret = err; |
2173 | 0 | } |
2174 | 0 | return ret; |
2175 | 0 | } |
2176 | | |
2177 | | int av_opt_get_array_size(void *obj, const char *name, int search_flags, |
2178 | | unsigned int *out_val) |
2179 | 0 | { |
2180 | 0 | void *target_obj, *parray; |
2181 | 0 | const AVOption *o; |
2182 | |
|
2183 | 0 | o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
2184 | 0 | if (!o || !target_obj) |
2185 | 0 | return AVERROR_OPTION_NOT_FOUND; |
2186 | 0 | if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY)) |
2187 | 0 | return AVERROR(EINVAL); |
2188 | | |
2189 | 0 | parray = (uint8_t *)target_obj + o->offset; |
2190 | 0 | *out_val = *opt_array_pcount(parray); |
2191 | |
|
2192 | 0 | return 0; |
2193 | 0 | } |
2194 | | |
2195 | | int av_opt_get_array(void *obj, const char *name, int search_flags, |
2196 | | unsigned int start_elem, unsigned int nb_elems, |
2197 | | enum AVOptionType out_type, void *out_val) |
2198 | 0 | { |
2199 | 0 | const size_t elem_size_out = opt_type_desc[TYPE_BASE(out_type)].size; |
2200 | |
|
2201 | 0 | const AVOption *o; |
2202 | 0 | void *target_obj; |
2203 | |
|
2204 | 0 | const void *parray; |
2205 | 0 | unsigned array_size; |
2206 | |
|
2207 | 0 | int ret; |
2208 | |
|
2209 | 0 | o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); |
2210 | 0 | if (!o || !target_obj) |
2211 | 0 | return AVERROR_OPTION_NOT_FOUND; |
2212 | 0 | if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || |
2213 | 0 | (out_type & AV_OPT_TYPE_FLAG_ARRAY)) |
2214 | 0 | return AVERROR(EINVAL); |
2215 | | |
2216 | 0 | parray = (uint8_t *)target_obj + o->offset; |
2217 | 0 | array_size = *opt_array_pcount(parray); |
2218 | |
|
2219 | 0 | if (start_elem >= array_size || |
2220 | 0 | array_size - start_elem < nb_elems) |
2221 | 0 | return AVERROR(EINVAL); |
2222 | | |
2223 | 0 | for (unsigned i = 0; i < nb_elems; i++) { |
2224 | 0 | const void *src = opt_array_pelem(o, *(void**)parray, start_elem + i); |
2225 | 0 | void *dst = (uint8_t*)out_val + i * elem_size_out; |
2226 | |
|
2227 | 0 | if (out_type == TYPE_BASE(o->type)) { |
2228 | 0 | ret = opt_copy_elem(obj, out_type, dst, src); |
2229 | 0 | if (ret < 0) |
2230 | 0 | goto fail; |
2231 | 0 | } else if (out_type == AV_OPT_TYPE_STRING) { |
2232 | 0 | uint8_t buf[128], *out = buf; |
2233 | |
|
2234 | 0 | ret = opt_get_elem(o, &out, sizeof(buf), src, search_flags); |
2235 | 0 | if (ret < 0) |
2236 | 0 | goto fail; |
2237 | | |
2238 | 0 | if (out == buf) { |
2239 | 0 | out = av_strdup(buf); |
2240 | 0 | if (!out) { |
2241 | 0 | ret = AVERROR(ENOMEM); |
2242 | 0 | goto fail; |
2243 | 0 | } |
2244 | 0 | } |
2245 | | |
2246 | 0 | *(uint8_t**)dst = out; |
2247 | 0 | } else if (out_type == AV_OPT_TYPE_INT64 || |
2248 | 0 | out_type == AV_OPT_TYPE_DOUBLE || |
2249 | 0 | out_type == AV_OPT_TYPE_RATIONAL) { |
2250 | 0 | double num = 1.0; |
2251 | 0 | int den = 1; |
2252 | 0 | int64_t intnum = 1; |
2253 | |
|
2254 | 0 | ret = read_number(o, src, &num, &den, &intnum); |
2255 | 0 | if (ret < 0) |
2256 | 0 | goto fail; |
2257 | | |
2258 | 0 | switch (out_type) { |
2259 | 0 | case AV_OPT_TYPE_INT64: |
2260 | 0 | *(int64_t*)dst = (num == den) ? intnum : num * intnum / den; |
2261 | 0 | break; |
2262 | 0 | case AV_OPT_TYPE_DOUBLE: |
2263 | 0 | *(double*)dst = num * intnum / den; |
2264 | 0 | break; |
2265 | 0 | case AV_OPT_TYPE_RATIONAL: |
2266 | 0 | *(AVRational*)dst = (num == 1.0 && (int)intnum == intnum) ? |
2267 | 0 | (AVRational){ intnum, den } : |
2268 | 0 | double_to_rational(num * intnum / den); |
2269 | 0 | break; |
2270 | 0 | default: av_assert0(0); |
2271 | 0 | } |
2272 | 0 | } else |
2273 | 0 | return AVERROR(ENOSYS); |
2274 | 0 | } |
2275 | | |
2276 | 0 | return 0; |
2277 | 0 | fail: |
2278 | 0 | for (unsigned i = 0; i < nb_elems; i++) |
2279 | 0 | opt_free_elem(out_type, (uint8_t*)out_val + i * elem_size_out); |
2280 | 0 | return ret; |
2281 | 0 | } |
2282 | | |
2283 | | int av_opt_set_array(void *obj, const char *name, int search_flags, |
2284 | | unsigned int start_elem, unsigned int nb_elems, |
2285 | | enum AVOptionType val_type, const void *val) |
2286 | 0 | { |
2287 | 0 | const size_t elem_size_val = opt_type_desc[TYPE_BASE(val_type)].size; |
2288 | |
|
2289 | 0 | const AVOption *o; |
2290 | 0 | const AVOptionArrayDef *arr; |
2291 | 0 | void *target_obj; |
2292 | |
|
2293 | 0 | void *parray; |
2294 | 0 | void *new_elems; |
2295 | 0 | unsigned *array_size, new_size; |
2296 | 0 | size_t elem_size; |
2297 | |
|
2298 | 0 | int ret = 0; |
2299 | |
|
2300 | 0 | ret = opt_set_init(obj, name, search_flags, 0, &target_obj, &o, &parray); |
2301 | 0 | if (ret < 0) |
2302 | 0 | return ret; |
2303 | | |
2304 | 0 | if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || |
2305 | 0 | (val_type & AV_OPT_TYPE_FLAG_ARRAY)) |
2306 | 0 | return AVERROR(EINVAL); |
2307 | | |
2308 | 0 | arr = o->default_val.arr; |
2309 | 0 | array_size = opt_array_pcount(parray); |
2310 | 0 | elem_size = opt_type_desc[TYPE_BASE(o->type)].size; |
2311 | |
|
2312 | 0 | if (start_elem > *array_size) |
2313 | 0 | return AVERROR(EINVAL); |
2314 | | |
2315 | | // compute new array size |
2316 | 0 | if (!val) { |
2317 | 0 | if (*array_size - start_elem < nb_elems) |
2318 | 0 | return AVERROR(EINVAL); |
2319 | | |
2320 | 0 | new_size = *array_size - nb_elems; |
2321 | 0 | } else if (search_flags & AV_OPT_ARRAY_REPLACE) { |
2322 | 0 | if (start_elem >= UINT_MAX - nb_elems) |
2323 | 0 | return AVERROR(EINVAL); |
2324 | | |
2325 | 0 | new_size = FFMAX(*array_size, start_elem + nb_elems); |
2326 | 0 | } else { |
2327 | 0 | if (nb_elems >= UINT_MAX - *array_size) |
2328 | 0 | return AVERROR(EINVAL); |
2329 | | |
2330 | 0 | new_size = *array_size + nb_elems; |
2331 | 0 | } |
2332 | | |
2333 | 0 | if (arr && |
2334 | 0 | ((arr->size_max && new_size > arr->size_max) || |
2335 | 0 | (arr->size_min && new_size < arr->size_min))) |
2336 | 0 | return AVERROR(EINVAL); |
2337 | | |
2338 | | // desired operation is shrinking the array |
2339 | 0 | if (!val) { |
2340 | 0 | void *array = *(void**)parray; |
2341 | |
|
2342 | 0 | for (unsigned i = 0; i < nb_elems; i++) { |
2343 | 0 | opt_free_elem(o->type, |
2344 | 0 | opt_array_pelem(o, array, start_elem + i)); |
2345 | 0 | } |
2346 | |
|
2347 | 0 | if (new_size > 0) { |
2348 | 0 | memmove(opt_array_pelem(o, array, start_elem), |
2349 | 0 | opt_array_pelem(o, array, start_elem + nb_elems), |
2350 | 0 | elem_size * (*array_size - start_elem - nb_elems)); |
2351 | |
|
2352 | 0 | array = av_realloc_array(array, new_size, elem_size); |
2353 | 0 | if (!array) |
2354 | 0 | return AVERROR(ENOMEM); |
2355 | | |
2356 | 0 | *(void**)parray = array; |
2357 | 0 | } else |
2358 | 0 | av_freep(parray); |
2359 | | |
2360 | 0 | *array_size = new_size; |
2361 | |
|
2362 | 0 | return 0; |
2363 | 0 | } |
2364 | | |
2365 | | // otherwise, desired operation is insert/replace; |
2366 | | // first, store new elements in a separate array to simplify |
2367 | | // rollback on failure |
2368 | 0 | new_elems = av_calloc(nb_elems, elem_size); |
2369 | 0 | if (!new_elems) |
2370 | 0 | return AVERROR(ENOMEM); |
2371 | | |
2372 | | // convert/validate each new element |
2373 | 0 | for (unsigned i = 0; i < nb_elems; i++) { |
2374 | 0 | void *dst = opt_array_pelem(o, new_elems, i); |
2375 | 0 | const void *src = (uint8_t*)val + i * elem_size_val; |
2376 | |
|
2377 | 0 | double num = 1.0; |
2378 | 0 | int den = 1; |
2379 | 0 | int64_t intnum = 1; |
2380 | |
|
2381 | 0 | if (val_type == TYPE_BASE(o->type)) { |
2382 | 0 | int err; |
2383 | |
|
2384 | 0 | ret = opt_copy_elem(obj, val_type, dst, src); |
2385 | 0 | if (ret < 0) |
2386 | 0 | goto fail; |
2387 | | |
2388 | | // validate the range for numeric options |
2389 | 0 | err = read_number(o, dst, &num, &den, &intnum); |
2390 | 0 | if (err >= 0 && TYPE_BASE(o->type) != AV_OPT_TYPE_FLAGS && |
2391 | 0 | (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { |
2392 | 0 | num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); |
2393 | 0 | av_log(obj, AV_LOG_ERROR, "Cannot set array element %u for " |
2394 | 0 | "parameter '%s': value %f out of range [%g - %g]\n", |
2395 | 0 | start_elem + i, o->name, num, o->min, o->max); |
2396 | 0 | ret = AVERROR(ERANGE); |
2397 | 0 | goto fail; |
2398 | 0 | } |
2399 | 0 | } else if (val_type == AV_OPT_TYPE_STRING) { |
2400 | 0 | ret = opt_set_elem(obj, target_obj, o, *(const char **)src, dst); |
2401 | 0 | if (ret < 0) |
2402 | 0 | goto fail; |
2403 | 0 | } else if (val_type == AV_OPT_TYPE_INT || |
2404 | 0 | val_type == AV_OPT_TYPE_INT64 || |
2405 | 0 | val_type == AV_OPT_TYPE_FLOAT || |
2406 | 0 | val_type == AV_OPT_TYPE_DOUBLE || |
2407 | 0 | val_type == AV_OPT_TYPE_RATIONAL) { |
2408 | |
|
2409 | 0 | switch (val_type) { |
2410 | 0 | case AV_OPT_TYPE_INT: intnum = *(int*)src; break; |
2411 | 0 | case AV_OPT_TYPE_INT64: intnum = *(int64_t*)src; break; |
2412 | 0 | case AV_OPT_TYPE_FLOAT: num = *(float*)src; break; |
2413 | 0 | case AV_OPT_TYPE_DOUBLE: num = *(double*)src; break; |
2414 | 0 | case AV_OPT_TYPE_RATIONAL: intnum = ((AVRational*)src)->num; |
2415 | 0 | den = ((AVRational*)src)->den; break; |
2416 | 0 | default: av_assert0(0); |
2417 | 0 | } |
2418 | | |
2419 | 0 | ret = write_number(obj, o, dst, num, den, intnum); |
2420 | 0 | if (ret < 0) |
2421 | 0 | goto fail; |
2422 | 0 | } else { |
2423 | 0 | ret = AVERROR(ENOSYS); |
2424 | 0 | goto fail; |
2425 | 0 | } |
2426 | 0 | } |
2427 | | |
2428 | | // commit new elements to the array |
2429 | 0 | if (start_elem == 0 && nb_elems == new_size) { |
2430 | | // replacing the existing array entirely |
2431 | 0 | opt_free_array(o, parray, array_size); |
2432 | 0 | *(void**)parray = new_elems; |
2433 | 0 | *array_size = nb_elems; |
2434 | |
|
2435 | 0 | new_elems = NULL; |
2436 | 0 | nb_elems = 0; |
2437 | 0 | } else { |
2438 | 0 | void *array = av_realloc_array(*(void**)parray, new_size, elem_size); |
2439 | 0 | if (!array) { |
2440 | 0 | ret = AVERROR(ENOMEM); |
2441 | 0 | goto fail; |
2442 | 0 | } |
2443 | | |
2444 | 0 | if (search_flags & AV_OPT_ARRAY_REPLACE) { |
2445 | | // free the elements being overwritten |
2446 | 0 | for (unsigned i = start_elem; i < FFMIN(start_elem + nb_elems, *array_size); i++) |
2447 | 0 | opt_free_elem(o->type, opt_array_pelem(o, array, i)); |
2448 | 0 | } else { |
2449 | | // shift existing elements to the end |
2450 | 0 | memmove(opt_array_pelem(o, array, start_elem + nb_elems), |
2451 | 0 | opt_array_pelem(o, array, start_elem), |
2452 | 0 | elem_size * (*array_size - start_elem)); |
2453 | 0 | } |
2454 | |
|
2455 | 0 | memcpy((uint8_t*)array + elem_size * start_elem, new_elems, elem_size * nb_elems); |
2456 | |
|
2457 | 0 | av_freep(&new_elems); |
2458 | 0 | nb_elems = 0; |
2459 | |
|
2460 | 0 | *(void**)parray = array; |
2461 | 0 | *array_size = new_size; |
2462 | 0 | } |
2463 | | |
2464 | 0 | fail: |
2465 | 0 | opt_free_array(o, &new_elems, &nb_elems); |
2466 | |
|
2467 | 0 | return ret; |
2468 | 0 | } |
2469 | | |
2470 | | int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) |
2471 | 0 | { |
2472 | 0 | int ret; |
2473 | 0 | const AVClass *c = *(AVClass**)obj; |
2474 | 0 | int (*callback)(AVOptionRanges **, void *obj, const char *key, int flags) = c->query_ranges; |
2475 | |
|
2476 | 0 | if (!callback) |
2477 | 0 | callback = av_opt_query_ranges_default; |
2478 | |
|
2479 | 0 | ret = callback(ranges_arg, obj, key, flags); |
2480 | 0 | if (ret >= 0) { |
2481 | 0 | if (!(flags & AV_OPT_MULTI_COMPONENT_RANGE)) |
2482 | 0 | ret = 1; |
2483 | 0 | (*ranges_arg)->nb_components = ret; |
2484 | 0 | } |
2485 | 0 | return ret; |
2486 | 0 | } |
2487 | | |
2488 | | int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) |
2489 | 0 | { |
2490 | 0 | AVOptionRanges *ranges = av_mallocz(sizeof(*ranges)); |
2491 | 0 | AVOptionRange **range_array = av_mallocz(sizeof(void*)); |
2492 | 0 | AVOptionRange *range = av_mallocz(sizeof(*range)); |
2493 | 0 | const AVOption *field = av_opt_find(obj, key, NULL, 0, flags); |
2494 | 0 | int ret; |
2495 | |
|
2496 | 0 | *ranges_arg = NULL; |
2497 | |
|
2498 | 0 | if (!ranges || !range || !range_array || !field) { |
2499 | 0 | ret = AVERROR(ENOMEM); |
2500 | 0 | goto fail; |
2501 | 0 | } |
2502 | | |
2503 | 0 | ranges->range = range_array; |
2504 | 0 | ranges->range[0] = range; |
2505 | 0 | ranges->nb_ranges = 1; |
2506 | 0 | ranges->nb_components = 1; |
2507 | 0 | range->is_range = 1; |
2508 | 0 | range->value_min = field->min; |
2509 | 0 | range->value_max = field->max; |
2510 | |
|
2511 | 0 | switch (field->type) { |
2512 | 0 | case AV_OPT_TYPE_BOOL: |
2513 | 0 | case AV_OPT_TYPE_INT: |
2514 | 0 | case AV_OPT_TYPE_UINT: |
2515 | 0 | case AV_OPT_TYPE_INT64: |
2516 | 0 | case AV_OPT_TYPE_UINT64: |
2517 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
2518 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
2519 | 0 | case AV_OPT_TYPE_FLOAT: |
2520 | 0 | case AV_OPT_TYPE_DOUBLE: |
2521 | 0 | case AV_OPT_TYPE_DURATION: |
2522 | 0 | case AV_OPT_TYPE_COLOR: |
2523 | 0 | break; |
2524 | 0 | case AV_OPT_TYPE_STRING: |
2525 | 0 | range->component_min = 0; |
2526 | 0 | range->component_max = 0x10FFFF; // max unicode value |
2527 | 0 | range->value_min = -1; |
2528 | 0 | range->value_max = INT_MAX; |
2529 | 0 | break; |
2530 | 0 | case AV_OPT_TYPE_RATIONAL: |
2531 | 0 | range->component_min = INT_MIN; |
2532 | 0 | range->component_max = INT_MAX; |
2533 | 0 | break; |
2534 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
2535 | 0 | range->component_min = 0; |
2536 | 0 | range->component_max = INT_MAX/128/8; |
2537 | 0 | range->value_min = 0; |
2538 | 0 | range->value_max = INT_MAX/8; |
2539 | 0 | break; |
2540 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
2541 | 0 | range->component_min = 1; |
2542 | 0 | range->component_max = INT_MAX; |
2543 | 0 | range->value_min = 1; |
2544 | 0 | range->value_max = INT_MAX; |
2545 | 0 | break; |
2546 | 0 | default: |
2547 | 0 | ret = AVERROR(ENOSYS); |
2548 | 0 | goto fail; |
2549 | 0 | } |
2550 | | |
2551 | 0 | *ranges_arg = ranges; |
2552 | 0 | return 1; |
2553 | 0 | fail: |
2554 | 0 | av_free(ranges); |
2555 | 0 | av_free(range); |
2556 | 0 | av_free(range_array); |
2557 | 0 | return ret; |
2558 | 0 | } |
2559 | | |
2560 | | void av_opt_freep_ranges(AVOptionRanges **rangesp) |
2561 | 0 | { |
2562 | 0 | int i; |
2563 | 0 | AVOptionRanges *ranges = *rangesp; |
2564 | |
|
2565 | 0 | if (!ranges) |
2566 | 0 | return; |
2567 | | |
2568 | 0 | for (i = 0; i < ranges->nb_ranges * ranges->nb_components; i++) { |
2569 | 0 | AVOptionRange *range = ranges->range[i]; |
2570 | 0 | if (range) { |
2571 | 0 | av_freep(&range->str); |
2572 | 0 | av_freep(&ranges->range[i]); |
2573 | 0 | } |
2574 | 0 | } |
2575 | 0 | av_freep(&ranges->range); |
2576 | 0 | av_freep(rangesp); |
2577 | 0 | } |
2578 | | |
2579 | | int av_opt_is_set_to_default(void *obj, const AVOption *o) |
2580 | 0 | { |
2581 | 0 | int64_t i64; |
2582 | 0 | double d; |
2583 | 0 | AVRational q; |
2584 | 0 | int ret, w, h; |
2585 | 0 | char *str; |
2586 | 0 | void *dst; |
2587 | |
|
2588 | 0 | if (!o || !obj) |
2589 | 0 | return AVERROR(EINVAL); |
2590 | | |
2591 | 0 | dst = ((uint8_t*)obj) + o->offset; |
2592 | |
|
2593 | 0 | if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { |
2594 | 0 | const char *def = o->default_val.arr ? o->default_val.arr->def : NULL; |
2595 | 0 | uint8_t *val; |
2596 | |
|
2597 | 0 | ret = opt_get_array(o, dst, &val); |
2598 | 0 | if (ret < 0) |
2599 | 0 | return ret; |
2600 | | |
2601 | 0 | if (!!val != !!def) |
2602 | 0 | ret = 0; |
2603 | 0 | else if (val) |
2604 | 0 | ret = !strcmp(val, def); |
2605 | 0 | else |
2606 | 0 | ret = 1; |
2607 | |
|
2608 | 0 | av_freep(&val); |
2609 | |
|
2610 | 0 | return ret; |
2611 | 0 | } |
2612 | | |
2613 | 0 | switch (o->type) { |
2614 | 0 | case AV_OPT_TYPE_CONST: |
2615 | 0 | return 1; |
2616 | 0 | case AV_OPT_TYPE_BOOL: |
2617 | 0 | case AV_OPT_TYPE_FLAGS: |
2618 | 0 | case AV_OPT_TYPE_PIXEL_FMT: |
2619 | 0 | case AV_OPT_TYPE_SAMPLE_FMT: |
2620 | 0 | case AV_OPT_TYPE_INT: |
2621 | 0 | case AV_OPT_TYPE_UINT: |
2622 | 0 | case AV_OPT_TYPE_DURATION: |
2623 | 0 | case AV_OPT_TYPE_INT64: |
2624 | 0 | case AV_OPT_TYPE_UINT64: |
2625 | 0 | read_number(o, dst, NULL, NULL, &i64); |
2626 | 0 | return o->default_val.i64 == i64; |
2627 | 0 | case AV_OPT_TYPE_CHLAYOUT: { |
2628 | 0 | AVChannelLayout ch_layout = { 0 }; |
2629 | 0 | if (o->default_val.str) { |
2630 | 0 | if ((ret = av_channel_layout_from_string(&ch_layout, o->default_val.str)) < 0) |
2631 | 0 | return ret; |
2632 | 0 | } |
2633 | 0 | ret = !av_channel_layout_compare((AVChannelLayout *)dst, &ch_layout); |
2634 | 0 | av_channel_layout_uninit(&ch_layout); |
2635 | 0 | return ret; |
2636 | 0 | } |
2637 | 0 | case AV_OPT_TYPE_STRING: |
2638 | 0 | str = *(char **)dst; |
2639 | 0 | if (str == o->default_val.str) //2 NULLs |
2640 | 0 | return 1; |
2641 | 0 | if (!str || !o->default_val.str) //1 NULL |
2642 | 0 | return 0; |
2643 | 0 | return !strcmp(str, o->default_val.str); |
2644 | 0 | case AV_OPT_TYPE_DOUBLE: |
2645 | 0 | d = *(double *)dst; |
2646 | 0 | return o->default_val.dbl == d; |
2647 | 0 | case AV_OPT_TYPE_FLOAT: |
2648 | 0 | d = *(float *)dst; |
2649 | 0 | return (float)o->default_val.dbl == d; |
2650 | 0 | case AV_OPT_TYPE_RATIONAL: |
2651 | 0 | q = av_d2q(o->default_val.dbl, INT_MAX); |
2652 | 0 | return !av_cmp_q(*(AVRational*)dst, q); |
2653 | 0 | case AV_OPT_TYPE_BINARY: { |
2654 | 0 | struct { |
2655 | 0 | uint8_t *data; |
2656 | 0 | int size; |
2657 | 0 | } tmp = {0}; |
2658 | 0 | int opt_size = *(int *)((void **)dst + 1); |
2659 | 0 | void *opt_ptr = *(void **)dst; |
2660 | 0 | if (!opt_size && (!o->default_val.str || !strlen(o->default_val.str))) |
2661 | 0 | return 1; |
2662 | 0 | if (!opt_size || !o->default_val.str || !strlen(o->default_val.str )) |
2663 | 0 | return 0; |
2664 | 0 | if (opt_size != strlen(o->default_val.str) / 2) |
2665 | 0 | return 0; |
2666 | 0 | ret = set_string_binary(NULL, NULL, o->default_val.str, &tmp.data); |
2667 | 0 | if (!ret) |
2668 | 0 | ret = !memcmp(opt_ptr, tmp.data, tmp.size); |
2669 | 0 | av_free(tmp.data); |
2670 | 0 | return ret; |
2671 | 0 | } |
2672 | 0 | case AV_OPT_TYPE_DICT: { |
2673 | 0 | AVDictionary *dict1 = NULL; |
2674 | 0 | AVDictionary *dict2 = *(AVDictionary **)dst; |
2675 | 0 | const AVDictionaryEntry *en1 = NULL; |
2676 | 0 | const AVDictionaryEntry *en2 = NULL; |
2677 | 0 | ret = av_dict_parse_string(&dict1, o->default_val.str, "=", ":", 0); |
2678 | 0 | if (ret < 0) { |
2679 | 0 | av_dict_free(&dict1); |
2680 | 0 | return ret; |
2681 | 0 | } |
2682 | 0 | do { |
2683 | 0 | en1 = av_dict_iterate(dict1, en1); |
2684 | 0 | en2 = av_dict_iterate(dict2, en2); |
2685 | 0 | } while (en1 && en2 && !strcmp(en1->key, en2->key) && !strcmp(en1->value, en2->value)); |
2686 | 0 | av_dict_free(&dict1); |
2687 | 0 | return (!en1 && !en2); |
2688 | 0 | } |
2689 | 0 | case AV_OPT_TYPE_IMAGE_SIZE: |
2690 | 0 | if (!o->default_val.str || !strcmp(o->default_val.str, "none")) |
2691 | 0 | w = h = 0; |
2692 | 0 | else if ((ret = av_parse_video_size(&w, &h, o->default_val.str)) < 0) |
2693 | 0 | return ret; |
2694 | 0 | return (w == *(int *)dst) && (h == *((int *)dst+1)); |
2695 | 0 | case AV_OPT_TYPE_VIDEO_RATE: |
2696 | 0 | q = (AVRational){0, 0}; |
2697 | 0 | if (o->default_val.str) { |
2698 | 0 | if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0) |
2699 | 0 | return ret; |
2700 | 0 | } |
2701 | 0 | return !av_cmp_q(*(AVRational*)dst, q); |
2702 | 0 | case AV_OPT_TYPE_COLOR: { |
2703 | 0 | uint8_t color[4] = {0, 0, 0, 0}; |
2704 | 0 | if (o->default_val.str) { |
2705 | 0 | if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0) |
2706 | 0 | return ret; |
2707 | 0 | } |
2708 | 0 | return !memcmp(color, dst, sizeof(color)); |
2709 | 0 | } |
2710 | 0 | default: |
2711 | 0 | av_log(obj, AV_LOG_WARNING, "Not supported option type: %d, option name: %s\n", o->type, o->name); |
2712 | 0 | break; |
2713 | 0 | } |
2714 | 0 | return AVERROR_PATCHWELCOME; |
2715 | 0 | } |
2716 | | |
2717 | | int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags) |
2718 | 0 | { |
2719 | 0 | const AVOption *o; |
2720 | 0 | void *target; |
2721 | 0 | if (!obj) |
2722 | 0 | return AVERROR(EINVAL); |
2723 | 0 | o = av_opt_find2(obj, name, NULL, 0, search_flags, &target); |
2724 | 0 | if (!o) |
2725 | 0 | return AVERROR_OPTION_NOT_FOUND; |
2726 | 0 | return av_opt_is_set_to_default(target, o); |
2727 | 0 | } |
2728 | | |
2729 | | static int opt_serialize(void *obj, int opt_flags, int flags, int *cnt, |
2730 | | AVBPrint *bprint, const char key_val_sep, const char pairs_sep) |
2731 | 0 | { |
2732 | 0 | const AVOption *o = NULL; |
2733 | 0 | void *child = NULL; |
2734 | 0 | uint8_t *buf; |
2735 | 0 | int ret; |
2736 | 0 | const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; |
2737 | |
|
2738 | 0 | if (flags & AV_OPT_SERIALIZE_SEARCH_CHILDREN) |
2739 | 0 | while (child = av_opt_child_next(obj, child)) { |
2740 | 0 | ret = opt_serialize(child, opt_flags, flags, cnt, bprint, |
2741 | 0 | key_val_sep, pairs_sep); |
2742 | 0 | if (ret < 0) |
2743 | 0 | return ret; |
2744 | 0 | } |
2745 | | |
2746 | 0 | while (o = av_opt_next(obj, o)) { |
2747 | 0 | if (o->type == AV_OPT_TYPE_CONST) |
2748 | 0 | continue; |
2749 | 0 | if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) |
2750 | 0 | continue; |
2751 | 0 | else if (((o->flags & opt_flags) != opt_flags)) |
2752 | 0 | continue; |
2753 | 0 | if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0) |
2754 | 0 | continue; |
2755 | 0 | if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { |
2756 | 0 | av_bprint_finalize(bprint, NULL); |
2757 | 0 | return ret; |
2758 | 0 | } |
2759 | 0 | if (buf) { |
2760 | 0 | if ((*cnt)++) |
2761 | 0 | av_bprint_append_data(bprint, &pairs_sep, 1); |
2762 | 0 | av_bprint_escape(bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); |
2763 | 0 | av_bprint_append_data(bprint, &key_val_sep, 1); |
2764 | 0 | av_bprint_escape(bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); |
2765 | 0 | av_freep(&buf); |
2766 | 0 | } |
2767 | 0 | } |
2768 | | |
2769 | 0 | return 0; |
2770 | 0 | } |
2771 | | |
2772 | | int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, |
2773 | | const char key_val_sep, const char pairs_sep) |
2774 | 0 | { |
2775 | 0 | AVBPrint bprint; |
2776 | 0 | int ret, cnt = 0; |
2777 | |
|
2778 | 0 | if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || |
2779 | 0 | pairs_sep == '\\' || key_val_sep == '\\') { |
2780 | 0 | av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found."); |
2781 | 0 | return AVERROR(EINVAL); |
2782 | 0 | } |
2783 | | |
2784 | 0 | if (!obj || !buffer) |
2785 | 0 | return AVERROR(EINVAL); |
2786 | | |
2787 | 0 | *buffer = NULL; |
2788 | 0 | av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); |
2789 | |
|
2790 | 0 | ret = opt_serialize(obj, opt_flags, flags, &cnt, &bprint, |
2791 | 0 | key_val_sep, pairs_sep); |
2792 | 0 | if (ret < 0) |
2793 | 0 | return ret; |
2794 | | |
2795 | 0 | ret = av_bprint_finalize(&bprint, buffer); |
2796 | 0 | if (ret < 0) |
2797 | 0 | return ret; |
2798 | 0 | return 0; |
2799 | 0 | } |