yading@10: /* yading@10: * Filter layer - format negotiation yading@10: * Copyright (c) 2007 Bobby Bingham yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "libavutil/avassert.h" yading@10: #include "libavutil/channel_layout.h" yading@10: #include "libavutil/common.h" yading@10: #include "libavutil/eval.h" yading@10: #include "libavutil/pixdesc.h" yading@10: #include "libavutil/parseutils.h" yading@10: #include "avfilter.h" yading@10: #include "internal.h" yading@10: #include "formats.h" yading@10: yading@10: #define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */ yading@10: yading@10: /** yading@10: * Add all refs from a to ret and destroy a. yading@10: */ yading@10: #define MERGE_REF(ret, a, fmts, type, fail) \ yading@10: do { \ yading@10: type ***tmp; \ yading@10: int i; \ yading@10: \ yading@10: if (!(tmp = av_realloc(ret->refs, \ yading@10: sizeof(*tmp) * (ret->refcount + a->refcount)))) \ yading@10: goto fail; \ yading@10: ret->refs = tmp; \ yading@10: \ yading@10: for (i = 0; i < a->refcount; i ++) { \ yading@10: ret->refs[ret->refcount] = a->refs[i]; \ yading@10: *ret->refs[ret->refcount++] = ret; \ yading@10: } \ yading@10: \ yading@10: av_freep(&a->refs); \ yading@10: av_freep(&a->fmts); \ yading@10: av_freep(&a); \ yading@10: } while (0) yading@10: yading@10: /** yading@10: * Add all formats common for a and b to ret, copy the refs and destroy yading@10: * a and b. yading@10: */ yading@10: #define MERGE_FORMATS(ret, a, b, fmts, nb, type, fail) \ yading@10: do { \ yading@10: int i, j, k = 0, count = FFMIN(a->nb, b->nb); \ yading@10: \ yading@10: if (!(ret = av_mallocz(sizeof(*ret)))) \ yading@10: goto fail; \ yading@10: \ yading@10: if (count) { \ yading@10: if (!(ret->fmts = av_malloc(sizeof(*ret->fmts) * count))) \ yading@10: goto fail; \ yading@10: for (i = 0; i < a->nb; i++) \ yading@10: for (j = 0; j < b->nb; j++) \ yading@10: if (a->fmts[i] == b->fmts[j]) { \ yading@10: if(k >= FFMIN(a->nb, b->nb)){ \ yading@10: av_log(NULL, AV_LOG_ERROR, "Duplicate formats in avfilter_merge_formats() detected\n"); \ yading@10: av_free(ret->fmts); \ yading@10: av_free(ret); \ yading@10: return NULL; \ yading@10: } \ yading@10: ret->fmts[k++] = a->fmts[i]; \ yading@10: } \ yading@10: } \ yading@10: ret->nb = k; \ yading@10: /* check that there was at least one common format */ \ yading@10: if (!ret->nb) \ yading@10: goto fail; \ yading@10: \ yading@10: MERGE_REF(ret, a, fmts, type, fail); \ yading@10: MERGE_REF(ret, b, fmts, type, fail); \ yading@10: } while (0) yading@10: yading@10: AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, yading@10: enum AVMediaType type) yading@10: { yading@10: AVFilterFormats *ret = NULL; yading@10: int i, j; yading@10: int alpha1=0, alpha2=0; yading@10: int chroma1=0, chroma2=0; yading@10: yading@10: if (a == b) yading@10: return a; yading@10: yading@10: /* Do not lose chroma or alpha in merging. yading@10: It happens if both lists have formats with chroma (resp. alpha), but yading@10: the only formats in common do not have it (e.g. YUV+gray vs. yading@10: RGB+gray): in that case, the merging would select the gray format, yading@10: possibly causing a lossy conversion elsewhere in the graph. yading@10: To avoid that, pretend that there are no common formats to force the yading@10: insertion of a conversion filter. */ yading@10: if (type == AVMEDIA_TYPE_VIDEO) yading@10: for (i = 0; i < a->format_count; i++) yading@10: for (j = 0; j < b->format_count; j++) { yading@10: const AVPixFmtDescriptor *adesc = av_pix_fmt_desc_get(a->formats[i]); yading@10: const AVPixFmtDescriptor *bdesc = av_pix_fmt_desc_get(b->formats[j]); yading@10: alpha2 |= adesc->flags & bdesc->flags & PIX_FMT_ALPHA; yading@10: chroma2|= adesc->nb_components > 1 && bdesc->nb_components > 1; yading@10: if (a->formats[i] == b->formats[j]) { yading@10: alpha1 |= adesc->flags & PIX_FMT_ALPHA; yading@10: chroma1|= adesc->nb_components > 1; yading@10: } yading@10: } yading@10: yading@10: // If chroma or alpha can be lost through merging then do not merge yading@10: if (alpha2 > alpha1 || chroma2 > chroma1) yading@10: return NULL; yading@10: yading@10: MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail); yading@10: yading@10: return ret; yading@10: fail: yading@10: if (ret) { yading@10: av_freep(&ret->refs); yading@10: av_freep(&ret->formats); yading@10: } yading@10: av_freep(&ret); yading@10: return NULL; yading@10: } yading@10: yading@10: AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a, yading@10: AVFilterFormats *b) yading@10: { yading@10: AVFilterFormats *ret = NULL; yading@10: yading@10: if (a == b) return a; yading@10: yading@10: if (a->format_count && b->format_count) { yading@10: MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail); yading@10: } else if (a->format_count) { yading@10: MERGE_REF(a, b, formats, AVFilterFormats, fail); yading@10: ret = a; yading@10: } else { yading@10: MERGE_REF(b, a, formats, AVFilterFormats, fail); yading@10: ret = b; yading@10: } yading@10: yading@10: return ret; yading@10: fail: yading@10: if (ret) { yading@10: av_freep(&ret->refs); yading@10: av_freep(&ret->formats); yading@10: } yading@10: av_freep(&ret); yading@10: return NULL; yading@10: } yading@10: yading@10: AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, yading@10: AVFilterChannelLayouts *b) yading@10: { yading@10: AVFilterChannelLayouts *ret = NULL; yading@10: unsigned a_all = a->all_layouts + a->all_counts; yading@10: unsigned b_all = b->all_layouts + b->all_counts; yading@10: int ret_max, ret_nb = 0, i, j, round; yading@10: yading@10: if (a == b) return a; yading@10: yading@10: /* Put the most generic set in a, to avoid doing everything twice */ yading@10: if (a_all < b_all) { yading@10: FFSWAP(AVFilterChannelLayouts *, a, b); yading@10: FFSWAP(unsigned, a_all, b_all); yading@10: } yading@10: if (a_all) { yading@10: if (a_all == 1 && !b_all) { yading@10: /* keep only known layouts in b; works also for b_all = 1 */ yading@10: for (i = j = 0; i < b->nb_channel_layouts; i++) yading@10: if (KNOWN(b->channel_layouts[i])) yading@10: b->channel_layouts[j++] = b->channel_layouts[i]; yading@10: /* Not optimal: the unknown layouts of b may become known after yading@10: another merge. */ yading@10: if (!j) yading@10: return NULL; yading@10: b->nb_channel_layouts = j; yading@10: } yading@10: MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, fail); yading@10: return b; yading@10: } yading@10: yading@10: ret_max = a->nb_channel_layouts + b->nb_channel_layouts; yading@10: if (!(ret = av_mallocz(sizeof(*ret))) || yading@10: !(ret->channel_layouts = av_malloc(sizeof(*ret->channel_layouts) * yading@10: ret_max))) yading@10: goto fail; yading@10: yading@10: /* a[known] intersect b[known] */ yading@10: for (i = 0; i < a->nb_channel_layouts; i++) { yading@10: if (!KNOWN(a->channel_layouts[i])) yading@10: continue; yading@10: for (j = 0; j < b->nb_channel_layouts; j++) { yading@10: if (a->channel_layouts[i] == b->channel_layouts[j]) { yading@10: ret->channel_layouts[ret_nb++] = a->channel_layouts[i]; yading@10: a->channel_layouts[i] = b->channel_layouts[j] = 0; yading@10: } yading@10: } yading@10: } yading@10: /* 1st round: a[known] intersect b[generic] yading@10: 2nd round: a[generic] intersect b[known] */ yading@10: for (round = 0; round < 2; round++) { yading@10: for (i = 0; i < a->nb_channel_layouts; i++) { yading@10: uint64_t fmt = a->channel_layouts[i], bfmt; yading@10: if (!fmt || !KNOWN(fmt)) yading@10: continue; yading@10: bfmt = FF_COUNT2LAYOUT(av_get_channel_layout_nb_channels(fmt)); yading@10: for (j = 0; j < b->nb_channel_layouts; j++) yading@10: if (b->channel_layouts[j] == bfmt) yading@10: ret->channel_layouts[ret_nb++] = a->channel_layouts[i]; yading@10: } yading@10: /* 1st round: swap to prepare 2nd round; 2nd round: put it back */ yading@10: FFSWAP(AVFilterChannelLayouts *, a, b); yading@10: } yading@10: /* a[generic] intersect b[generic] */ yading@10: for (i = 0; i < a->nb_channel_layouts; i++) { yading@10: if (KNOWN(a->channel_layouts[i])) yading@10: continue; yading@10: for (j = 0; j < b->nb_channel_layouts; j++) yading@10: if (a->channel_layouts[i] == b->channel_layouts[j]) yading@10: ret->channel_layouts[ret_nb++] = a->channel_layouts[i]; yading@10: } yading@10: yading@10: ret->nb_channel_layouts = ret_nb; yading@10: if (!ret->nb_channel_layouts) yading@10: goto fail; yading@10: MERGE_REF(ret, a, channel_layouts, AVFilterChannelLayouts, fail); yading@10: MERGE_REF(ret, b, channel_layouts, AVFilterChannelLayouts, fail); yading@10: return ret; yading@10: yading@10: fail: yading@10: if (ret) { yading@10: av_freep(&ret->refs); yading@10: av_freep(&ret->channel_layouts); yading@10: } yading@10: av_freep(&ret); yading@10: return NULL; yading@10: } yading@10: yading@10: int ff_fmt_is_in(int fmt, const int *fmts) yading@10: { yading@10: const int *p; yading@10: yading@10: for (p = fmts; *p != -1; p++) { yading@10: if (fmt == *p) yading@10: return 1; yading@10: } yading@10: return 0; yading@10: } yading@10: yading@10: #define COPY_INT_LIST(list_copy, list, type) { \ yading@10: int count = 0; \ yading@10: if (list) \ yading@10: for (count = 0; list[count] != -1; count++) \ yading@10: ; \ yading@10: list_copy = av_calloc(count+1, sizeof(type)); \ yading@10: if (list_copy) { \ yading@10: memcpy(list_copy, list, sizeof(type) * count); \ yading@10: list_copy[count] = -1; \ yading@10: } \ yading@10: } yading@10: yading@10: int *ff_copy_int_list(const int * const list) yading@10: { yading@10: int *ret = NULL; yading@10: COPY_INT_LIST(ret, list, int); yading@10: return ret; yading@10: } yading@10: yading@10: int64_t *ff_copy_int64_list(const int64_t * const list) yading@10: { yading@10: int64_t *ret = NULL; yading@10: COPY_INT_LIST(ret, list, int64_t); yading@10: return ret; yading@10: } yading@10: yading@10: #define MAKE_FORMAT_LIST(type, field, count_field) \ yading@10: type *formats; \ yading@10: int count = 0; \ yading@10: if (fmts) \ yading@10: for (count = 0; fmts[count] != -1; count++) \ yading@10: ; \ yading@10: formats = av_mallocz(sizeof(*formats)); \ yading@10: if (!formats) return NULL; \ yading@10: formats->count_field = count; \ yading@10: if (count) { \ yading@10: formats->field = av_malloc(sizeof(*formats->field)*count); \ yading@10: if (!formats->field) { \ yading@10: av_free(formats); \ yading@10: return NULL; \ yading@10: } \ yading@10: } yading@10: yading@10: AVFilterFormats *ff_make_format_list(const int *fmts) yading@10: { yading@10: MAKE_FORMAT_LIST(AVFilterFormats, formats, format_count); yading@10: while (count--) yading@10: formats->formats[count] = fmts[count]; yading@10: yading@10: return formats; yading@10: } yading@10: yading@10: AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts) yading@10: { yading@10: MAKE_FORMAT_LIST(AVFilterChannelLayouts, yading@10: channel_layouts, nb_channel_layouts); yading@10: if (count) yading@10: memcpy(formats->channel_layouts, fmts, yading@10: sizeof(*formats->channel_layouts) * count); yading@10: yading@10: return formats; yading@10: } yading@10: yading@10: #define ADD_FORMAT(f, fmt, type, list, nb) \ yading@10: do { \ yading@10: type *fmts; \ yading@10: \ yading@10: if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) \ yading@10: return AVERROR(ENOMEM); \ yading@10: \ yading@10: fmts = av_realloc((*f)->list, \ yading@10: sizeof(*(*f)->list) * ((*f)->nb + 1));\ yading@10: if (!fmts) \ yading@10: return AVERROR(ENOMEM); \ yading@10: \ yading@10: (*f)->list = fmts; \ yading@10: (*f)->list[(*f)->nb++] = fmt; \ yading@10: } while (0) yading@10: yading@10: int ff_add_format(AVFilterFormats **avff, int64_t fmt) yading@10: { yading@10: ADD_FORMAT(avff, fmt, int, formats, format_count); yading@10: return 0; yading@10: } yading@10: yading@10: int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout) yading@10: { yading@10: av_assert1(!(*l && (*l)->all_layouts)); yading@10: ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts); yading@10: return 0; yading@10: } yading@10: yading@10: AVFilterFormats *ff_all_formats(enum AVMediaType type) yading@10: { yading@10: AVFilterFormats *ret = NULL; yading@10: int fmt; yading@10: int num_formats = type == AVMEDIA_TYPE_VIDEO ? AV_PIX_FMT_NB : yading@10: type == AVMEDIA_TYPE_AUDIO ? AV_SAMPLE_FMT_NB : 0; yading@10: yading@10: for (fmt = 0; fmt < num_formats; fmt++) { yading@10: const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); yading@10: if ((type != AVMEDIA_TYPE_VIDEO) || yading@10: (type == AVMEDIA_TYPE_VIDEO && !(desc->flags & PIX_FMT_HWACCEL))) yading@10: ff_add_format(&ret, fmt); yading@10: } yading@10: yading@10: return ret; yading@10: } yading@10: yading@10: const int64_t avfilter_all_channel_layouts[] = { yading@10: #include "all_channel_layouts.inc" yading@10: -1 yading@10: }; yading@10: yading@10: // AVFilterFormats *avfilter_make_all_channel_layouts(void) yading@10: // { yading@10: // return avfilter_make_format64_list(avfilter_all_channel_layouts); yading@10: // } yading@10: yading@10: AVFilterFormats *ff_planar_sample_fmts(void) yading@10: { yading@10: AVFilterFormats *ret = NULL; yading@10: int fmt; yading@10: yading@10: for (fmt = 0; fmt < AV_SAMPLE_FMT_NB; fmt++) yading@10: if (av_sample_fmt_is_planar(fmt)) yading@10: ff_add_format(&ret, fmt); yading@10: yading@10: return ret; yading@10: } yading@10: yading@10: AVFilterFormats *ff_all_samplerates(void) yading@10: { yading@10: AVFilterFormats *ret = av_mallocz(sizeof(*ret)); yading@10: return ret; yading@10: } yading@10: yading@10: AVFilterChannelLayouts *ff_all_channel_layouts(void) yading@10: { yading@10: AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret)); yading@10: if (!ret) yading@10: return NULL; yading@10: ret->all_layouts = 1; yading@10: return ret; yading@10: } yading@10: yading@10: AVFilterChannelLayouts *ff_all_channel_counts(void) yading@10: { yading@10: AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret)); yading@10: if (!ret) yading@10: return NULL; yading@10: ret->all_layouts = ret->all_counts = 1; yading@10: return ret; yading@10: } yading@10: yading@10: #define FORMATS_REF(f, ref) \ yading@10: do { \ yading@10: *ref = f; \ yading@10: f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount); \ yading@10: f->refs[f->refcount-1] = ref; \ yading@10: } while (0) yading@10: yading@10: void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref) yading@10: { yading@10: FORMATS_REF(f, ref); yading@10: } yading@10: yading@10: void ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref) yading@10: { yading@10: FORMATS_REF(f, ref); yading@10: } yading@10: yading@10: #define FIND_REF_INDEX(ref, idx) \ yading@10: do { \ yading@10: int i; \ yading@10: for (i = 0; i < (*ref)->refcount; i ++) \ yading@10: if((*ref)->refs[i] == ref) { \ yading@10: idx = i; \ yading@10: break; \ yading@10: } \ yading@10: } while (0) yading@10: yading@10: #define FORMATS_UNREF(ref, list) \ yading@10: do { \ yading@10: int idx = -1; \ yading@10: \ yading@10: if (!*ref) \ yading@10: return; \ yading@10: \ yading@10: FIND_REF_INDEX(ref, idx); \ yading@10: \ yading@10: if (idx >= 0) \ yading@10: memmove((*ref)->refs + idx, (*ref)->refs + idx + 1, \ yading@10: sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); \ yading@10: \ yading@10: if(!--(*ref)->refcount) { \ yading@10: av_free((*ref)->list); \ yading@10: av_free((*ref)->refs); \ yading@10: av_free(*ref); \ yading@10: } \ yading@10: *ref = NULL; \ yading@10: } while (0) yading@10: yading@10: void ff_formats_unref(AVFilterFormats **ref) yading@10: { yading@10: FORMATS_UNREF(ref, formats); yading@10: } yading@10: yading@10: void ff_channel_layouts_unref(AVFilterChannelLayouts **ref) yading@10: { yading@10: FORMATS_UNREF(ref, channel_layouts); yading@10: } yading@10: yading@10: #define FORMATS_CHANGEREF(oldref, newref) \ yading@10: do { \ yading@10: int idx = -1; \ yading@10: \ yading@10: FIND_REF_INDEX(oldref, idx); \ yading@10: \ yading@10: if (idx >= 0) { \ yading@10: (*oldref)->refs[idx] = newref; \ yading@10: *newref = *oldref; \ yading@10: *oldref = NULL; \ yading@10: } \ yading@10: } while (0) yading@10: yading@10: void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref, yading@10: AVFilterChannelLayouts **newref) yading@10: { yading@10: FORMATS_CHANGEREF(oldref, newref); yading@10: } yading@10: yading@10: void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref) yading@10: { yading@10: FORMATS_CHANGEREF(oldref, newref); yading@10: } yading@10: yading@10: #define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \ yading@10: { \ yading@10: int count = 0, i; \ yading@10: \ yading@10: for (i = 0; i < ctx->nb_inputs; i++) { \ yading@10: if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) { \ yading@10: ref(fmts, &ctx->inputs[i]->out_fmts); \ yading@10: count++; \ yading@10: } \ yading@10: } \ yading@10: for (i = 0; i < ctx->nb_outputs; i++) { \ yading@10: if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) { \ yading@10: ref(fmts, &ctx->outputs[i]->in_fmts); \ yading@10: count++; \ yading@10: } \ yading@10: } \ yading@10: \ yading@10: if (!count) { \ yading@10: av_freep(&fmts->list); \ yading@10: av_freep(&fmts->refs); \ yading@10: av_freep(&fmts); \ yading@10: } \ yading@10: } yading@10: yading@10: void ff_set_common_channel_layouts(AVFilterContext *ctx, yading@10: AVFilterChannelLayouts *layouts) yading@10: { yading@10: SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts, yading@10: ff_channel_layouts_ref, channel_layouts); yading@10: } yading@10: yading@10: void ff_set_common_samplerates(AVFilterContext *ctx, yading@10: AVFilterFormats *samplerates) yading@10: { yading@10: SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates, yading@10: ff_formats_ref, formats); yading@10: } yading@10: yading@10: /** yading@10: * A helper for query_formats() which sets all links to the same list of yading@10: * formats. If there are no links hooked to this filter, the list of formats is yading@10: * freed. yading@10: */ yading@10: void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats) yading@10: { yading@10: SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats, yading@10: ff_formats_ref, formats); yading@10: } yading@10: yading@10: static int default_query_formats_common(AVFilterContext *ctx, yading@10: AVFilterChannelLayouts *(layouts)(void)) yading@10: { yading@10: enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type : yading@10: ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type : yading@10: AVMEDIA_TYPE_VIDEO; yading@10: yading@10: ff_set_common_formats(ctx, ff_all_formats(type)); yading@10: if (type == AVMEDIA_TYPE_AUDIO) { yading@10: ff_set_common_channel_layouts(ctx, layouts()); yading@10: ff_set_common_samplerates(ctx, ff_all_samplerates()); yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: int ff_default_query_formats(AVFilterContext *ctx) yading@10: { yading@10: return default_query_formats_common(ctx, ff_all_channel_layouts); yading@10: } yading@10: yading@10: int ff_query_formats_all(AVFilterContext *ctx) yading@10: { yading@10: return default_query_formats_common(ctx, ff_all_channel_counts); yading@10: } yading@10: yading@10: /* internal functions for parsing audio format arguments */ yading@10: yading@10: int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx) yading@10: { yading@10: char *tail; yading@10: int pix_fmt = av_get_pix_fmt(arg); yading@10: if (pix_fmt == AV_PIX_FMT_NONE) { yading@10: pix_fmt = strtol(arg, &tail, 0); yading@10: if (*tail || (unsigned)pix_fmt >= AV_PIX_FMT_NB) { yading@10: av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: } yading@10: *ret = pix_fmt; yading@10: return 0; yading@10: } yading@10: yading@10: int ff_parse_sample_format(int *ret, const char *arg, void *log_ctx) yading@10: { yading@10: char *tail; yading@10: int sfmt = av_get_sample_fmt(arg); yading@10: if (sfmt == AV_SAMPLE_FMT_NONE) { yading@10: sfmt = strtol(arg, &tail, 0); yading@10: if (*tail || (unsigned)sfmt >= AV_SAMPLE_FMT_NB) { yading@10: av_log(log_ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: } yading@10: *ret = sfmt; yading@10: return 0; yading@10: } yading@10: yading@10: int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx) yading@10: { yading@10: AVRational r; yading@10: if(av_parse_ratio(&r, arg, INT_MAX, 0, log_ctx) < 0 ||r.num<=0 ||r.den<=0) { yading@10: av_log(log_ctx, AV_LOG_ERROR, "Invalid time base '%s'\n", arg); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: *ret = r; yading@10: return 0; yading@10: } yading@10: yading@10: int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx) yading@10: { yading@10: char *tail; yading@10: double srate = av_strtod(arg, &tail); yading@10: if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) { yading@10: av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: *ret = srate; yading@10: return 0; yading@10: } yading@10: yading@10: int ff_parse_channel_layout(int64_t *ret, const char *arg, void *log_ctx) yading@10: { yading@10: char *tail; yading@10: int64_t chlayout = av_get_channel_layout(arg); yading@10: if (chlayout == 0) { yading@10: chlayout = strtol(arg, &tail, 10); yading@10: if (*tail || chlayout == 0) { yading@10: av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: } yading@10: *ret = chlayout; yading@10: return 0; yading@10: } yading@10: yading@10: #ifdef TEST yading@10: yading@10: #undef printf yading@10: yading@10: int main(void) yading@10: { yading@10: const int64_t *cl; yading@10: char buf[512]; yading@10: yading@10: for (cl = avfilter_all_channel_layouts; *cl != -1; cl++) { yading@10: av_get_channel_layout_string(buf, sizeof(buf), -1, *cl); yading@10: printf("%s\n", buf); yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: #endif yading@10: