]> git.sesse.net Git - ffmpeg/blob - libavfilter/formats.c
Merge commit '5bc223b15d064e328ff90b0241fa1191f1d2786d'
[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 *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
303 AVFilterChannelLayouts *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)        \
315 do {                                                        \
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
337 int 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
343 int 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
350 AVFilterFormats *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
372 const 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
382 AVFilterFormats *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
395 AVFilterFormats *ff_all_samplerates(void)
396 {
397     AVFilterFormats *ret = av_mallocz(sizeof(*ret));
398     return ret;
399 }
400
401 AVFilterChannelLayouts *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
410 AVFilterChannelLayouts *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
435 int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
436 {
437     FORMATS_REF(f, ref, ff_channel_layouts_unref);
438 }
439
440 int 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)            \
446 do {                                        \
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)                                   \
456 do {                                                               \
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
476 void ff_formats_unref(AVFilterFormats **ref)
477 {
478     FORMATS_UNREF(ref, formats);
479 }
480
481 void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
482 {
483     FORMATS_UNREF(ref, channel_layouts);
484 }
485
486 #define FORMATS_CHANGEREF(oldref, newref)       \
487 do {                                            \
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
499 void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
500                                   AVFilterChannelLayouts **newref)
501 {
502     FORMATS_CHANGEREF(oldref, newref);
503 }
504
505 void 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                 return ret;                                         \
522             }                                                       \
523             count++;                                                \
524         }                                                           \
525     }                                                               \
526     for (i = 0; i < ctx->nb_outputs; i++) {                         \
527         if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) {         \
528             int ret = ref_fn(fmts, &ctx->outputs[i]->in_fmts);      \
529             if (ret < 0) {                                          \
530                 unref_fn(&fmts);                                    \
531                 return ret;                                         \
532             }                                                       \
533             count++;                                                \
534         }                                                           \
535     }                                                               \
536                                                                     \
537     if (!count) {                                                   \
538         av_freep(&fmts->list);                                      \
539         av_freep(&fmts->refs);                                      \
540         av_freep(&fmts);                                            \
541     }                                                               \
542                                                                     \
543     return 0;
544
545 int ff_set_common_channel_layouts(AVFilterContext *ctx,
546                                   AVFilterChannelLayouts *layouts)
547 {
548     SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts,
549                        ff_channel_layouts_ref, ff_channel_layouts_unref, channel_layouts);
550 }
551
552 int ff_set_common_samplerates(AVFilterContext *ctx,
553                               AVFilterFormats *samplerates)
554 {
555     SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates,
556                        ff_formats_ref, ff_formats_unref, formats);
557 }
558
559 /**
560  * A helper for query_formats() which sets all links to the same list of
561  * formats. If there are no links hooked to this filter, the list of formats is
562  * freed.
563  */
564 int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
565 {
566     SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats,
567                        ff_formats_ref, ff_formats_unref, formats);
568 }
569
570 static int default_query_formats_common(AVFilterContext *ctx,
571                                         AVFilterChannelLayouts *(layouts)(void))
572 {
573     int ret;
574     enum AVMediaType type = ctx->inputs  && ctx->inputs [0] ? ctx->inputs [0]->type :
575                             ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
576                             AVMEDIA_TYPE_VIDEO;
577
578     ret = ff_set_common_formats(ctx, ff_all_formats(type));
579     if (ret < 0)
580         return ret;
581     if (type == AVMEDIA_TYPE_AUDIO) {
582         ret = ff_set_common_channel_layouts(ctx, layouts());
583         if (ret < 0)
584             return ret;
585         ret = ff_set_common_samplerates(ctx, ff_all_samplerates());
586         if (ret < 0)
587             return ret;
588     }
589
590     return 0;
591 }
592
593 int ff_default_query_formats(AVFilterContext *ctx)
594 {
595     return default_query_formats_common(ctx, ff_all_channel_layouts);
596 }
597
598 int ff_query_formats_all(AVFilterContext *ctx)
599 {
600     return default_query_formats_common(ctx, ff_all_channel_counts);
601 }
602
603 /* internal functions for parsing audio format arguments */
604
605 int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx)
606 {
607     char *tail;
608     int pix_fmt = av_get_pix_fmt(arg);
609     if (pix_fmt == AV_PIX_FMT_NONE) {
610         pix_fmt = strtol(arg, &tail, 0);
611         if (*tail || !av_pix_fmt_desc_get(pix_fmt)) {
612             av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg);
613             return AVERROR(EINVAL);
614         }
615     }
616     *ret = pix_fmt;
617     return 0;
618 }
619
620 int ff_parse_sample_format(int *ret, const char *arg, void *log_ctx)
621 {
622     char *tail;
623     int sfmt = av_get_sample_fmt(arg);
624     if (sfmt == AV_SAMPLE_FMT_NONE) {
625         sfmt = strtol(arg, &tail, 0);
626         if (*tail || av_get_bytes_per_sample(sfmt)<=0) {
627             av_log(log_ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg);
628             return AVERROR(EINVAL);
629         }
630     }
631     *ret = sfmt;
632     return 0;
633 }
634
635 int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx)
636 {
637     AVRational r;
638     if(av_parse_ratio(&r, arg, INT_MAX, 0, log_ctx) < 0 ||r.num<=0  ||r.den<=0) {
639         av_log(log_ctx, AV_LOG_ERROR, "Invalid time base '%s'\n", arg);
640         return AVERROR(EINVAL);
641     }
642     *ret = r;
643     return 0;
644 }
645
646 int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
647 {
648     char *tail;
649     double srate = av_strtod(arg, &tail);
650     if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) {
651         av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg);
652         return AVERROR(EINVAL);
653     }
654     *ret = srate;
655     return 0;
656 }
657
658 int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
659                             void *log_ctx)
660 {
661     char *tail;
662     int64_t chlayout;
663
664     chlayout = av_get_channel_layout(arg);
665     if (chlayout == 0) {
666         chlayout = strtol(arg, &tail, 10);
667         if (!(*tail == '\0' || *tail == 'c' && *(tail + 1) == '\0') || chlayout <= 0 || chlayout > 63) {
668             av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
669             return AVERROR(EINVAL);
670         }
671         if (nret) {
672             *nret = chlayout;
673             *ret = 0;
674             return 0;
675         }
676     }
677     *ret = chlayout;
678     if (nret)
679         *nret = av_get_channel_layout_nb_channels(chlayout);
680     return 0;
681 }
682
683 #ifdef TEST
684
685 #undef printf
686
687 int main(void)
688 {
689     const int64_t *cl;
690     char buf[512];
691     int i;
692     const char *teststrings[] ={
693         "blah",
694         "1",
695         "2",
696         "-1",
697         "60",
698         "65",
699         "1c",
700         "2c",
701         "-1c",
702         "60c",
703         "65c",
704         "5.1",
705         "stereo",
706         "1+1+1+1",
707         "1c+1c+1c+1c",
708         "2c+1c",
709         "0x3",
710     };
711
712     for (cl = avfilter_all_channel_layouts; *cl != -1; cl++) {
713         av_get_channel_layout_string(buf, sizeof(buf), -1, *cl);
714         printf("%s\n", buf);
715     }
716
717     for ( i = 0; i<FF_ARRAY_ELEMS(teststrings); i++) {
718         int64_t layout = -1;
719         int count = -1;
720         int ret;
721         ret = ff_parse_channel_layout(&layout, &count, teststrings[i], NULL);
722
723         printf ("%d = ff_parse_channel_layout(%016"PRIX64", %2d, %s);\n", ret ? -1 : 0, layout, count, teststrings[i]);
724     }
725
726     return 0;
727 }
728
729 #endif
730