summaryrefslogtreecommitdiff
path: root/libavfilter/formats.c (plain)
blob: d4de86223750373006311fa058147c6ddee85ad7
1/*
2 * Filter layer - format negotiation
3 * Copyright (c) 2007 Bobby Bingham
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#include "libavutil/avassert.h"
23#include "libavutil/channel_layout.h"
24#include "libavutil/common.h"
25#include "libavutil/eval.h"
26#include "libavutil/pixdesc.h"
27#include "libavutil/parseutils.h"
28#include "avfilter.h"
29#include "internal.h"
30#include "formats.h"
31
32#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */
33
34/**
35 * Add all refs from a to ret and destroy a.
36 */
37#define MERGE_REF(ret, a, fmts, type, fail) \
38do { \
39 type ***tmp; \
40 int i; \
41 \
42 if (!(tmp = av_realloc_array(ret->refs, ret->refcount + a->refcount, \
43 sizeof(*tmp)))) \
44 goto fail; \
45 ret->refs = tmp; \
46 \
47 for (i = 0; i < a->refcount; i ++) { \
48 ret->refs[ret->refcount] = a->refs[i]; \
49 *ret->refs[ret->refcount++] = ret; \
50 } \
51 \
52 av_freep(&a->refs); \
53 av_freep(&a->fmts); \
54 av_freep(&a); \
55} while (0)
56
57/**
58 * Add all formats common for a and b to ret, copy the refs and destroy
59 * a and b.
60 */
61#define MERGE_FORMATS(ret, a, b, fmts, nb, type, fail) \
62do { \
63 int i, j, k = 0, count = FFMIN(a->nb, b->nb); \
64 \
65 if (!(ret = av_mallocz(sizeof(*ret)))) \
66 goto fail; \
67 \
68 if (count) { \
69 if (!(ret->fmts = av_malloc_array(count, sizeof(*ret->fmts)))) \
70 goto fail; \
71 for (i = 0; i < a->nb; i++) \
72 for (j = 0; j < b->nb; j++) \
73 if (a->fmts[i] == b->fmts[j]) { \
74 if(k >= FFMIN(a->nb, b->nb)){ \
75 av_log(NULL, AV_LOG_ERROR, "Duplicate formats in avfilter_merge_formats() detected\n"); \
76 av_free(ret->fmts); \
77 av_free(ret); \
78 return NULL; \
79 } \
80 ret->fmts[k++] = a->fmts[i]; \
81 } \
82 } \
83 ret->nb = k; \
84 /* check that there was at least one common format */ \
85 if (!ret->nb) \
86 goto fail; \
87 \
88 MERGE_REF(ret, a, fmts, type, fail); \
89 MERGE_REF(ret, b, fmts, type, fail); \
90} while (0)
91
92AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b,
93 enum AVMediaType type)
94{
95 AVFilterFormats *ret = NULL;
96 int i, j;
97 int alpha1=0, alpha2=0;
98 int chroma1=0, chroma2=0;
99
100 if (a == b)
101 return a;
102
103 /* Do not lose chroma or alpha in merging.
104 It happens if both lists have formats with chroma (resp. alpha), but
105 the only formats in common do not have it (e.g. YUV+gray vs.
106 RGB+gray): in that case, the merging would select the gray format,
107 possibly causing a lossy conversion elsewhere in the graph.
108 To avoid that, pretend that there are no common formats to force the
109 insertion of a conversion filter. */
110 if (type == AVMEDIA_TYPE_VIDEO)
111 for (i = 0; i < a->nb_formats; i++)
112 for (j = 0; j < b->nb_formats; j++) {
113 const AVPixFmtDescriptor *adesc = av_pix_fmt_desc_get(a->formats[i]);
114 const AVPixFmtDescriptor *bdesc = av_pix_fmt_desc_get(b->formats[j]);
115 alpha2 |= adesc->flags & bdesc->flags & AV_PIX_FMT_FLAG_ALPHA;
116 chroma2|= adesc->nb_components > 1 && bdesc->nb_components > 1;
117 if (a->formats[i] == b->formats[j]) {
118 alpha1 |= adesc->flags & AV_PIX_FMT_FLAG_ALPHA;
119 chroma1|= adesc->nb_components > 1;
120 }
121 }
122
123 // If chroma or alpha can be lost through merging then do not merge
124 if (alpha2 > alpha1 || chroma2 > chroma1)
125 return NULL;
126
127 MERGE_FORMATS(ret, a, b, formats, nb_formats, AVFilterFormats, fail);
128
129 return ret;
130fail:
131 if (ret) {
132 av_freep(&ret->refs);
133 av_freep(&ret->formats);
134 }
135 av_freep(&ret);
136 return NULL;
137}
138
139AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a,
140 AVFilterFormats *b)
141{
142 AVFilterFormats *ret = NULL;
143
144 if (a == b) return a;
145
146 if (a->nb_formats && b->nb_formats) {
147 MERGE_FORMATS(ret, a, b, formats, nb_formats, AVFilterFormats, fail);
148 } else if (a->nb_formats) {
149 MERGE_REF(a, b, formats, AVFilterFormats, fail);
150 ret = a;
151 } else {
152 MERGE_REF(b, a, formats, AVFilterFormats, fail);
153 ret = b;
154 }
155
156 return ret;
157fail:
158 if (ret) {
159 av_freep(&ret->refs);
160 av_freep(&ret->formats);
161 }
162 av_freep(&ret);
163 return NULL;
164}
165
166AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a,
167 AVFilterChannelLayouts *b)
168{
169 AVFilterChannelLayouts *ret = NULL;
170 unsigned a_all = a->all_layouts + a->all_counts;
171 unsigned b_all = b->all_layouts + b->all_counts;
172 int ret_max, ret_nb = 0, i, j, round;
173
174 if (a == b) return a;
175
176 /* Put the most generic set in a, to avoid doing everything twice */
177 if (a_all < b_all) {
178 FFSWAP(AVFilterChannelLayouts *, a, b);
179 FFSWAP(unsigned, a_all, b_all);
180 }
181 if (a_all) {
182 if (a_all == 1 && !b_all) {
183 /* keep only known layouts in b; works also for b_all = 1 */
184 for (i = j = 0; i < b->nb_channel_layouts; i++)
185 if (KNOWN(b->channel_layouts[i]))
186 b->channel_layouts[j++] = b->channel_layouts[i];
187 /* Not optimal: the unknown layouts of b may become known after
188 another merge. */
189 if (!j)
190 return NULL;
191 b->nb_channel_layouts = j;
192 }
193 MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, fail);
194 return b;
195 }
196
197 ret_max = a->nb_channel_layouts + b->nb_channel_layouts;
198 if (!(ret = av_mallocz(sizeof(*ret))) ||
199 !(ret->channel_layouts = av_malloc_array(ret_max,
200 sizeof(*ret->channel_layouts))))
201 goto fail;
202
203 /* a[known] intersect b[known] */
204 for (i = 0; i < a->nb_channel_layouts; i++) {
205 if (!KNOWN(a->channel_layouts[i]))
206 continue;
207 for (j = 0; j < b->nb_channel_layouts; j++) {
208 if (a->channel_layouts[i] == b->channel_layouts[j]) {
209 ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
210 a->channel_layouts[i] = b->channel_layouts[j] = 0;
211 }
212 }
213 }
214 /* 1st round: a[known] intersect b[generic]
215 2nd round: a[generic] intersect b[known] */
216 for (round = 0; round < 2; round++) {
217 for (i = 0; i < a->nb_channel_layouts; i++) {
218 uint64_t fmt = a->channel_layouts[i], bfmt;
219 if (!fmt || !KNOWN(fmt))
220 continue;
221 bfmt = FF_COUNT2LAYOUT(av_get_channel_layout_nb_channels(fmt));
222 for (j = 0; j < b->nb_channel_layouts; j++)
223 if (b->channel_layouts[j] == bfmt)
224 ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
225 }
226 /* 1st round: swap to prepare 2nd round; 2nd round: put it back */
227 FFSWAP(AVFilterChannelLayouts *, a, b);
228 }
229 /* a[generic] intersect b[generic] */
230 for (i = 0; i < a->nb_channel_layouts; i++) {
231 if (KNOWN(a->channel_layouts[i]))
232 continue;
233 for (j = 0; j < b->nb_channel_layouts; j++)
234 if (a->channel_layouts[i] == b->channel_layouts[j])
235 ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
236 }
237
238 ret->nb_channel_layouts = ret_nb;
239 if (!ret->nb_channel_layouts)
240 goto fail;
241 MERGE_REF(ret, a, channel_layouts, AVFilterChannelLayouts, fail);
242 MERGE_REF(ret, b, channel_layouts, AVFilterChannelLayouts, fail);
243 return ret;
244
245fail:
246 if (ret) {
247 av_freep(&ret->refs);
248 av_freep(&ret->channel_layouts);
249 }
250 av_freep(&ret);
251 return NULL;
252}
253
254int ff_fmt_is_in(int fmt, const int *fmts)
255{
256 const int *p;
257
258 for (p = fmts; *p != -1; p++) {
259 if (fmt == *p)
260 return 1;
261 }
262 return 0;
263}
264
265#define MAKE_FORMAT_LIST(type, field, count_field) \
266 type *formats; \
267 int count = 0; \
268 if (fmts) \
269 for (count = 0; fmts[count] != -1; count++) \
270 ; \
271 formats = av_mallocz(sizeof(*formats)); \
272 if (!formats) \
273 return NULL; \
274 formats->count_field = count; \
275 if (count) { \
276 formats->field = av_malloc_array(count, sizeof(*formats->field)); \
277 if (!formats->field) { \
278 av_freep(&formats); \
279 return NULL; \
280 } \
281 }
282
283AVFilterFormats *ff_make_format_list(const int *fmts)
284{
285 MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
286 while (count--)
287 formats->formats[count] = fmts[count];
288
289 return formats;
290}
291
292AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
293{
294 MAKE_FORMAT_LIST(AVFilterChannelLayouts,
295 channel_layouts, nb_channel_layouts);
296 if (count)
297 memcpy(formats->channel_layouts, fmts,
298 sizeof(*formats->channel_layouts) * count);
299
300 return formats;
301}
302
303AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
304{
305 MAKE_FORMAT_LIST(AVFilterChannelLayouts,
306 channel_layouts, nb_channel_layouts);
307 if (count)
308 memcpy(formats->channel_layouts, fmts,
309 sizeof(*formats->channel_layouts) * count);
310
311 return formats;
312}
313
314#define ADD_FORMAT(f, fmt, unref_fn, type, list, nb) \
315do { \
316 type *fmts; \
317 void *oldf = *f; \
318 \
319 if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) { \
320 unref_fn(f); \
321 return AVERROR(ENOMEM); \
322 } \
323 \
324 fmts = av_realloc_array((*f)->list, (*f)->nb + 1, \
325 sizeof(*(*f)->list)); \
326 if (!fmts) { \
327 unref_fn(f); \
328 if (!oldf) \
329 av_freep(f); \
330 return AVERROR(ENOMEM); \
331 } \
332 \
333 (*f)->list = fmts; \
334 (*f)->list[(*f)->nb++] = fmt; \
335} while (0)
336
337int ff_add_format(AVFilterFormats **avff, int64_t fmt)
338{
339 ADD_FORMAT(avff, fmt, ff_formats_unref, int, formats, nb_formats);
340 return 0;
341}
342
343int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
344{
345 av_assert1(!(*l && (*l)->all_layouts));
346 ADD_FORMAT(l, channel_layout, ff_channel_layouts_unref, uint64_t, channel_layouts, nb_channel_layouts);
347 return 0;
348}
349
350AVFilterFormats *ff_all_formats(enum AVMediaType type)
351{
352 AVFilterFormats *ret = NULL;
353
354 if (type == AVMEDIA_TYPE_VIDEO) {
355 const AVPixFmtDescriptor *desc = NULL;
356 while ((desc = av_pix_fmt_desc_next(desc))) {
357 if (ff_add_format(&ret, av_pix_fmt_desc_get_id(desc)) < 0)
358 return NULL;
359 }
360 } else if (type == AVMEDIA_TYPE_AUDIO) {
361 enum AVSampleFormat fmt = 0;
362 while (av_get_sample_fmt_name(fmt)) {
363 if (ff_add_format(&ret, fmt) < 0)
364 return NULL;
365 fmt++;
366 }
367 }
368
369 return ret;
370}
371
372const int64_t avfilter_all_channel_layouts[] = {
373#include "all_channel_layouts.inc"
374 -1
375};
376
377// AVFilterFormats *avfilter_make_all_channel_layouts(void)
378// {
379// return avfilter_make_format64_list(avfilter_all_channel_layouts);
380// }
381
382AVFilterFormats *ff_planar_sample_fmts(void)
383{
384 AVFilterFormats *ret = NULL;
385 int fmt;
386
387 for (fmt = 0; av_get_bytes_per_sample(fmt)>0; fmt++)
388 if (av_sample_fmt_is_planar(fmt))
389 if (ff_add_format(&ret, fmt) < 0)
390 return NULL;
391
392 return ret;
393}
394
395AVFilterFormats *ff_all_samplerates(void)
396{
397 AVFilterFormats *ret = av_mallocz(sizeof(*ret));
398 return ret;
399}
400
401AVFilterChannelLayouts *ff_all_channel_layouts(void)
402{
403 AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
404 if (!ret)
405 return NULL;
406 ret->all_layouts = 1;
407 return ret;
408}
409
410AVFilterChannelLayouts *ff_all_channel_counts(void)
411{
412 AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
413 if (!ret)
414 return NULL;
415 ret->all_layouts = ret->all_counts = 1;
416 return ret;
417}
418
419#define FORMATS_REF(f, ref, unref_fn) \
420 void *tmp; \
421 \
422 if (!f || !ref) \
423 return AVERROR(ENOMEM); \
424 \
425 tmp = av_realloc_array(f->refs, sizeof(*f->refs), f->refcount + 1); \
426 if (!tmp) { \
427 unref_fn(&f); \
428 return AVERROR(ENOMEM); \
429 } \
430 f->refs = tmp; \
431 f->refs[f->refcount++] = ref; \
432 *ref = f; \
433 return 0
434
435int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
436{
437 FORMATS_REF(f, ref, ff_channel_layouts_unref);
438}
439
440int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
441{
442 FORMATS_REF(f, ref, ff_formats_unref);
443}
444
445#define FIND_REF_INDEX(ref, idx) \
446do { \
447 int i; \
448 for (i = 0; i < (*ref)->refcount; i ++) \
449 if((*ref)->refs[i] == ref) { \
450 idx = i; \
451 break; \
452 } \
453} while (0)
454
455#define FORMATS_UNREF(ref, list) \
456do { \
457 int idx = -1; \
458 \
459 if (!*ref || !(*ref)->refs) \
460 return; \
461 \
462 FIND_REF_INDEX(ref, idx); \
463 \
464 if (idx >= 0) \
465 memmove((*ref)->refs + idx, (*ref)->refs + idx + 1, \
466 sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); \
467 \
468 if(!--(*ref)->refcount) { \
469 av_free((*ref)->list); \
470 av_free((*ref)->refs); \
471 av_free(*ref); \
472 } \
473 *ref = NULL; \
474} while (0)
475
476void ff_formats_unref(AVFilterFormats **ref)
477{
478 FORMATS_UNREF(ref, formats);
479}
480
481void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
482{
483 FORMATS_UNREF(ref, channel_layouts);
484}
485
486#define FORMATS_CHANGEREF(oldref, newref) \
487do { \
488 int idx = -1; \
489 \
490 FIND_REF_INDEX(oldref, idx); \
491 \
492 if (idx >= 0) { \
493 (*oldref)->refs[idx] = newref; \
494 *newref = *oldref; \
495 *oldref = NULL; \
496 } \
497} while (0)
498
499void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
500 AVFilterChannelLayouts **newref)
501{
502 FORMATS_CHANGEREF(oldref, newref);
503}
504
505void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
506{
507 FORMATS_CHANGEREF(oldref, newref);
508}
509
510#define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref_fn, unref_fn, list) \
511 int count = 0, i; \
512 \
513 if (!fmts) \
514 return AVERROR(ENOMEM); \
515 \
516 for (i = 0; i < ctx->nb_inputs; i++) { \
517 if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) { \
518 int ret = ref_fn(fmts, &ctx->inputs[i]->out_fmts); \
519 if (ret < 0) { \
520 unref_fn(&fmts); \
521 av_freep(&fmts->list); \
522 av_freep(&fmts); \
523 return ret; \
524 } \
525 count++; \
526 } \
527 } \
528 for (i = 0; i < ctx->nb_outputs; i++) { \
529 if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) { \
530 int ret = ref_fn(fmts, &ctx->outputs[i]->in_fmts); \
531 if (ret < 0) { \
532 unref_fn(&fmts); \
533 av_freep(&fmts->list); \
534 av_freep(&fmts); \
535 return ret; \
536 } \
537 count++; \
538 } \
539 } \
540 \
541 if (!count) { \
542 av_freep(&fmts->list); \
543 av_freep(&fmts->refs); \
544 av_freep(&fmts); \
545 } \
546 \
547 return 0;
548
549int ff_set_common_channel_layouts(AVFilterContext *ctx,
550 AVFilterChannelLayouts *layouts)
551{
552 SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts,
553 ff_channel_layouts_ref, ff_channel_layouts_unref, channel_layouts);
554}
555
556int ff_set_common_samplerates(AVFilterContext *ctx,
557 AVFilterFormats *samplerates)
558{
559 SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates,
560 ff_formats_ref, ff_formats_unref, formats);
561}
562
563/**
564 * A helper for query_formats() which sets all links to the same list of
565 * formats. If there are no links hooked to this filter, the list of formats is
566 * freed.
567 */
568int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
569{
570 SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats,
571 ff_formats_ref, ff_formats_unref, formats);
572}
573
574static int default_query_formats_common(AVFilterContext *ctx,
575 AVFilterChannelLayouts *(layouts)(void))
576{
577 int ret;
578 enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
579 ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
580 AVMEDIA_TYPE_VIDEO;
581
582 ret = ff_set_common_formats(ctx, ff_all_formats(type));
583 if (ret < 0)
584 return ret;
585 if (type == AVMEDIA_TYPE_AUDIO) {
586 ret = ff_set_common_channel_layouts(ctx, layouts());
587 if (ret < 0)
588 return ret;
589 ret = ff_set_common_samplerates(ctx, ff_all_samplerates());
590 if (ret < 0)
591 return ret;
592 }
593
594 return 0;
595}
596
597int ff_default_query_formats(AVFilterContext *ctx)
598{
599 return default_query_formats_common(ctx, ff_all_channel_counts);
600}
601
602int ff_query_formats_all_layouts(AVFilterContext *ctx)
603{
604 return default_query_formats_common(ctx, ff_all_channel_layouts);
605}
606
607/* internal functions for parsing audio format arguments */
608
609int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx)
610{
611 char *tail;
612 int pix_fmt = av_get_pix_fmt(arg);
613 if (pix_fmt == AV_PIX_FMT_NONE) {
614 pix_fmt = strtol(arg, &tail, 0);
615 if (*tail || !av_pix_fmt_desc_get(pix_fmt)) {
616 av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg);
617 return AVERROR(EINVAL);
618 }
619 }
620 *ret = pix_fmt;
621 return 0;
622}
623
624int ff_parse_sample_format(int *ret, const char *arg, void *log_ctx)
625{
626 char *tail;
627 int sfmt = av_get_sample_fmt(arg);
628 if (sfmt == AV_SAMPLE_FMT_NONE) {
629 sfmt = strtol(arg, &tail, 0);
630 if (*tail || av_get_bytes_per_sample(sfmt)<=0) {
631 av_log(log_ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg);
632 return AVERROR(EINVAL);
633 }
634 }
635 *ret = sfmt;
636 return 0;
637}
638
639int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx)
640{
641 AVRational r;
642 if(av_parse_ratio(&r, arg, INT_MAX, 0, log_ctx) < 0 ||r.num<=0 ||r.den<=0) {
643 av_log(log_ctx, AV_LOG_ERROR, "Invalid time base '%s'\n", arg);
644 return AVERROR(EINVAL);
645 }
646 *ret = r;
647 return 0;
648}
649
650int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
651{
652 char *tail;
653 double srate = av_strtod(arg, &tail);
654 if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) {
655 av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg);
656 return AVERROR(EINVAL);
657 }
658 *ret = srate;
659 return 0;
660}
661
662int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
663 void *log_ctx)
664{
665 char *tail;
666 int64_t chlayout;
667 int nb_channels;
668
669 if (av_get_extended_channel_layout(arg, &chlayout, &nb_channels) < 0) {
670 /* [TEMPORARY 2016-12 -> 2017-12]*/
671 nb_channels = strtol(arg, &tail, 10);
672 if (!errno && *tail == 'c' && *(tail + 1) == '\0' && nb_channels > 0 && nb_channels < 64) {
673 chlayout = 0;
674 av_log(log_ctx, AV_LOG_WARNING, "Deprecated channel count specification '%s'. This will stop working in releases made in 2018 and after.\n", arg);
675 } else {
676 av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
677 return AVERROR(EINVAL);
678 }
679 }
680 if (!chlayout && !nret) {
681 av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg);
682 return AVERROR(EINVAL);
683 }
684 *ret = chlayout;
685 if (nret)
686 *nret = nb_channels;
687
688 return 0;
689}
690