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 | 363 | static int filter_query_formats(AVFilterContext *ctx) |
| 317 | 364 | { |
| 318 | 365 | int ret, i; |
| @@ -329,6 +376,9 @@ static int filter_query_formats(AVFilterContext *ctx) · 10 unmodified lines | ||
| 329 | 376 | ctx->name, av_err2str(ret)); |
| 330 | 377 | return ret; |
| 331 | 378 | } |
| 379 | + ret = filter_check_formats(ctx); | |
| 380 | + if (ret < 0) | |
| 381 | + return ret; | |
| 332 | 382 | |
| 333 | 383 | for (i = 0; i < ctx->nb_inputs; i++) |
| 334 | 384 | sanitize_channel_layouts(ctx, ctx->inputs[i]->outcfg.channel_layouts); |