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