By ffmpeg threading support implementation via frame slicing and doing zimg_filter_graph_build that used to take 30-60% of each frame processig only if necessary (some parameters changed) the performance increase vs original version in video downscale and color conversion >4x is seen on 64 cores Intel Xeon, 3x on i7-6700K (4 cores with HT)
Unified · Split
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Copyright (c) 2015 Paul B Mahol |
| 3 | + * Copyright (c) 2022 Victoria Zhislina, Intel | |
| 3 | 4 | * |
| 4 | 5 | * This file is part of FFmpeg. |
| 5 | 6 | * |
| @@ -44,6 +45,8 @@ · 38 unmodified lines | ||
| 44 | 45 | #include "libavutil/imgutils.h" |
| 45 | 46 | |
| 46 | 47 | #define ZIMG_ALIGNMENT 32 |
| 48 | +#define MIN_TILESIZE 64 | |
| 49 | +#define MAX_THREADS 64 | |
| 47 | 50 | |
| 48 | 51 | static const char *const var_names[] = { |
| 49 | 52 | "in_w", "iw", |
| @@ -113,13 +116,17 @@ typedef struct ZScaleContext { · 63 unmodified lines | ||
| 113 | 116 | |
| 114 | 117 | int force_original_aspect_ratio; |
| 115 | 118 | |
| 116 | − void *tmp; | |
| 117 | − size_t tmp_size; | |
| 119 | + void *tmp[MAX_THREADS]; //separate for each thread; | |
| 120 | + int nb_threads; | |
| 121 | + int slice_h; | |
| 118 | 122 | |
| 119 | 123 | zimg_image_format src_format, dst_format; |
| 120 | 124 | zimg_image_format alpha_src_format, alpha_dst_format; |
| 125 | + zimg_image_format src_format_tmp, dst_format_tmp; | |
| 126 | + zimg_image_format alpha_src_format_tmp, alpha_dst_format_tmp; | |
| 121 | 127 | zimg_graph_builder_params alpha_params, params; |
| 122 | − zimg_filter_graph *alpha_graph, *graph; | |
| 128 | + zimg_graph_builder_params alpha_params_tmp, params_tmp; | |
| 129 | + zimg_filter_graph *alpha_graph[MAX_THREADS], *graph[MAX_THREADS]; | |
| 123 | 130 | |
| 124 | 131 | enum AVColorSpace in_colorspace, out_colorspace; |
| 125 | 132 | enum AVColorTransferCharacteristic in_trc, out_trc; |
| @@ -128,10 +135,35 @@ typedef struct ZScaleContext { · 2 unmodified lines | ||
| 128 | 135 | enum AVChromaLocation in_chromal, out_chromal; |
| 129 | 136 | } ZScaleContext; |
| 130 | 137 | |
| 138 | +typedef struct ThreadData { | |
| 139 | + const AVPixFmtDescriptor *desc, *odesc; | |
| 140 | + AVFrame *in, *out; | |
| 141 | +} ThreadData; | |
| 142 | + | |
| 131 | 143 | static av_cold int init(AVFilterContext *ctx) |
| 132 | 144 | { |
| 133 | 145 | ZScaleContext *s = ctx->priv; |
| 134 | 146 | int ret; |
| 147 | + int i; | |
| 148 | + for (i = 0; i < MAX_THREADS; i++) { | |
| 149 | + s->tmp[i] = NULL; | |
| 150 | + s->graph[i] = NULL; | |
| 151 | + s->alpha_graph[i] = NULL; | |
| 152 | + } | |
| 153 | + zimg_image_format_default(&s->src_format, ZIMG_API_VERSION); | |
| 154 | + zimg_image_format_default(&s->dst_format, ZIMG_API_VERSION); | |
| 155 | + zimg_image_format_default(&s->src_format_tmp, ZIMG_API_VERSION); | |
| 156 | + zimg_image_format_default(&s->dst_format_tmp, ZIMG_API_VERSION); | |
| 157 | + | |
| 158 | + zimg_image_format_default(&s->alpha_src_format, ZIMG_API_VERSION); | |
| 159 | + zimg_image_format_default(&s->alpha_dst_format, ZIMG_API_VERSION); | |
| 160 | + zimg_image_format_default(&s->alpha_src_format_tmp, ZIMG_API_VERSION); | |
| 161 | + zimg_image_format_default(&s->alpha_dst_format_tmp, ZIMG_API_VERSION); | |
| 162 | + | |
| 163 | + zimg_graph_builder_params_default(&s->params, ZIMG_API_VERSION); | |
| 164 | + zimg_graph_builder_params_default(&s->params_tmp, ZIMG_API_VERSION); | |
| 165 | + zimg_graph_builder_params_default(&s->alpha_params, ZIMG_API_VERSION); | |
| 166 | + zimg_graph_builder_params_default(&s->alpha_params_tmp, ZIMG_API_VERSION); | |
| 135 | 167 | |
| 136 | 168 | if (s->size_str && (s->w_expr || s->h_expr)) { |
| 137 | 169 | av_log(ctx, AV_LOG_ERROR, |
| @@ -471,6 +503,51 @@ static enum AVColorRange convert_range_from_zimg(enum zimg_pixel_range_e color_r · 333 unmodified lines | ||
| 471 | 503 | return AVCOL_RANGE_UNSPECIFIED; |
| 472 | 504 | } |
| 473 | 505 | |
| 506 | +/* returns 0 if image formats are the same and 1 otherwise */ | |
| 507 | +static int compare_zimg_image_formats(zimg_image_format *img_fmt0, zimg_image_format *img_fmt1) | |
| 508 | +{ | |
| 509 | + return ((img_fmt0->chroma_location != img_fmt1->chroma_location) || | |
| 510 | +#if ZIMG_API_VERSION >= 0x204 | |
| 511 | + (img_fmt0->alpha != img_fmt1->alpha) || | |
| 512 | +#endif | |
| 513 | + (img_fmt0->color_family != img_fmt1->color_family) || | |
| 514 | + (img_fmt0->color_primaries != img_fmt1->color_primaries) || | |
| 515 | + (img_fmt0->depth != img_fmt1->depth) || | |
| 516 | + (img_fmt0->field_parity != img_fmt1->field_parity) || | |
| 517 | + (img_fmt0->height != img_fmt1->height) || | |
| 518 | + (img_fmt0->matrix_coefficients != img_fmt1->matrix_coefficients) || | |
| 519 | + (img_fmt0->pixel_range != img_fmt1->pixel_range) || | |
| 520 | + (img_fmt0->pixel_type != img_fmt1->pixel_type) || | |
| 521 | + (img_fmt0->subsample_h != img_fmt1->subsample_h) || | |
| 522 | + (img_fmt0->subsample_w != img_fmt1->subsample_w) || | |
| 523 | + (img_fmt0->transfer_characteristics != img_fmt1->transfer_characteristics) || | |
| 524 | + (img_fmt0->width != img_fmt1->width)); | |
| 525 | +} | |
| 526 | + | |
| 527 | +/* returns 0 if graph builder parameters are the same and 1 otherwise */ | |
| 528 | +static int compare_zimg_graph_builder_params(zimg_graph_builder_params *parm0, zimg_graph_builder_params *parm1) | |
| 529 | +{ | |
| 530 | + /* the parameters that could be changed inside a single ffmpeg zscale invocation are checked only | |
| 531 | + and NaN values that are default for some params are treated properly*/ | |
| 532 | + int ret = (parm0->allow_approximate_gamma != parm1->allow_approximate_gamma) || | |
| 533 | + (parm0->dither_type != parm1->dither_type) || | |
| 534 | + (parm0->resample_filter != parm1->resample_filter) || | |
| 535 | + (parm0->resample_filter_uv != parm1->resample_filter_uv); | |
| 536 | + | |
| 537 | + if ((isnan(parm0->nominal_peak_luminance) == 0) || (isnan(parm1->nominal_peak_luminance) == 0)) | |
| 538 | + ret = ret || (parm0->nominal_peak_luminance != parm1->nominal_peak_luminance); | |
| 539 | + if ((isnan(parm0->filter_param_a) == 0) || (isnan(parm1->filter_param_a) == 0)) | |
| 540 | + ret = ret || (parm0->filter_param_a != parm1->filter_param_a); | |
| 541 | + if ((isnan(parm0->filter_param_a_uv) == 0) || (isnan(parm1->filter_param_a_uv) == 0)) | |
| 542 | + ret = ret || (parm0->filter_param_a_uv != parm1->filter_param_a_uv); | |
| 543 | + if ((isnan(parm0->filter_param_b) == 0) || (isnan(parm1->filter_param_b) == 0)) | |
| 544 | + ret = ret || (parm0->filter_param_b != parm1->filter_param_b); | |
| 545 | + if ((isnan(parm0->filter_param_b_uv) == 0) || (isnan(parm1->filter_param_b_uv) == 0)) | |
| 546 | + ret = ret || (parm0->filter_param_b_uv != parm1->filter_param_b_uv); | |
| 547 | + | |
| 548 | + return ret; | |
| 549 | +} | |
| 550 | + | |
| 474 | 551 | static void format_init(zimg_image_format *format, AVFrame *frame, const AVPixFmtDescriptor *desc, |
| 475 | 552 | int colorspace, int primaries, int transfer, int range, int location) |
| 476 | 553 | { |
| @@ -483,46 +560,94 @@ static void format_init(zimg_image_format *format, AVFrame *frame, const AVPixFm · 6 unmodified lines | ||
| 483 | 560 | format->color_family = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_COLOR_RGB : ZIMG_COLOR_YUV; |
| 484 | 561 | format->matrix_coefficients = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_MATRIX_RGB : colorspace == -1 ? convert_matrix(frame->colorspace) : colorspace; |
| 485 | 562 | format->color_primaries = primaries == -1 ? convert_primaries(frame->color_primaries) : primaries; |
| 486 | − format->transfer_characteristics = transfer == - 1 ? convert_trc(frame->color_trc) : transfer; | |
| 563 | + format->transfer_characteristics = transfer == -1 ? convert_trc(frame->color_trc) : transfer; | |
| 487 | 564 | format->pixel_range = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_RANGE_FULL : range == -1 ? convert_range(frame->color_range) : range; |
| 488 | 565 | format->chroma_location = location == -1 ? convert_chroma_location(frame->chroma_location) : location; |
| 489 | 566 | } |
| 490 | 567 | |
| 491 | −static int graph_build(zimg_filter_graph **graph, zimg_graph_builder_params *params, | |
| 492 | − zimg_image_format *src_format, zimg_image_format *dst_format, | |
| 493 | − void **tmp, size_t *tmp_size) | |
| 568 | +static int graphs_build(AVFrame *in, AVFrame *out, const AVPixFmtDescriptor *desc, const AVPixFmtDescriptor *out_desc, | |
| 569 | + ZScaleContext *s, int job_nr) | |
| 494 | 570 | { |
| 495 | 571 | int ret; |
| 496 | 572 | size_t size; |
| 573 | + zimg_image_format src_format; | |
| 574 | + zimg_image_format dst_format; | |
| 575 | + zimg_image_format alpha_src_format; | |
| 576 | + zimg_image_format alpha_dst_format; | |
| 577 | + | |
| 578 | + src_format = s->src_format; | |
| 579 | + dst_format = s->dst_format; | |
| 580 | + /* The input slice is specified through the active_region field, | |
| 581 | + unlike the output slice. | |
| 582 | + according to zimg requirements input and output slices should have even dimentions */ | |
| 583 | + src_format.active_region.width = in->width; | |
| 584 | + src_format.active_region.height = s->slice_h; | |
| 585 | + src_format.active_region.left = 0; | |
| 586 | + src_format.active_region.top = job_nr * src_format.active_region.height; | |
| 587 | + //dst now is the single tile only!! | |
| 588 | + dst_format.width = out->width; | |
| 589 | + dst_format.height = ((unsigned int)(out->height / s->nb_threads)) & 0xfffffffe; | |
| 590 | + | |
| 591 | + //the last slice could differ from the previous ones due to the slices division "tail" | |
| 592 | + if (job_nr == (s->nb_threads - 1)) { | |
| 593 | + src_format.active_region.height = src_format.height - src_format.active_region.top; | |
| 594 | + dst_format.height = out->height - job_nr * dst_format.height; | |
| 595 | + } | |
| 497 | 596 | |
| 498 | − zimg_filter_graph_free(*graph); | |
| 499 | − *graph = zimg_filter_graph_build(src_format, dst_format, params); | |
| 500 | − if (!*graph) | |
| 597 | + if (s->graph[job_nr]) { | |
| 598 | + zimg_filter_graph_free(s->graph[job_nr]); | |
| 599 | + } | |
| 600 | + s->graph[job_nr] = zimg_filter_graph_build(&src_format, &dst_format, &s->params); | |
| 601 | + if (!s->graph[job_nr]) | |
| 501 | 602 | return print_zimg_error(NULL); |
| 502 | 603 | |
| 503 | − ret = zimg_filter_graph_get_tmp_size(*graph, &size); | |
| 604 | + ret = zimg_filter_graph_get_tmp_size(s->graph[job_nr], &size); | |
| 504 | 605 | if (ret) |
| 505 | 606 | return print_zimg_error(NULL); |
| 506 | 607 | |
| 507 | − if (size > *tmp_size) { | |
| 508 | − av_freep(tmp); | |
| 509 | − *tmp = av_malloc(size); | |
| 510 | − if (!*tmp) | |
| 511 | − return AVERROR(ENOMEM); | |
| 512 | − | |
| 513 | − *tmp_size = size; | |
| 514 | − } | |
| 608 | + if (s->tmp[job_nr]) | |
| 609 | + av_freep(&s->tmp[job_nr]); | |
| 610 | + s->tmp[job_nr] = av_malloc(size); | |
| 611 | + if (!s->tmp[job_nr]) | |
| 612 | + return AVERROR(ENOMEM); | |
| 613 | + | |
| 614 | + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && out_desc->flags & AV_PIX_FMT_FLAG_ALPHA) { | |
| 615 | + alpha_src_format = s->alpha_src_format; | |
| 616 | + alpha_dst_format = s->alpha_dst_format; | |
| 617 | + /* The input slice is specified through the active_region field, unlike the output slice. | |
| 618 | + according to zimg requirements input and output slices should have even dimentions */ | |
| 619 | + alpha_src_format.active_region.width = in->width; | |
| 620 | + alpha_src_format.active_region.height = s->slice_h; | |
| 621 | + alpha_src_format.active_region.left = 0; | |
| 622 | + alpha_src_format.active_region.top = job_nr * alpha_src_format.active_region.height; | |
| 623 | + //dst now is the single tile only!! | |
| 624 | + alpha_dst_format.width = out->width; | |
| 625 | + alpha_dst_format.height = ((unsigned int)(out->height / s->nb_threads)) & 0xfffffffe; | |
| 626 | + | |
| 627 | + //the last slice could differ from the previous ones due to the slices division "tail" | |
| 628 | + if (job_nr == (s->nb_threads - 1)) { | |
| 629 | + alpha_src_format.active_region.height = alpha_src_format.height - alpha_src_format.active_region.top; | |
| 630 | + alpha_dst_format.height = out->height - job_nr * alpha_dst_format.height; | |
| 631 | + } | |
| 515 | 632 | |
| 633 | + if (s->alpha_graph[job_nr]) { | |
| 634 | + zimg_filter_graph_free(s->alpha_graph[job_nr]); | |
| 635 | + } | |
| 636 | + s->alpha_graph[job_nr] = zimg_filter_graph_build(&alpha_src_format, &alpha_dst_format, &s->alpha_params); | |
| 637 | + if (!s->alpha_graph[job_nr]) | |
| 638 | + return print_zimg_error(NULL); | |
| 639 | + } | |
| 516 | 640 | return 0; |
| 517 | 641 | } |
| 518 | 642 | |
| 519 | 643 | static int realign_frame(const AVPixFmtDescriptor *desc, AVFrame **frame) |
| 520 | 644 | { |
| 521 | 645 | AVFrame *aligned = NULL; |
| 522 | − int ret = 0, plane; | |
| 646 | + int ret = 0, plane, planes; | |
| 523 | 647 | |
| 524 | 648 | /* Realign any unaligned input frame. */ |
| 525 | − for (plane = 0; plane < 3; plane++) { | |
| 649 | + planes = av_pix_fmt_count_planes(desc->nb_components); | |
| 650 | + for (plane = 0; plane < planes; plane++) { | |
| 526 | 651 | int p = desc->comp[plane].plane; |
| 527 | 652 | if ((uintptr_t)(*frame)->data[p] % ZIMG_ALIGNMENT || (*frame)->linesize[p] % ZIMG_ALIGNMENT) { |
| 528 | 653 | if (!(aligned = av_frame_alloc())) { |
| @@ -572,20 +697,77 @@ static void update_output_color_information(ZScaleContext *s, AVFrame *frame) · 43 unmodified lines | ||
| 572 | 697 | frame->chroma_location = (int)s->dst_format.chroma_location + 1; |
| 573 | 698 | } |
| 574 | 699 | |
| 700 | +static int filter_slice(AVFilterContext *ctx, void *data, int job_nr, int n_jobs) | |
| 701 | +{ | |
| 702 | + ThreadData *td = data; | |
| 703 | + int ret = 0; | |
| 704 | + int p; | |
| 705 | + int out_sampl; | |
| 706 | + int need_gb; | |
| 707 | + ZScaleContext *s = ctx->priv; | |
| 708 | + zimg_image_buffer_const src_buf = { ZIMG_API_VERSION }; | |
| 709 | + zimg_image_buffer dst_buf = { ZIMG_API_VERSION }; | |
| 710 | + int dst_tile_height = ((unsigned int)(td->out->height / n_jobs)) & 0xfffffffe; | |
| 711 | + | |
| 712 | + /* create zimg filter graphs for each thread | |
| 713 | + only if not created earlier or there is some change in frame parameters */ | |
| 714 | + need_gb = compare_zimg_image_formats(&s->src_format, &s->src_format_tmp) || | |
| 715 | + compare_zimg_image_formats(&s->dst_format, &s->dst_format_tmp) || | |
| 716 | + compare_zimg_graph_builder_params(&s->params, &s->params_tmp); | |
| 717 | + if(td->desc->flags & AV_PIX_FMT_FLAG_ALPHA && td->odesc->flags & AV_PIX_FMT_FLAG_ALPHA) | |
| 718 | + need_gb = need_gb || compare_zimg_image_formats(&s->alpha_src_format, &s->alpha_src_format_tmp) || | |
| 719 | + compare_zimg_image_formats(&s->alpha_dst_format, &s->alpha_dst_format_tmp) || | |
| 720 | + compare_zimg_graph_builder_params(&s->alpha_params, &s->alpha_params_tmp); | |
| 721 | + | |
| 722 | + if (need_gb){ | |
| 723 | + ret = graphs_build(td->in, td->out, td->desc, td->odesc, s, job_nr); | |
| 724 | + if (ret < 0) | |
| 725 | + return print_zimg_error(ctx); | |
| 726 | + } | |
| 727 | + out_sampl = FFMAX3(td->out->linesize[0], td->out->linesize[1], td->out->linesize[2]); | |
| 728 | + for (int i = 0; i < 3; i++) { | |
| 729 | + p = td->desc->comp[i].plane; | |
| 730 | + | |
| 731 | + src_buf.plane[i].data = td->in->data[p]; | |
| 732 | + src_buf.plane[i].stride = td->in->linesize[p]; | |
| 733 | + src_buf.plane[i].mask = -1; | |
| 734 | + | |
| 735 | + p = td->odesc->comp[i].plane; | |
| 736 | + dst_buf.plane[i].data = td->out->data[p] + td->out->linesize[p] * dst_tile_height * td->out->linesize[p] / out_sampl * job_nr; | |
| 737 | + dst_buf.plane[i].stride = td->out->linesize[p]; | |
| 738 | + dst_buf.plane[i].mask = -1; | |
| 739 | + } | |
| 740 | + ret = zimg_filter_graph_process(s->graph[job_nr], &src_buf, &dst_buf, s->tmp[job_nr], 0, 0, 0, 0); | |
| 741 | + if (ret) | |
| 742 | + return print_zimg_error(ctx); | |
| 743 | + | |
| 744 | + if (td->desc->flags & AV_PIX_FMT_FLAG_ALPHA && td->odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | |
| 745 | + src_buf.plane[0].data = td->in->data[3]; | |
| 746 | + src_buf.plane[0].stride = td->in->linesize[3]; | |
| 747 | + src_buf.plane[0].mask = -1; | |
| 748 | + | |
| 749 | + dst_buf.plane[0].data = td->out->data[3] + td->out->linesize[3] * dst_tile_height * job_nr; | |
| 750 | + dst_buf.plane[0].stride = td->out->linesize[3]; | |
| 751 | + dst_buf.plane[0].mask = -1; | |
| 752 | + | |
| 753 | + ret = zimg_filter_graph_process(s->alpha_graph[job_nr], &src_buf, &dst_buf, s->tmp[job_nr], 0, 0, 0, 0); | |
| 754 | + if (ret) | |
| 755 | + return print_zimg_error(ctx); | |
| 756 | + } | |
| 757 | + return 0; | |
| 758 | +} | |
| 759 | + | |
| 575 | 760 | static int filter_frame(AVFilterLink *link, AVFrame *in) |
| 576 | 761 | { |
| 577 | − ZScaleContext *s = link->dst->priv; | |
| 578 | − AVFilterLink *outlink = link->dst->outputs[0]; | |
| 762 | + AVFilterContext *ctx = link->dst; | |
| 763 | + ZScaleContext *s = ctx->priv; | |
| 764 | + AVFilterLink *outlink = ctx->outputs[0]; | |
| 579 | 765 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); |
| 580 | 766 | const AVPixFmtDescriptor *odesc = av_pix_fmt_desc_get(outlink->format); |
| 581 | − zimg_image_buffer_const src_buf = { ZIMG_API_VERSION }; | |
| 582 | − zimg_image_buffer dst_buf = { ZIMG_API_VERSION }; | |
| 583 | 767 | char buf[32]; |
| 584 | − int ret = 0, plane; | |
| 768 | + int ret = 0; | |
| 585 | 769 | AVFrame *out = NULL; |
| 586 | − | |
| 587 | − if ((ret = realign_frame(desc, &in)) < 0) | |
| 588 | − goto fail; | |
| 770 | + ThreadData td; | |
| 589 | 771 | |
| 590 | 772 | if (!(out = ff_get_video_buffer(outlink, outlink->w, outlink->h))) { |
| 591 | 773 | ret = AVERROR(ENOMEM); |
| @@ -596,19 +778,23 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 4 unmodified lines | ||
| 596 | 778 | out->width = outlink->w; |
| 597 | 779 | out->height = outlink->h; |
| 598 | 780 | |
| 599 | − if( in->width != link->w | |
| 600 | − || in->height != link->h | |
| 601 | − || in->format != link->format | |
| 602 | − || s->in_colorspace != in->colorspace | |
| 603 | − || s->in_trc != in->color_trc | |
| 604 | − || s->in_primaries != in->color_primaries | |
| 605 | − || s->in_range != in->color_range | |
| 606 | − || s->out_colorspace != out->colorspace | |
| 607 | − || s->out_trc != out->color_trc | |
| 608 | − || s->out_primaries != out->color_primaries | |
| 609 | − || s->out_range != out->color_range | |
| 610 | − || s->in_chromal != in->chroma_location | |
| 611 | − || s->out_chromal != out->chroma_location) { | |
| 781 | + //we need to use this filter if something is different for an input and output only | |
| 782 | + //otherwise - just copy the input frame to the output | |
| 783 | + if ((link->w != outlink->w) || | |
| 784 | + (link->h != outlink->h) || | |
| 785 | + (s->src_format.chroma_location != s->dst_format.chroma_location) || | |
| 786 | + (s->src_format.color_family !=s->dst_format.color_family) || | |
| 787 | + (s->src_format.color_primaries !=s->dst_format.color_primaries) || | |
| 788 | + (s->src_format.depth !=s->dst_format.depth) || | |
| 789 | + (s->src_format.matrix_coefficients !=s->dst_format.matrix_coefficients) || | |
| 790 | + (s->src_format.field_parity !=s->dst_format.field_parity) || | |
| 791 | + (s->src_format.pixel_range !=s->dst_format.pixel_range) || | |
| 792 | + (s->src_format.pixel_type !=s->dst_format.pixel_type) || | |
| 793 | + (s->src_format.transfer_characteristics !=s->dst_format.transfer_characteristics) | |
| 794 | + ){ | |
| 795 | + if ((ret = realign_frame(desc, &in)) < 0) | |
| 796 | + goto fail; | |
| 797 | + | |
| 612 | 798 | snprintf(buf, sizeof(buf)-1, "%d", outlink->w); |
| 613 | 799 | av_opt_set(s, "w", buf, 0); |
| 614 | 800 | snprintf(buf, sizeof(buf)-1, "%d", outlink->h); |
| @@ -618,13 +804,26 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 3 unmodified lines | ||
| 618 | 804 | link->dst->inputs[0]->w = in->width; |
| 619 | 805 | link->dst->inputs[0]->h = in->height; |
| 620 | 806 | |
| 621 | − if ((ret = config_props(outlink)) < 0) | |
| 622 | − goto fail; | |
| 807 | + s->nb_threads = FFMIN(ff_filter_get_nb_threads(ctx), link->h / MIN_TILESIZE); | |
| 808 | + s->slice_h = ((unsigned int)(link->h / s->nb_threads)) & 0xfffffffe; // slice_h should be even for zimg | |
| 809 | + s->in_colorspace = in->colorspace; | |
| 810 | + s->in_trc = in->color_trc; | |
| 811 | + s->in_primaries = in->color_primaries; | |
| 812 | + s->in_range = in->color_range; | |
| 813 | + s->out_colorspace = out->colorspace; | |
| 814 | + s->out_trc = out->color_trc; | |
| 815 | + s->out_primaries = out->color_primaries; | |
| 816 | + s->out_range = out->color_range; | |
| 623 | 817 | |
| 624 | 818 | zimg_image_format_default(&s->src_format, ZIMG_API_VERSION); |
| 625 | 819 | zimg_image_format_default(&s->dst_format, ZIMG_API_VERSION); |
| 626 | 820 | zimg_graph_builder_params_default(&s->params, ZIMG_API_VERSION); |
| 627 | 821 | |
| 822 | + format_init(&s->src_format, in, desc, s->colorspace_in, | |
| 823 | + s->primaries_in, s->trc_in, s->range_in, s->chromal_in); | |
| 824 | + format_init(&s->dst_format, out, odesc, s->colorspace, | |
| 825 | + s->primaries, s->trc, s->range, s->chromal); | |
| 826 | + | |
| 628 | 827 | s->params.dither_type = s->dither; |
| 629 | 828 | s->params.cpu_type = ZIMG_CPU_AUTO; |
| 630 | 829 | s->params.resample_filter = s->filter; |
| @@ -634,27 +833,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 3 unmodified lines | ||
| 634 | 833 | s->params.filter_param_a = s->params.filter_param_a_uv = s->param_a; |
| 635 | 834 | s->params.filter_param_b = s->params.filter_param_b_uv = s->param_b; |
| 636 | 835 | |
| 637 | − format_init(&s->src_format, in, desc, s->colorspace_in, | |
| 638 | − s->primaries_in, s->trc_in, s->range_in, s->chromal_in); | |
| 639 | − format_init(&s->dst_format, out, odesc, s->colorspace, | |
| 640 | − s->primaries, s->trc, s->range, s->chromal); | |
| 641 | − | |
| 642 | − update_output_color_information(s, out); | |
| 643 | − | |
| 644 | − ret = graph_build(&s->graph, &s->params, &s->src_format, &s->dst_format, | |
| 645 | − &s->tmp, &s->tmp_size); | |
| 646 | − if (ret < 0) | |
| 647 | − goto fail; | |
| 648 | − | |
| 649 | − s->in_colorspace = in->colorspace; | |
| 650 | − s->in_trc = in->color_trc; | |
| 651 | − s->in_primaries = in->color_primaries; | |
| 652 | − s->in_range = in->color_range; | |
| 653 | − s->out_colorspace = out->colorspace; | |
| 654 | − s->out_trc = out->color_trc; | |
| 655 | − s->out_primaries = out->color_primaries; | |
| 656 | − s->out_range = out->color_range; | |
| 657 | − | |
| 658 | 836 | if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { |
| 659 | 837 | zimg_image_format_default(&s->alpha_src_format, ZIMG_API_VERSION); |
| 660 | 838 | zimg_image_format_default(&s->alpha_dst_format, ZIMG_API_VERSION); |
| @@ -670,76 +848,52 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 9 unmodified lines | ||
| 670 | 848 | s->alpha_src_format.pixel_type = (desc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : desc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; |
| 671 | 849 | s->alpha_src_format.color_family = ZIMG_COLOR_GREY; |
| 672 | 850 | |
| 673 | − s->alpha_dst_format.width = out->width; | |
| 674 | − s->alpha_dst_format.height = out->height; | |
| 675 | 851 | s->alpha_dst_format.depth = odesc->comp[0].depth; |
| 676 | 852 | s->alpha_dst_format.pixel_type = (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : odesc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; |
| 677 | 853 | s->alpha_dst_format.color_family = ZIMG_COLOR_GREY; |
| 678 | − | |
| 679 | − zimg_filter_graph_free(s->alpha_graph); | |
| 680 | − s->alpha_graph = zimg_filter_graph_build(&s->alpha_src_format, &s->alpha_dst_format, &s->alpha_params); | |
| 681 | − if (!s->alpha_graph) { | |
| 682 | − ret = print_zimg_error(link->dst); | |
| 683 | − goto fail; | |
| 684 | − } | |
| 685 | 854 | } |
| 686 | − } | |
| 687 | − | |
| 688 | − update_output_color_information(s, out); | |
| 689 | − | |
| 690 | − av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den, | |
| 691 | − (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w, | |
| 692 | − (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h, | |
| 693 | − INT_MAX); | |
| 694 | − | |
| 695 | − for (plane = 0; plane < 3; plane++) { | |
| 696 | − int p = desc->comp[plane].plane; | |
| 697 | − src_buf.plane[plane].data = in->data[p]; | |
| 698 | − src_buf.plane[plane].stride = in->linesize[p]; | |
| 699 | − src_buf.plane[plane].mask = -1; | |
| 700 | − | |
| 701 | − p = odesc->comp[plane].plane; | |
| 702 | − dst_buf.plane[plane].data = out->data[p]; | |
| 703 | − dst_buf.plane[plane].stride = out->linesize[p]; | |
| 704 | − dst_buf.plane[plane].mask = -1; | |
| 705 | − } | |
| 706 | 855 | |
| 707 | − ret = zimg_filter_graph_process(s->graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); | |
| 708 | − if (ret) { | |
| 709 | − ret = print_zimg_error(link->dst); | |
| 710 | − goto fail; | |
| 711 | − } | |
| 856 | + update_output_color_information(s, out); | |
| 857 | + av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den, | |
| 858 | + (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w, | |
| 859 | + (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h, | |
| 860 | + INT_MAX); | |
| 712 | 861 | |
| 713 | − if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | |
| 714 | − src_buf.plane[0].data = in->data[3]; | |
| 715 | − src_buf.plane[0].stride = in->linesize[3]; | |
| 716 | − src_buf.plane[0].mask = -1; | |
| 862 | + td.in = in; | |
| 863 | + td.out = out; | |
| 864 | + td.desc = desc; | |
| 865 | + td.odesc = odesc; | |
| 717 | 866 | |
| 718 | − dst_buf.plane[0].data = out->data[3]; | |
| 719 | − dst_buf.plane[0].stride = out->linesize[3]; | |
| 720 | − dst_buf.plane[0].mask = -1; | |
| 867 | + ff_filter_execute(ctx, filter_slice, &td, NULL, s->nb_threads); | |
| 721 | 868 | |
| 722 | − ret = zimg_filter_graph_process(s->alpha_graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); | |
| 723 | − if (ret) { | |
| 724 | − ret = print_zimg_error(link->dst); | |
| 725 | − goto fail; | |
| 869 | + s->src_format_tmp = s->src_format; | |
| 870 | + s->dst_format_tmp = s->dst_format; | |
| 871 | + s->params_tmp = s->params; | |
| 872 | + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | |
| 873 | + s->alpha_src_format_tmp = s->alpha_src_format; | |
| 874 | + s->alpha_dst_format_tmp = s->alpha_dst_format; | |
| 875 | + s->alpha_params_tmp = s->alpha_params; | |
| 726 | 876 | } |
| 727 | − } else if (odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | |
| 728 | − int x, y; | |
| 729 | − | |
| 730 | − if (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) { | |
| 731 | − for (y = 0; y < out->height; y++) { | |
| 732 | − for (x = 0; x < out->width; x++) { | |
| 733 | − AV_WN32(out->data[3] + x * odesc->comp[3].step + y * out->linesize[3], | |
| 734 | − av_float2int(1.0f)); | |
| 877 | + | |
| 878 | + if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) && (odesc->flags & AV_PIX_FMT_FLAG_ALPHA) ){ | |
| 879 | + int x, y; | |
| 880 | + if (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) { | |
| 881 | + for (y = 0; y < out->height; y++) { | |
| 882 | + for (x = 0; x < out->width; x++) { | |
| 883 | + AV_WN32(out->data[3] + x * odesc->comp[3].step + y * out->linesize[3], | |
| 884 | + av_float2int(1.0f)); | |
| 885 | + } | |
| 735 | 886 | } |
| 887 | + } else { | |
| 888 | + for (y = 0; y < outlink->h; y++) | |
| 889 | + memset(out->data[3] + y * out->linesize[3], 0xff, outlink->w); | |
| 736 | 890 | } |
| 737 | − } else { | |
| 738 | − for (y = 0; y < outlink->h; y++) | |
| 739 | − memset(out->data[3] + y * out->linesize[3], 0xff, outlink->w); | |
| 740 | 891 | } |
| 741 | 892 | } |
| 742 | − | |
| 893 | + else { | |
| 894 | + /*no need for any filtering */ | |
| 895 | + return ff_filter_frame(outlink, in); | |
| 896 | + } | |
| 743 | 897 | fail: |
| 744 | 898 | av_frame_free(&in); |
| 745 | 899 | if (ret) { |
| @@ -754,10 +908,11 @@ static av_cold void uninit(AVFilterContext *ctx) · 8 unmodified lines | ||
| 754 | 908 | { |
| 755 | 909 | ZScaleContext *s = ctx->priv; |
| 756 | 910 | |
| 757 | − zimg_filter_graph_free(s->graph); | |
| 758 | − zimg_filter_graph_free(s->alpha_graph); | |
| 759 | − av_freep(&s->tmp); | |
| 760 | − s->tmp_size = 0; | |
| 911 | + for (int i = 0; i < s->nb_threads; i++) { | |
| 912 | + av_freep(&s->tmp[i]); | |
| 913 | + zimg_filter_graph_free(s->graph[i]); | |
| 914 | + zimg_filter_graph_free(s->alpha_graph[i]); | |
| 915 | + } | |
| 761 | 916 | } |
| 762 | 917 | |
| 763 | 918 | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, |
| @@ -941,4 +1096,5 @@ const AVFilter ff_vf_zscale = { · 177 unmodified lines | ||
| 941 | 1096 | FILTER_OUTPUTS(avfilter_vf_zscale_outputs), |
| 942 | 1097 | FILTER_QUERY_FUNC(query_formats), |
| 943 | 1098 | .process_command = process_command, |
| 1099 | + .flags = AVFILTER_FLAG_SLICE_THREADS, | |
| 944 | 1100 | }; |