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