Unified · Split
| @@ -55,14 +55,15 @@ enum MappingMode { · 54 unmodified lines | ||
| 55 | 55 | MAP_PAIR_STR_STR |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | −#define MAX_CH 64 | |
| 59 | 58 | typedef struct ChannelMapContext { |
| 60 | 59 | const AVClass *class; |
| 61 | 60 | char *mapping_str; |
| 62 | 61 | AVChannelLayout output_layout; |
| 63 | − struct ChannelMap map[MAX_CH]; | |
| 62 | + struct ChannelMap *map; | |
| 64 | 63 | int nch; |
| 65 | 64 | enum MappingMode mode; |
| 65 | + | |
| 66 | + uint8_t **source_planes; | |
| 66 | 67 | } ChannelMapContext; |
| 67 | 68 | |
| 68 | 69 | #define OFFSET(x) offsetof(ChannelMapContext, x) |
| @@ -78,6 +79,13 @@ static const AVOption channelmap_options[] = { · 9 unmodified lines | ||
| 78 | 79 | |
| 79 | 80 | AVFILTER_DEFINE_CLASS(channelmap); |
| 80 | 81 | |
| 82 | +static void channelmap_uninit(AVFilterContext *ctx) | |
| 83 | +{ | |
| 84 | + ChannelMapContext *s = ctx->priv; | |
| 85 | + av_freep(&s->map); | |
| 86 | + av_freep(&s->source_planes); | |
| 87 | +} | |
| 88 | + | |
| 81 | 89 | static char* split(char *message, char delim) { |
| 82 | 90 | char *next = strchr(message, delim); |
| 83 | 91 | if (next) |
| @@ -85,7 +93,7 @@ static char* split(char *message, char delim) { · 1 unmodified line | ||
| 85 | 93 | return next; |
| 86 | 94 | } |
| 87 | 95 | |
| 88 | −static int get_channel_idx(char **map, int *ch, char delim, int max_nb_channels) | |
| 96 | +static int get_channel_idx(char **map, int *ch, char delim) | |
| 89 | 97 | { |
| 90 | 98 | char *next; |
| 91 | 99 | int len; |
| @@ -99,7 +107,7 @@ static int get_channel_idx(char **map, int *ch, char delim, int max_nb_channels) · 7 unmodified lines | ||
| 99 | 107 | sscanf(*map, "%d%n", ch, &n); |
| 100 | 108 | if (n != len) |
| 101 | 109 | return AVERROR(EINVAL); |
| 102 | − if (*ch < 0 || *ch >= max_nb_channels) | |
| 110 | + if (*ch < 0) | |
| 103 | 111 | return AVERROR(EINVAL); |
| 104 | 112 | *map = next; |
| 105 | 113 | return 0; |
| @@ -148,7 +156,8 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 42 unmodified lines | ||
| 148 | 156 | int map_entries = 0; |
| 149 | 157 | enum MappingMode mode; |
| 150 | 158 | int64_t out_ch_mask = 0; |
| 151 | − uint64_t presence_mask; | |
| 159 | + uint8_t *presence_map = NULL; | |
| 160 | + int ret = 0; | |
| 152 | 161 | int i; |
| 153 | 162 | |
| 154 | 163 | mapping = s->mapping_str; |
| @@ -182,27 +191,25 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 27 unmodified lines | ||
| 182 | 191 | if (*++sep) // Allow trailing comma |
| 183 | 192 | map_entries++; |
| 184 | 193 | } |
| 185 | − } | |
| 186 | 194 | |
| 187 | − if (map_entries > MAX_CH) { | |
| 188 | − av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries); | |
| 189 | − return AVERROR(EINVAL); | |
| 195 | + s->map = av_malloc_array(map_entries, sizeof(*s->map)); | |
| 196 | + if (!s->map) | |
| 197 | + return AVERROR(ENOMEM); | |
| 190 | 198 | } |
| 191 | 199 | |
| 192 | − for (i = 0; i < MAX_CH; i++) { | |
| 200 | + for (i = 0; i < map_entries; i++) { | |
| 201 | + int in_ch_idx = -1, out_ch_idx = -1; | |
| 202 | + int in_ch = -1, out_ch = -1; | |
| 203 | + static const char err[] = "Failed to parse channel map\n"; | |
| 204 | + | |
| 193 | 205 | s->map[i].in_channel_idx = -1; |
| 194 | 206 | s->map[i].out_channel_idx = -1; |
| 195 | 207 | s->map[i].in_channel = -1; |
| 196 | 208 | s->map[i].out_channel = -1; |
| 197 | − } | |
| 198 | 209 | |
| 199 | − for (i = 0; i < map_entries; i++) { | |
| 200 | − int in_ch_idx = -1, out_ch_idx = -1; | |
| 201 | − int in_ch = -1, out_ch = -1; | |
| 202 | − static const char err[] = "Failed to parse channel map\n"; | |
| 203 | 210 | switch (mode) { |
| 204 | 211 | case MAP_ONE_INT: |
| 205 | − if (get_channel_idx(&mapping, &in_ch_idx, separator, MAX_CH) < 0) { | |
| 212 | + if (get_channel_idx(&mapping, &in_ch_idx, separator) < 0) { | |
| 206 | 213 | av_log(ctx, AV_LOG_ERROR, err); |
| 207 | 214 | return AVERROR(EINVAL); |
| 208 | 215 | } |
| @@ -218,8 +225,8 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 9 unmodified lines | ||
| 218 | 225 | s->map[i].out_channel_idx = i; |
| 219 | 226 | break; |
| 220 | 227 | case MAP_PAIR_INT_INT: |
| 221 | − if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || | |
| 222 | − get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { | |
| 228 | + if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 || | |
| 229 | + get_channel_idx(&mapping, &out_ch_idx, separator) < 0) { | |
| 223 | 230 | av_log(ctx, AV_LOG_ERROR, err); |
| 224 | 231 | return AVERROR(EINVAL); |
| 225 | 232 | } |
| @@ -227,7 +234,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 1 unmodified line | ||
| 227 | 234 | s->map[i].out_channel_idx = out_ch_idx; |
| 228 | 235 | break; |
| 229 | 236 | case MAP_PAIR_INT_STR: |
| 230 | − if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || | |
| 237 | + if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 || | |
| 231 | 238 | get_channel(&mapping, &out_ch, separator) < 0) { |
| 232 | 239 | av_log(ctx, AV_LOG_ERROR, err); |
| 233 | 240 | return AVERROR(EINVAL); |
| @@ -241,7 +248,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 7 unmodified lines | ||
| 241 | 248 | break; |
| 242 | 249 | case MAP_PAIR_STR_INT: |
| 243 | 250 | if (get_channel(&mapping, &in_ch, '-') < 0 || |
| 244 | − get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { | |
| 251 | + get_channel_idx(&mapping, &out_ch_idx, separator) < 0) { | |
| 245 | 252 | av_log(ctx, AV_LOG_ERROR, err); |
| 246 | 253 | return AVERROR(EINVAL); |
| 247 | 254 | } |
| @@ -275,6 +282,11 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 27 unmodified lines | ||
| 275 | 282 | if (mode == MAP_NONE) { |
| 276 | 283 | int i; |
| 277 | 284 | s->nch = s->output_layout.nb_channels; |
| 285 | + | |
| 286 | + s->map = av_malloc_array(s->nch, sizeof(*s->map)); | |
| 287 | + if (!s->map) | |
| 288 | + return AVERROR(ENOMEM); | |
| 289 | + | |
| 278 | 290 | for (i = 0; i < s->nch; i++) { |
| 279 | 291 | s->map[i].in_channel_idx = i; |
| 280 | 292 | s->map[i].out_channel_idx = i; |
| @@ -301,22 +313,25 @@ static av_cold int channelmap_init(AVFilterContext *ctx) · 20 unmodified lines | ||
| 301 | 313 | } |
| 302 | 314 | } |
| 303 | 315 | |
| 304 | − presence_mask = 0; | |
| 316 | + presence_map = av_calloc(s->nch, sizeof(*presence_map)); | |
| 305 | 317 | for (i = 0; i < s->nch; i++) { |
| 306 | − uint64_t idx_mask; | |
| 307 | − int ret = check_idx_and_id(ctx, s->map[i].out_channel_idx, s->map[i].out_channel, &s->output_layout, "out"); | |
| 318 | + const int out_idx = s->map[i].out_channel_idx; | |
| 319 | + int ret = check_idx_and_id(ctx, out_idx, s->map[i].out_channel, &s->output_layout, "out"); | |
| 308 | 320 | if (ret < 0) |
| 309 | − return ret; | |
| 310 | − idx_mask = (1ULL << s->map[i].out_channel_idx); | |
| 311 | − if (presence_mask & idx_mask) { | |
| 321 | + break; | |
| 322 | + if (presence_map[out_idx]) { | |
| 312 | 323 | char layout_name[256]; |
| 313 | 324 | av_channel_layout_describe(&s->output_layout, layout_name, sizeof(layout_name)); |
| 314 | 325 | av_log(ctx, AV_LOG_ERROR, "Mapping %d assigns channel #%d twice in output layout '%s'.\n", |
| 315 | 326 | i + 1, s->map[i].out_channel_idx, layout_name); |
| 316 | − return AVERROR(EINVAL); | |
| 327 | + ret = AVERROR(EINVAL); | |
| 328 | + break; | |
| 317 | 329 | } |
| 318 | − presence_mask |= idx_mask; | |
| 330 | + presence_map[out_idx] = 1; | |
| 319 | 331 | } |
| 332 | + av_freep(&presence_map); | |
| 333 | + if (ret < 0) | |
| 334 | + return ret; | |
| 320 | 335 | |
| 321 | 336 | return 0; |
| 322 | 337 | } |
| @@ -353,10 +368,9 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) · 30 unmodified lines | ||
| 353 | 368 | const int nch_in = inlink->ch_layout.nb_channels; |
| 354 | 369 | const int nch_out = s->nch; |
| 355 | 370 | int ch, ret; |
| 356 | − uint8_t *source_planes[MAX_CH]; | |
| 357 | 371 | |
| 358 | − memcpy(source_planes, buf->extended_data, | |
| 359 | − nch_in * sizeof(source_planes[0])); | |
| 372 | + memcpy(s->source_planes, buf->extended_data, | |
| 373 | + nch_in * sizeof(s->source_planes[0])); | |
| 360 | 374 | |
| 361 | 375 | if (nch_out > nch_in) { |
| 362 | 376 | if (nch_out > FF_ARRAY_ELEMS(buf->data)) { |
| @@ -380,7 +394,7 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) · 17 unmodified lines | ||
| 380 | 394 | |
| 381 | 395 | for (ch = 0; ch < nch_out; ch++) { |
| 382 | 396 | buf->extended_data[s->map[ch].out_channel_idx] = |
| 383 | − source_planes[s->map[ch].in_channel_idx]; | |
| 397 | + s->source_planes[s->map[ch].in_channel_idx]; | |
| 384 | 398 | } |
| 385 | 399 | |
| 386 | 400 | if (buf->data != buf->extended_data) |
| @@ -411,6 +425,12 @@ static int channelmap_config_input(AVFilterLink *inlink) · 24 unmodified lines | ||
| 411 | 425 | err = AVERROR(EINVAL); |
| 412 | 426 | } |
| 413 | 427 | |
| 428 | + av_freep(&s->source_planes); | |
| 429 | + s->source_planes = av_calloc(inlink->ch_layout.nb_channels, | |
| 430 | + sizeof(*s->source_planes)); | |
| 431 | + if (!s->source_planes) | |
| 432 | + return AVERROR(ENOMEM); | |
| 433 | + | |
| 414 | 434 | return err; |
| 415 | 435 | } |
| 416 | 436 | |
| @@ -428,6 +448,7 @@ const AVFilter ff_af_channelmap = { · 11 unmodified lines | ||
| 428 | 448 | .name = "channelmap", |
| 429 | 449 | .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), |
| 430 | 450 | .init = channelmap_init, |
| 451 | + .uninit = channelmap_uninit, | |
| 431 | 452 | .priv_size = sizeof(ChannelMapContext), |
| 432 | 453 | .priv_class = &channelmap_class, |
| 433 | 454 | FILTER_INPUTS(avfilter_af_channelmap_inputs), |