X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Faf_channelmap.c;h=572549808f94551fa1fdea79061bcf3f94bc7086;hb=95db8c757cb003a71b040b567f38be74151deb5c;hp=3e945d6e915e1b357dd1b94e1d08947a9b16fbec;hpb=1d9c2dc89a2302076a68b4a3ae3639abbb1a502d;p=ffmpeg diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 3e945d6e915..572549808f9 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -25,8 +25,8 @@ #include -#include "libavutil/audioconvert.h" #include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" @@ -57,7 +57,6 @@ enum MappingMode { #define MAX_CH 64 typedef struct ChannelMapContext { const AVClass *class; - AVFilterChannelLayouts *channel_layouts; char *mapping_str; char *channel_layout_str; uint64_t output_layout; @@ -119,31 +118,16 @@ static int get_channel(char **map, uint64_t *ch, char delim) return 0; } -static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) +static av_cold int channelmap_init(AVFilterContext *ctx) { ChannelMapContext *s = ctx->priv; - int ret; - char *mapping; - enum mode; + char *mapping, separator = '|'; int map_entries = 0; char buf[256]; enum MappingMode mode; uint64_t out_ch_mask = 0; int i; - if (!args) { - av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n"); - return AVERROR(EINVAL); - } - - s->class = &channelmap_class; - av_opt_set_defaults(s); - - if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { - av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args); - return ret; - } - mapping = s->mapping_str; if (!mapping) { @@ -151,36 +135,42 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) } else { char *dash = strchr(mapping, '-'); if (!dash) { // short mapping - if (isdigit(*mapping)) + if (av_isdigit(*mapping)) mode = MAP_ONE_INT; else mode = MAP_ONE_STR; - } else if (isdigit(*mapping)) { - if (isdigit(*(dash+1))) + } else if (av_isdigit(*mapping)) { + if (av_isdigit(*(dash+1))) mode = MAP_PAIR_INT_INT; else mode = MAP_PAIR_INT_STR; } else { - if (isdigit(*(dash+1))) + if (av_isdigit(*(dash+1))) mode = MAP_PAIR_STR_INT; else mode = MAP_PAIR_STR_STR; } +#if FF_API_OLD_FILTER_OPTS + if (strchr(mapping, ',')) { + av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use " + "'|' to separate the mappings.\n"); + separator = ','; + } +#endif } if (mode != MAP_NONE) { - char *comma = mapping; + char *sep = mapping; map_entries = 1; - while ((comma = strchr(comma, ','))) { - if (*++comma) // Allow trailing comma + while ((sep = strchr(sep, separator))) { + if (*++sep) // Allow trailing comma map_entries++; } } if (map_entries > MAX_CH) { av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } for (i = 0; i < map_entries; i++) { @@ -189,40 +179,36 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) static const char err[] = "Failed to parse channel map\n"; switch (mode) { case MAP_ONE_INT: - if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) { - ret = AVERROR(EINVAL); + if (get_channel_idx(&mapping, &in_ch_idx, separator, MAX_CH) < 0) { av_log(ctx, AV_LOG_ERROR, err); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel_idx = in_ch_idx; s->map[i].out_channel_idx = i; break; case MAP_ONE_STR: - if (!get_channel(&mapping, &in_ch, ',')) { + if (get_channel(&mapping, &in_ch, separator) < 0) { av_log(ctx, AV_LOG_ERROR, err); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel = in_ch; s->map[i].out_channel_idx = i; break; case MAP_PAIR_INT_INT: if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || - get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) { + get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { av_log(ctx, AV_LOG_ERROR, err); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel_idx = in_ch_idx; s->map[i].out_channel_idx = out_ch_idx; break; case MAP_PAIR_INT_STR: if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || - get_channel(&mapping, &out_ch, ',') < 0 || + get_channel(&mapping, &out_ch, separator) < 0 || out_ch & out_ch_mask) { av_log(ctx, AV_LOG_ERROR, err); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel_idx = in_ch_idx; s->map[i].out_channel = out_ch; @@ -230,21 +216,19 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) break; case MAP_PAIR_STR_INT: if (get_channel(&mapping, &in_ch, '-') < 0 || - get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) { + get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { av_log(ctx, AV_LOG_ERROR, err); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel = in_ch; s->map[i].out_channel_idx = out_ch_idx; break; case MAP_PAIR_STR_STR: if (get_channel(&mapping, &in_ch, '-') < 0 || - get_channel(&mapping, &out_ch, ',') < 0 || + get_channel(&mapping, &out_ch, separator) < 0 || out_ch & out_ch_mask) { av_log(ctx, AV_LOG_ERROR, err); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->map[i].in_channel = in_ch; s->map[i].out_channel = out_ch; @@ -262,8 +246,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) { av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n", s->channel_layout_str); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } if (mode == MAP_NONE) { int i; @@ -277,18 +260,20 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) av_log(ctx, AV_LOG_ERROR, "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n", s->channel_layout_str, buf); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) { av_log(ctx, AV_LOG_ERROR, "Output channel layout %s does not match the number of channels mapped %d.\n", s->channel_layout_str, s->nch); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } s->output_layout = fmt; } - ff_add_channel_layout(&s->channel_layouts, s->output_layout); + if (!s->output_layout) { + av_log(ctx, AV_LOG_ERROR, "Output channel layout is not set and " + "cannot be guessed from the maps.\n"); + return AVERROR(EINVAL); + } if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) { for (i = 0; i < s->nch; i++) { @@ -297,24 +282,25 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args) } } -fail: - av_opt_free(s); - return ret; + return 0; } static int channelmap_query_formats(AVFilterContext *ctx) { ChannelMapContext *s = ctx->priv; + AVFilterChannelLayouts *channel_layouts = NULL; + + ff_add_channel_layout(&channel_layouts, s->output_layout); ff_set_common_formats(ctx, ff_planar_sample_fmts()); ff_set_common_samplerates(ctx, ff_all_samplerates()); ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts); - ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts); + ff_channel_layouts_ref(channel_layouts, &ctx->outputs[0]->in_channel_layouts); return 0; } -static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -332,14 +318,14 @@ static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *bu uint8_t **new_extended_data = av_mallocz(nch_out * sizeof(*buf->extended_data)); if (!new_extended_data) { - avfilter_unref_buffer(buf); + av_frame_free(&buf); return AVERROR(ENOMEM); } if (buf->extended_data == buf->data) { buf->extended_data = new_extended_data; } else { - buf->extended_data = new_extended_data; av_free(buf->extended_data); + buf->extended_data = new_extended_data; } } else if (buf->extended_data != buf->data) { av_free(buf->extended_data); @@ -356,49 +342,74 @@ static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *bu memcpy(buf->data, buf->extended_data, FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); - return ff_filter_samples(outlink, buf); + buf->channel_layout = outlink->channel_layout; + + return ff_filter_frame(outlink, buf); } static int channelmap_config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; ChannelMapContext *s = ctx->priv; + int nb_channels = av_get_channel_layout_nb_channels(inlink->channel_layout); int i, err = 0; const char *channel_name; char layout_name[256]; - if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) { - for (i = 0; i < s->nch; i++) { - s->map[i].in_channel_idx = av_get_channel_layout_channel_index( - inlink->channel_layout, s->map[i].in_channel); - if (s->map[i].in_channel_idx < 0) { - channel_name = av_get_channel_name(s->map[i].in_channel); - av_get_channel_layout_string(layout_name, sizeof(layout_name), - 0, inlink->channel_layout); + for (i = 0; i < s->nch; i++) { + struct ChannelMap *m = &s->map[i]; + + if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) { + m->in_channel_idx = av_get_channel_layout_channel_index( + inlink->channel_layout, m->in_channel); + } + + if (m->in_channel_idx < 0 || m->in_channel_idx >= nb_channels) { + av_get_channel_layout_string(layout_name, sizeof(layout_name), + 0, inlink->channel_layout); + if (m->in_channel) { + channel_name = av_get_channel_name(m->in_channel); av_log(ctx, AV_LOG_ERROR, "input channel '%s' not available from input layout '%s'\n", channel_name, layout_name); - err = AVERROR(EINVAL); + } else { + av_log(ctx, AV_LOG_ERROR, + "input channel #%d not available from input layout '%s'\n", + m->in_channel_idx, layout_name); } + err = AVERROR(EINVAL); } } return err; } -AVFilter avfilter_af_channelmap = { +static const AVFilterPad avfilter_af_channelmap_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = channelmap_filter_frame, + .config_props = channelmap_config_input + }, + { NULL } +}; + +static const AVFilterPad avfilter_af_channelmap_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO + }, + { NULL } +}; + +AVFilter ff_af_channelmap = { .name = "channelmap", .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), .init = channelmap_init, .query_formats = channelmap_query_formats, .priv_size = sizeof(ChannelMapContext), + .priv_class = &channelmap_class, - .inputs = (const AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .filter_samples = channelmap_filter_samples, - .config_props = channelmap_config_input }, - { .name = NULL }}, - .outputs = (const AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_AUDIO }, - { .name = NULL }}, + .inputs = avfilter_af_channelmap_inputs, + .outputs = avfilter_af_channelmap_outputs, };