Part of the code expects valid lists, in particular no duplicates. These tests allow to catch bugs in filters (unlikely but possible) and to give a clear message when the error comes from the user ((a)formats) or the application (buffersink). If we decide to switch to a more efficient merging algorithm, possibly sorting the lists, these functions will be the preferred place for pre-processing, and can be renamed accordingly.
Showing the changes to libavfilter/avfiltergraph.c (1 of 3 files). Show all
Unified · Split
| @@ -313,6 +313,53 @@ static void sanitize_channel_layouts(void *log, AVFilterChannelLayouts *l) · 312 unmodified lines | |||
| 313 | } | 313 | } |
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterFormatsConfig *cfg) | ||
| 317 | { | ||
| 318 | int ret; | ||
| 319 | |||
| 320 | switch (link->type) { | ||
| 321 | |||
| 322 | case AVMEDIA_TYPE_VIDEO: | ||
| 323 | if ((ret = ff_formats_check_pixel_formats(log, cfg->formats)) < 0) | ||
| 324 | return ret; | ||
| 325 | break; | ||
| 326 | |||
| 327 | case AVMEDIA_TYPE_AUDIO: | ||
| 328 | if ((ret = ff_formats_check_sample_formats(log, cfg->formats)) < 0 || | ||
| 329 | (ret = ff_formats_check_sample_rates(log, cfg->samplerates)) < 0 || | ||
| 330 | (ret = ff_formats_check_channel_layouts(log, cfg->channel_layouts)) < 0) | ||
| 331 | return ret; | ||
| 332 | break; | ||
| 333 | |||
| 334 | default: | ||
| 335 | av_assert0(!"reached"); | ||
| 336 | } | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | /** | ||
| 341 | * Check the validity of the formats / etc. lists set by query_formats(). | ||
| 342 | * | ||
| 343 | * In particular, check they do not contain any redundant element. | ||
| 344 | */ | ||
| 345 | static int filter_check_formats(AVFilterContext *ctx) | ||
| 346 | { | ||
| 347 | unsigned i; | ||
| 348 | int ret; | ||
| 349 | |||
| 350 | for (i = 0; i < ctx->nb_inputs; i++) { | ||
| 351 | ret = filter_link_check_formats(ctx, ctx->inputs[i], &ctx->inputs[i]->outcfg); | ||
| 352 | if (ret < 0) | ||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | for (i = 0; i < ctx->nb_outputs; i++) { | ||
| 356 | ret = filter_link_check_formats(ctx, ctx->outputs[i], &ctx->outputs[i]->incfg); | ||
| 357 | if (ret < 0) | ||
| 358 | return ret; | ||
| 359 | } | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 316 | static int filter_query_formats(AVFilterContext *ctx) | 363 | static int filter_query_formats(AVFilterContext *ctx) |
| 317 | { | 364 | { |
| 318 | int ret, i; | 365 | int ret, i; |
| @@ -329,6 +376,9 @@ static int filter_query_formats(AVFilterContext *ctx) · 10 unmodified lines | |||
| 329 | ctx->name, av_err2str(ret)); | 376 | ctx->name, av_err2str(ret)); |
| 330 | return ret; | 377 | return ret; |
| 331 | } | 378 | } |
| 379 | ret = filter_check_formats(ctx); | ||
| 380 | if (ret < 0) | ||
| 381 | return ret; | ||
| 332 | 382 | ||
| 333 | for (i = 0; i < ctx->nb_inputs; i++) | 383 | for (i = 0; i < ctx->nb_inputs; i++) |
| 334 | sanitize_channel_layouts(ctx, ctx->inputs[i]->outcfg.channel_layouts); | 384 | sanitize_channel_layouts(ctx, ctx->inputs[i]->outcfg.channel_layouts); |