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.
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); |
| @@ -662,3 +662,73 @@ int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, · 661 unmodified lines | ||
| 662 | 662 | |
| 663 | 663 | return 0; |
| 664 | 664 | } |
| 665 | + | |
| 666 | +static int check_list(void *log, const char *name, const AVFilterFormats *fmts) | |
| 667 | +{ | |
| 668 | + unsigned i, j; | |
| 669 | + | |
| 670 | + if (!fmts) | |
| 671 | + return 0; | |
| 672 | + if (!fmts->nb_formats) { | |
| 673 | + av_log(log, AV_LOG_ERROR, "Empty %s list\n", name); | |
| 674 | + return AVERROR(EINVAL); | |
| 675 | + } | |
| 676 | + for (i = 0; i < fmts->nb_formats; i++) { | |
| 677 | + for (j = i + 1; j < fmts->nb_formats; j++) { | |
| 678 | + if (fmts->formats[i] == fmts->formats[j]) { | |
| 679 | + av_log(log, AV_LOG_ERROR, "Duplicated %s\n", name); | |
| 680 | + return AVERROR(EINVAL); | |
| 681 | + } | |
| 682 | + } | |
| 683 | + } | |
| 684 | + return 0; | |
| 685 | +} | |
| 686 | + | |
| 687 | +int ff_formats_check_pixel_formats(void *log, const AVFilterFormats *fmts) | |
| 688 | +{ | |
| 689 | + return check_list(log, "pixel format", fmts); | |
| 690 | +} | |
| 691 | + | |
| 692 | +int ff_formats_check_sample_formats(void *log, const AVFilterFormats *fmts) | |
| 693 | +{ | |
| 694 | + return check_list(log, "sample format", fmts); | |
| 695 | +} | |
| 696 | + | |
| 697 | +int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts) | |
| 698 | +{ | |
| 699 | + if (!fmts || !fmts->nb_formats) | |
| 700 | + return 0; | |
| 701 | + return check_list(log, "sample rate", fmts); | |
| 702 | +} | |
| 703 | + | |
| 704 | +static int layouts_compatible(uint64_t a, uint64_t b) | |
| 705 | +{ | |
| 706 | + return a == b || | |
| 707 | + (KNOWN(a) && !KNOWN(b) && av_get_channel_layout_nb_channels(a) == FF_LAYOUT2COUNT(b)) || | |
| 708 | + (KNOWN(b) && !KNOWN(a) && av_get_channel_layout_nb_channels(b) == FF_LAYOUT2COUNT(a)); | |
| 709 | +} | |
| 710 | + | |
| 711 | +int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts) | |
| 712 | +{ | |
| 713 | + unsigned i, j; | |
| 714 | + | |
| 715 | + if (!fmts) | |
| 716 | + return 0; | |
| 717 | + if (fmts->all_layouts < fmts->all_counts) { | |
| 718 | + av_log(log, AV_LOG_ERROR, "Inconsistent generic list\n"); | |
| 719 | + return AVERROR(EINVAL); | |
| 720 | + } | |
| 721 | + if (!fmts->all_layouts && !fmts->nb_channel_layouts) { | |
| 722 | + av_log(log, AV_LOG_ERROR, "Empty channel layout list\n"); | |
| 723 | + return AVERROR(EINVAL); | |
| 724 | + } | |
| 725 | + for (i = 0; i < fmts->nb_channel_layouts; i++) { | |
| 726 | + for (j = i + 1; j < fmts->nb_channel_layouts; j++) { | |
| 727 | + if (layouts_compatible(fmts->channel_layouts[i], fmts->channel_layouts[j])) { | |
| 728 | + av_log(log, AV_LOG_ERROR, "Duplicated or redundant channel layout\n"); | |
| 729 | + return AVERROR(EINVAL); | |
| 730 | + } | |
| 731 | + } | |
| 732 | + } | |
| 733 | + return 0; | |
| 734 | +} | |
| @@ -291,4 +291,32 @@ void ff_formats_unref(AVFilterFormats **ref); · 290 unmodified lines | ||
| 291 | 291 | */ |
| 292 | 292 | void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref); |
| 293 | 293 | |
| 294 | +/** | |
| 295 | + * Check that fmts is a valid pixel formats list. | |
| 296 | + * | |
| 297 | + * In particular, check for duplicates. | |
| 298 | + */ | |
| 299 | +int ff_formats_check_pixel_formats(void *log, const AVFilterFormats *fmts); | |
| 300 | + | |
| 301 | +/** | |
| 302 | + * Check that fmts is a valid sample formats list. | |
| 303 | + * | |
| 304 | + * In particular, check for duplicates. | |
| 305 | + */ | |
| 306 | +int ff_formats_check_sample_formats(void *log, const AVFilterFormats *fmts); | |
| 307 | + | |
| 308 | +/** | |
| 309 | + * Check that fmts is a valid sample rates list. | |
| 310 | + * | |
| 311 | + * In particular, check for duplicates. | |
| 312 | + */ | |
| 313 | +int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts); | |
| 314 | + | |
| 315 | +/** | |
| 316 | + * Check that fmts is a valid channel layouts list. | |
| 317 | + * | |
| 318 | + * In particular, check for duplicates. | |
| 319 | + */ | |
| 320 | +int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts); | |
| 321 | + | |
| 294 | 322 | #endif /* AVFILTER_FORMATS_H */ |