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 | 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); |
| @@ -662,3 +662,73 @@ int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, · 661 unmodified lines | |||
| 662 | 662 | ||
| 663 | return 0; | 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 | void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref); | 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 | #endif /* AVFILTER_FORMATS_H */ | 322 | #endif /* AVFILTER_FORMATS_H */ |