]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/af_channelmap.c
configure: Simplify nvenc check (and move it to the correct spot)
[ffmpeg] / libavfilter / af_channelmap.c
index 3e945d6e915e1b357dd1b94e1d08947a9b16fbec..e214bdbcc17b84ac74f0731ab0dc3865b39a7365 100644 (file)
@@ -25,8 +25,8 @@
 
 #include <ctype.h>
 
-#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,17 +135,17 @@ 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;
@@ -169,18 +153,17 @@ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args)
     }
 
     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 +172,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 +209,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 +239,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 +253,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 +275,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 +311,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 +335,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,
 };