]> git.sesse.net Git - ffmpeg/blob - libavfilter/formats.c
avformat/mpegts: Fix potential pointer overflows
[ffmpeg] / libavfilter / formats.c
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)                                \
38 do {                                                                       \
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)                          \
62 do {                                                                            \
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
92 AVFilterFormats *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;
130 fail:
131     if (ret) {
132         av_freep(&ret->refs);
133         av_freep(&ret->formats);
134     }
135     av_freep(&ret);
136     return NULL;
137 }
138
139 AVFilterFormats *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;
157 fail:
158     if (ret) {
159         av_freep(&ret->refs);
160         av_freep(&ret->formats);
161     }
162     av_freep(&ret);
163     return NULL;
164 }
165
166 AVFilterChannelLayouts *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
245 fail:
246     if (ret) {
247         av_freep(&ret->refs);
248         av_freep(&ret->channel_layouts);
249     }
250     av_freep(&ret);
251     return NULL;
252 }
253
254 int 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 COPY_INT_LIST(list_copy, list, type) {                          \
266     int count = 0;                                                      \
267     if (list)                                                           \
268         for (count = 0; list[count] != -1; count++)                     \
269             ;                                                           \
270     list_copy = av_calloc(count+1, sizeof(type));                       \
271     if (list_copy) {                                                    \
272         memcpy(list_copy, list, sizeof(type) * count);                  \
273         list_copy[count] = -1;                                          \
274     }                                                                   \
275 }
276
277 #define MAKE_FORMAT_LIST(type, field, count_field)                      \
278     type *formats;                                                      \
279     int count = 0;                                                      \
280     if (fmts)                                                           \
281         for (count = 0; fmts[count] != -1; count++)                     \
282             ;                                                           \
283     formats = av_mallocz(sizeof(*formats));                             \
284     if (!formats)                                                       \
285         return NULL;                                                    \
286     formats->count_field = count;                                       \
287     if (count) {                                                        \
288         formats->field = av_malloc_array(count, sizeof(*formats->field));      \
289         if (!formats->field) {                                          \
290             av_freep(&formats);                                         \
291             return NULL;                                                \
292         }                                                               \
293     }
294
295 AVFilterFormats *ff_make_format_list(const int *fmts)
296 {
297     MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
298     while (count--)
299         formats->formats[count] = fmts[count];
300
301     return formats;
302 }
303
304 AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
305 {
306     MAKE_FORMAT_LIST(AVFilterChannelLayouts,
307                      channel_layouts, nb_channel_layouts);
308     if (count)
309         memcpy(formats->channel_layouts, fmts,
310                sizeof(*formats->channel_layouts) * count);
311
312     return formats;
313 }
314
315 #define ADD_FORMAT(f, fmt, type, list, nb)                  \
316 do {                                                        \
317     type *fmts;                                             \
318     void *oldf = *f;                                        \
319                                                             \
320     if (!(*f) && !(*f = av_mallocz(sizeof(**f))))           \
321         return AVERROR(ENOMEM);                             \
322                                                             \
323     fmts = av_realloc((*f)->list,                           \
324                       sizeof(*(*f)->list) * ((*f)->nb + 1));\
325     if (!fmts) {                                            \
326         if (!oldf)                                          \
327             av_freep(f);                                    \
328         return AVERROR(ENOMEM);                             \
329     }                                                       \
330                                                             \
331     (*f)->list = fmts;                                      \
332     (*f)->list[(*f)->nb++] = fmt;                           \
333 } while (0)
334
335 int ff_add_format(AVFilterFormats **avff, int64_t fmt)
336 {
337     ADD_FORMAT(avff, fmt, int, formats, nb_formats);
338     return 0;
339 }
340
341 int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
342 {
343     av_assert1(!(*l && (*l)->all_layouts));
344     ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts);
345     return 0;
346 }
347
348 AVFilterFormats *ff_all_formats(enum AVMediaType type)
349 {
350     AVFilterFormats *ret = NULL;
351
352     if (type == AVMEDIA_TYPE_VIDEO) {
353         const AVPixFmtDescriptor *desc = NULL;
354         while ((desc = av_pix_fmt_desc_next(desc))) {
355             if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
356                 ff_add_format(&ret, av_pix_fmt_desc_get_id(desc));
357         }
358     } else if (type == AVMEDIA_TYPE_AUDIO) {
359         enum AVSampleFormat fmt = 0;
360         while (av_get_sample_fmt_name(fmt)) {
361             ff_add_format(&ret, fmt);
362             fmt++;
363         }
364     }
365
366     return ret;
367 }
368
369 const int64_t avfilter_all_channel_layouts[] = {
370 #include "all_channel_layouts.inc"
371     -1
372 };
373
374 // AVFilterFormats *avfilter_make_all_channel_layouts(void)
375 // {
376 //     return avfilter_make_format64_list(avfilter_all_channel_layouts);
377 // }
378
379 AVFilterFormats *ff_planar_sample_fmts(void)
380 {
381     AVFilterFormats *ret = NULL;
382     int fmt;
383
384     for (fmt = 0; av_get_bytes_per_sample(fmt)>0; fmt++)
385         if (av_sample_fmt_is_planar(fmt))
386             ff_add_format(&ret, fmt);
387
388     return ret;
389 }
390
391 AVFilterFormats *ff_all_samplerates(void)
392 {
393     AVFilterFormats *ret = av_mallocz(sizeof(*ret));
394     return ret;
395 }
396
397 AVFilterChannelLayouts *ff_all_channel_layouts(void)
398 {
399     AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
400     if (!ret)
401         return NULL;
402     ret->all_layouts = 1;
403     return ret;
404 }
405
406 AVFilterChannelLayouts *ff_all_channel_counts(void)
407 {
408     AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
409     if (!ret)
410         return NULL;
411     ret->all_layouts = ret->all_counts = 1;
412     return ret;
413 }
414
415 #define FORMATS_REF(f, ref)                                          \
416 do {                                                                 \
417     *ref = f;                                                        \
418     f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount); \
419     if (!f->refs)                                                    \
420         return;                                                      \
421     f->refs[f->refcount-1] = ref;                                    \
422 } while (0)
423
424 void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
425 {
426     FORMATS_REF(f, ref);
427 }
428
429 void ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
430 {
431     FORMATS_REF(f, ref);
432 }
433
434 #define FIND_REF_INDEX(ref, idx)            \
435 do {                                        \
436     int i;                                  \
437     for (i = 0; i < (*ref)->refcount; i ++) \
438         if((*ref)->refs[i] == ref) {        \
439             idx = i;                        \
440             break;                          \
441         }                                   \
442 } while (0)
443
444 #define FORMATS_UNREF(ref, list)                                   \
445 do {                                                               \
446     int idx = -1;                                                  \
447                                                                    \
448     if (!*ref)                                                     \
449         return;                                                    \
450                                                                    \
451     FIND_REF_INDEX(ref, idx);                                      \
452                                                                    \
453     if (idx >= 0)                                                  \
454         memmove((*ref)->refs + idx, (*ref)->refs + idx + 1,        \
455             sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); \
456                                                                    \
457     if(!--(*ref)->refcount) {                                      \
458         av_free((*ref)->list);                                     \
459         av_free((*ref)->refs);                                     \
460         av_free(*ref);                                             \
461     }                                                              \
462     *ref = NULL;                                                   \
463 } while (0)
464
465 void ff_formats_unref(AVFilterFormats **ref)
466 {
467     FORMATS_UNREF(ref, formats);
468 }
469
470 void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
471 {
472     FORMATS_UNREF(ref, channel_layouts);
473 }
474
475 #define FORMATS_CHANGEREF(oldref, newref)       \
476 do {                                            \
477     int idx = -1;                               \
478                                                 \
479     FIND_REF_INDEX(oldref, idx);                \
480                                                 \
481     if (idx >= 0) {                             \
482         (*oldref)->refs[idx] = newref;          \
483         *newref = *oldref;                      \
484         *oldref = NULL;                         \
485     }                                           \
486 } while (0)
487
488 void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
489                                   AVFilterChannelLayouts **newref)
490 {
491     FORMATS_CHANGEREF(oldref, newref);
492 }
493
494 void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
495 {
496     FORMATS_CHANGEREF(oldref, newref);
497 }
498
499 #define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \
500 if (fmts) {                                                         \
501     int count = 0, i;                                               \
502                                                                     \
503     for (i = 0; i < ctx->nb_inputs; i++) {                          \
504         if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) {          \
505             ref(fmts, &ctx->inputs[i]->out_fmts);                   \
506             count++;                                                \
507         }                                                           \
508     }                                                               \
509     for (i = 0; i < ctx->nb_outputs; i++) {                         \
510         if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) {         \
511             ref(fmts, &ctx->outputs[i]->in_fmts);                   \
512             count++;                                                \
513         }                                                           \
514     }                                                               \
515                                                                     \
516     if (!count) {                                                   \
517         av_freep(&fmts->list);                                      \
518         av_freep(&fmts->refs);                                      \
519         av_freep(&fmts);                                            \
520     }                                                               \
521 }
522
523 void ff_set_common_channel_layouts(AVFilterContext *ctx,
524                                    AVFilterChannelLayouts *layouts)
525 {
526     SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts,
527                        ff_channel_layouts_ref, channel_layouts);
528 }
529
530 void ff_set_common_samplerates(AVFilterContext *ctx,
531                                AVFilterFormats *samplerates)
532 {
533     SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates,
534                        ff_formats_ref, formats);
535 }
536
537 /**
538  * A helper for query_formats() which sets all links to the same list of
539  * formats. If there are no links hooked to this filter, the list of formats is
540  * freed.
541  */
542 void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
543 {
544     SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats,
545                        ff_formats_ref, formats);
546 }
547
548 static int default_query_formats_common(AVFilterContext *ctx,
549                                         AVFilterChannelLayouts *(layouts)(void))
550 {
551     enum AVMediaType type = ctx->inputs  && ctx->inputs [0] ? ctx->inputs [0]->type :
552                             ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
553                             AVMEDIA_TYPE_VIDEO;
554
555     ff_set_common_formats(ctx, ff_all_formats(type));
556     if (type == AVMEDIA_TYPE_AUDIO) {
557         ff_set_common_channel_layouts(ctx, layouts());
558         ff_set_common_samplerates(ctx, ff_all_samplerates());
559     }
560
561     return 0;
562 }
563
564 int ff_default_query_formats(AVFilterContext *ctx)
565 {
566     return default_query_formats_common(ctx, ff_all_channel_layouts);
567 }
568
569 int ff_query_formats_all(AVFilterContext *ctx)
570 {
571     return default_query_formats_common(ctx, ff_all_channel_counts);
572 }
573
574 /* internal functions for parsing audio format arguments */
575
576 int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx)
577 {
578     char *tail;
579     int pix_fmt = av_get_pix_fmt(arg);
580     if (pix_fmt == AV_PIX_FMT_NONE) {
581         pix_fmt = strtol(arg, &tail, 0);
582         if (*tail || !av_pix_fmt_desc_get(pix_fmt)) {
583             av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg);
584             return AVERROR(EINVAL);
585         }
586     }
587     *ret = pix_fmt;
588     return 0;
589 }
590
591 int ff_parse_sample_format(int *ret, const char *arg, void *log_ctx)
592 {
593     char *tail;
594     int sfmt = av_get_sample_fmt(arg);
595     if (sfmt == AV_SAMPLE_FMT_NONE) {
596         sfmt = strtol(arg, &tail, 0);
597         if (*tail || av_get_bytes_per_sample(sfmt)<=0) {
598             av_log(log_ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg);
599             return AVERROR(EINVAL);
600         }
601     }
602     *ret = sfmt;
603     return 0;
604 }
605
606 int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx)
607 {
608     AVRational r;
609     if(av_parse_ratio(&r, arg, INT_MAX, 0, log_ctx) < 0 ||r.num<=0  ||r.den<=0) {
610         av_log(log_ctx, AV_LOG_ERROR, "Invalid time base '%s'\n", arg);
611         return AVERROR(EINVAL);
612     }
613     *ret = r;
614     return 0;
615 }
616
617 int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
618 {
619     char *tail;
620     double srate = av_strtod(arg, &tail);
621     if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) {
622         av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg);
623         return AVERROR(EINVAL);
624     }
625     *ret = srate;
626     return 0;
627 }
628
629 int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
630                             void *log_ctx)
631 {
632     char *tail;
633     int64_t chlayout, count;
634
635     if (nret) {
636         count = strtol(arg, &tail, 10);
637         if (*tail == 'c' && !tail[1] && count > 0 && count < 63) {
638             *nret = count;
639             *ret = 0;
640             return 0;
641         }
642     }
643     chlayout = av_get_channel_layout(arg);
644     if (chlayout == 0) {
645         chlayout = strtol(arg, &tail, 10);
646         if (*tail || chlayout == 0) {
647             av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
648             return AVERROR(EINVAL);
649         }
650     }
651     *ret = chlayout;
652     if (nret)
653         *nret = av_get_channel_layout_nb_channels(chlayout);
654     return 0;
655 }
656
657 #ifdef TEST
658
659 #undef printf
660
661 int main(void)
662 {
663     const int64_t *cl;
664     char buf[512];
665
666     for (cl = avfilter_all_channel_layouts; *cl != -1; cl++) {
667         av_get_channel_layout_string(buf, sizeof(buf), -1, *cl);
668         printf("%s\n", buf);
669     }
670
671     return 0;
672 }
673
674 #endif
675