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