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)
Showing the changes to libavfilter (1 of 1 file). Show all
Unified · Split
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2015 Paul B Mahol | 2 | * Copyright (c) 2015 Paul B Mahol |
| 3 | * Copyright (c) 2022 Victoria Zhislina, Intel | ||
| 3 | * | 4 | * |
| 4 | * This file is part of FFmpeg. | 5 | * This file is part of FFmpeg. |
| 5 | * | 6 | * |
| @@ -44,6 +45,8 @@ · 38 unmodified lines | |||
| 44 | #include "libavutil/imgutils.h" | 45 | #include "libavutil/imgutils.h" |
| 45 | 46 | ||
| 46 | #define ZIMG_ALIGNMENT 32 | 47 | #define ZIMG_ALIGNMENT 32 |
| 48 | #define MIN_TILESIZE 64 | ||
| 49 | #define MAX_THREADS 64 | ||
| 47 | 50 | ||
| 48 | static const char *const var_names[] = { | 51 | static const char *const var_names[] = { |
| 49 | "in_w", "iw", | 52 | "in_w", "iw", |
| @@ -113,13 +116,17 @@ typedef struct ZScaleContext { · 63 unmodified lines | |||
| 113 | 116 | ||
| 114 | int force_original_aspect_ratio; | 117 | int force_original_aspect_ratio; |
| 115 | 118 | ||
| 116 | void *tmp; | 119 | void *tmp[MAX_THREADS]; //separate for each thread; |
| 117 | size_t tmp_size; | 120 | int nb_threads; |
| 121 | int slice_h; | ||
| 118 | 122 | ||
| 119 | zimg_image_format src_format, dst_format; | 123 | zimg_image_format src_format, dst_format; |
| 120 | zimg_image_format alpha_src_format, alpha_dst_format; | 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 | zimg_graph_builder_params alpha_params, params; | 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 | enum AVColorSpace in_colorspace, out_colorspace; | 131 | enum AVColorSpace in_colorspace, out_colorspace; |
| 125 | enum AVColorTransferCharacteristic in_trc, out_trc; | 132 | enum AVColorTransferCharacteristic in_trc, out_trc; |
| @@ -128,10 +135,35 @@ typedef struct ZScaleContext { · 2 unmodified lines | |||
| 128 | enum AVChromaLocation in_chromal, out_chromal; | 135 | enum AVChromaLocation in_chromal, out_chromal; |
| 129 | } ZScaleContext; | 136 | } ZScaleContext; |
| 130 | 137 | ||
| 138 | typedef struct ThreadData { | ||
| 139 | const AVPixFmtDescriptor *desc, *odesc; | ||
| 140 | AVFrame *in, *out; | ||
| 141 | } ThreadData; | ||
| 142 | |||
| 131 | static av_cold int init(AVFilterContext *ctx) | 143 | static av_cold int init(AVFilterContext *ctx) |
| 132 | { | 144 | { |
| 133 | ZScaleContext *s = ctx->priv; | 145 | ZScaleContext *s = ctx->priv; |
| 134 | int ret; | 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 | if (s->size_str && (s->w_expr || s->h_expr)) { | 168 | if (s->size_str && (s->w_expr || s->h_expr)) { |
| 137 | av_log(ctx, AV_LOG_ERROR, | 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 | return AVCOL_RANGE_UNSPECIFIED; | 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 | static void format_init(zimg_image_format *format, AVFrame *frame, const AVPixFmtDescriptor *desc, | 551 | static void format_init(zimg_image_format *format, AVFrame *frame, const AVPixFmtDescriptor *desc, |
| 475 | int colorspace, int primaries, int transfer, int range, int location) | 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 | format->color_family = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_COLOR_RGB : ZIMG_COLOR_YUV; | 560 | format->color_family = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_COLOR_RGB : ZIMG_COLOR_YUV; |
| 484 | format->matrix_coefficients = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_MATRIX_RGB : colorspace == -1 ? convert_matrix(frame->colorspace) : colorspace; | 561 | format->matrix_coefficients = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_MATRIX_RGB : colorspace == -1 ? convert_matrix(frame->colorspace) : colorspace; |
| 485 | format->color_primaries = primaries == -1 ? convert_primaries(frame->color_primaries) : primaries; | 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 | format->pixel_range = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_RANGE_FULL : range == -1 ? convert_range(frame->color_range) : range; | 564 | format->pixel_range = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? ZIMG_RANGE_FULL : range == -1 ? convert_range(frame->color_range) : range; |
| 488 | format->chroma_location = location == -1 ? convert_chroma_location(frame->chroma_location) : location; | 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, | 568 | static int graphs_build(AVFrame *in, AVFrame *out, const AVPixFmtDescriptor *desc, const AVPixFmtDescriptor *out_desc, |
| 492 | zimg_image_format *src_format, zimg_image_format *dst_format, | 569 | ZScaleContext *s, int job_nr) |
| 493 | void **tmp, size_t *tmp_size) | ||
| 494 | { | 570 | { |
| 495 | int ret; | 571 | int ret; |
| 496 | size_t size; | 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); | 597 | if (s->graph[job_nr]) { |
| 499 | *graph = zimg_filter_graph_build(src_format, dst_format, params); | 598 | zimg_filter_graph_free(s->graph[job_nr]); |
| 500 | if (!*graph) | 599 | } |
| 600 | s->graph[job_nr] = zimg_filter_graph_build(&src_format, &dst_format, &s->params); | ||
| 601 | if (!s->graph[job_nr]) | ||
| 501 | return print_zimg_error(NULL); | 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 | if (ret) | 605 | if (ret) |
| 505 | return print_zimg_error(NULL); | 606 | return print_zimg_error(NULL); |
| 506 | 607 | ||
| 507 | if (size > *tmp_size) { | 608 | if (s->tmp[job_nr]) |
| 508 | av_freep(tmp); | 609 | av_freep(&s->tmp[job_nr]); |
| 509 | *tmp = av_malloc(size); | 610 | s->tmp[job_nr] = av_malloc(size); |
| 510 | if (!*tmp) | 611 | if (!s->tmp[job_nr]) |
| 511 | return AVERROR(ENOMEM); | 612 | return AVERROR(ENOMEM); |
| 512 | 613 | ||
| 513 | *tmp_size = size; | 614 | if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && out_desc->flags & AV_PIX_FMT_FLAG_ALPHA) { |
| 514 | } | 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 | return 0; | 640 | return 0; |
| 517 | } | 641 | } |
| 518 | 642 | ||
| 519 | static int realign_frame(const AVPixFmtDescriptor *desc, AVFrame **frame) | 643 | static int realign_frame(const AVPixFmtDescriptor *desc, AVFrame **frame) |
| 520 | { | 644 | { |
| 521 | AVFrame *aligned = NULL; | 645 | AVFrame *aligned = NULL; |
| 522 | int ret = 0, plane; | 646 | int ret = 0, plane, planes; |
| 523 | 647 | ||
| 524 | /* Realign any unaligned input frame. */ | 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 | int p = desc->comp[plane].plane; | 651 | int p = desc->comp[plane].plane; |
| 527 | if ((uintptr_t)(*frame)->data[p] % ZIMG_ALIGNMENT || (*frame)->linesize[p] % ZIMG_ALIGNMENT) { | 652 | if ((uintptr_t)(*frame)->data[p] % ZIMG_ALIGNMENT || (*frame)->linesize[p] % ZIMG_ALIGNMENT) { |
| 528 | if (!(aligned = av_frame_alloc())) { | 653 | if (!(aligned = av_frame_alloc())) { |
| @@ -572,20 +697,77 @@ static void update_output_color_information(ZScaleContext *s, AVFrame *frame) · 43 unmodified lines | |||
| 572 | frame->chroma_location = (int)s->dst_format.chroma_location + 1; | 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 | static int filter_frame(AVFilterLink *link, AVFrame *in) | 760 | static int filter_frame(AVFilterLink *link, AVFrame *in) |
| 576 | { | 761 | { |
| 577 | ZScaleContext *s = link->dst->priv; | 762 | AVFilterContext *ctx = link->dst; |
| 578 | AVFilterLink *outlink = link->dst->outputs[0]; | 763 | ZScaleContext *s = ctx->priv; |
| 764 | AVFilterLink *outlink = ctx->outputs[0]; | ||
| 579 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | 765 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); |
| 580 | const AVPixFmtDescriptor *odesc = av_pix_fmt_desc_get(outlink->format); | 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 | char buf[32]; | 767 | char buf[32]; |
| 584 | int ret = 0, plane; | 768 | int ret = 0; |
| 585 | AVFrame *out = NULL; | 769 | AVFrame *out = NULL; |
| 586 | 770 | ThreadData td; | |
| 587 | if ((ret = realign_frame(desc, &in)) < 0) | ||
| 588 | goto fail; | ||
| 589 | 771 | ||
| 590 | if (!(out = ff_get_video_buffer(outlink, outlink->w, outlink->h))) { | 772 | if (!(out = ff_get_video_buffer(outlink, outlink->w, outlink->h))) { |
| 591 | ret = AVERROR(ENOMEM); | 773 | ret = AVERROR(ENOMEM); |
| @@ -596,19 +778,23 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 4 unmodified lines | |||
| 596 | out->width = outlink->w; | 778 | out->width = outlink->w; |
| 597 | out->height = outlink->h; | 779 | out->height = outlink->h; |
| 598 | 780 | ||
| 599 | if( in->width != link->w | 781 | //we need to use this filter if something is different for an input and output only |
| 600 | || in->height != link->h | 782 | //otherwise - just copy the input frame to the output |
| 601 | || in->format != link->format | 783 | if ((link->w != outlink->w) || |
| 602 | || s->in_colorspace != in->colorspace | 784 | (link->h != outlink->h) || |
| 603 | || s->in_trc != in->color_trc | 785 | (s->src_format.chroma_location != s->dst_format.chroma_location) || |
| 604 | || s->in_primaries != in->color_primaries | 786 | (s->src_format.color_family !=s->dst_format.color_family) || |
| 605 | || s->in_range != in->color_range | 787 | (s->src_format.color_primaries !=s->dst_format.color_primaries) || |
| 606 | || s->out_colorspace != out->colorspace | 788 | (s->src_format.depth !=s->dst_format.depth) || |
| 607 | || s->out_trc != out->color_trc | 789 | (s->src_format.matrix_coefficients !=s->dst_format.matrix_coefficients) || |
| 608 | || s->out_primaries != out->color_primaries | 790 | (s->src_format.field_parity !=s->dst_format.field_parity) || |
| 609 | || s->out_range != out->color_range | 791 | (s->src_format.pixel_range !=s->dst_format.pixel_range) || |
| 610 | || s->in_chromal != in->chroma_location | 792 | (s->src_format.pixel_type !=s->dst_format.pixel_type) || |
| 611 | || s->out_chromal != out->chroma_location) { | 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 | snprintf(buf, sizeof(buf)-1, "%d", outlink->w); | 798 | snprintf(buf, sizeof(buf)-1, "%d", outlink->w); |
| 613 | av_opt_set(s, "w", buf, 0); | 799 | av_opt_set(s, "w", buf, 0); |
| 614 | snprintf(buf, sizeof(buf)-1, "%d", outlink->h); | 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 | link->dst->inputs[0]->w = in->width; | 804 | link->dst->inputs[0]->w = in->width; |
| 619 | link->dst->inputs[0]->h = in->height; | 805 | link->dst->inputs[0]->h = in->height; |
| 620 | 806 | ||
| 621 | if ((ret = config_props(outlink)) < 0) | 807 | s->nb_threads = FFMIN(ff_filter_get_nb_threads(ctx), link->h / MIN_TILESIZE); |
| 622 | goto fail; | 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 | zimg_image_format_default(&s->src_format, ZIMG_API_VERSION); | 818 | zimg_image_format_default(&s->src_format, ZIMG_API_VERSION); |
| 625 | zimg_image_format_default(&s->dst_format, ZIMG_API_VERSION); | 819 | zimg_image_format_default(&s->dst_format, ZIMG_API_VERSION); |
| 626 | zimg_graph_builder_params_default(&s->params, ZIMG_API_VERSION); | 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 | s->params.dither_type = s->dither; | 827 | s->params.dither_type = s->dither; |
| 629 | s->params.cpu_type = ZIMG_CPU_AUTO; | 828 | s->params.cpu_type = ZIMG_CPU_AUTO; |
| 630 | s->params.resample_filter = s->filter; | 829 | s->params.resample_filter = s->filter; |
| @@ -634,27 +833,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 3 unmodified lines | |||
| 634 | s->params.filter_param_a = s->params.filter_param_a_uv = s->param_a; | 833 | s->params.filter_param_a = s->params.filter_param_a_uv = s->param_a; |
| 635 | s->params.filter_param_b = s->params.filter_param_b_uv = s->param_b; | 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 | if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | 836 | if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { |
| 659 | zimg_image_format_default(&s->alpha_src_format, ZIMG_API_VERSION); | 837 | zimg_image_format_default(&s->alpha_src_format, ZIMG_API_VERSION); |
| 660 | zimg_image_format_default(&s->alpha_dst_format, ZIMG_API_VERSION); | 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 | 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; | 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 | s->alpha_src_format.color_family = ZIMG_COLOR_GREY; | 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 | s->alpha_dst_format.depth = odesc->comp[0].depth; | 851 | s->alpha_dst_format.depth = odesc->comp[0].depth; |
| 676 | 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; | 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 | s->alpha_dst_format.color_family = ZIMG_COLOR_GREY; | 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); | 856 | update_output_color_information(s, out); |
| 708 | if (ret) { | 857 | av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den, |
| 709 | ret = print_zimg_error(link->dst); | 858 | (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w, |
| 710 | goto fail; | 859 | (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h, |
| 711 | } | 860 | INT_MAX); |
| 712 | 861 | ||
| 713 | if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { | 862 | td.in = in; |
| 714 | src_buf.plane[0].data = in->data[3]; | 863 | td.out = out; |
| 715 | src_buf.plane[0].stride = in->linesize[3]; | 864 | td.desc = desc; |
| 716 | src_buf.plane[0].mask = -1; | 865 | td.odesc = odesc; |
| 717 | 866 | ||
| 718 | dst_buf.plane[0].data = out->data[3]; | 867 | ff_filter_execute(ctx, filter_slice, &td, NULL, s->nb_threads); |
| 719 | dst_buf.plane[0].stride = out->linesize[3]; | ||
| 720 | dst_buf.plane[0].mask = -1; | ||
| 721 | 868 | ||
| 722 | ret = zimg_filter_graph_process(s->alpha_graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); | 869 | s->src_format_tmp = s->src_format; |
| 723 | if (ret) { | 870 | s->dst_format_tmp = s->dst_format; |
| 724 | ret = print_zimg_error(link->dst); | 871 | s->params_tmp = s->params; |
| 725 | goto fail; | 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) { | 877 | |
| 728 | int x, y; | 878 | if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) && (odesc->flags & AV_PIX_FMT_FLAG_ALPHA) ){ |
| 729 | 879 | int x, y; | |
| 730 | if (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) { | 880 | if (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) { |
| 731 | for (y = 0; y < out->height; y++) { | 881 | for (y = 0; y < out->height; y++) { |
| 732 | for (x = 0; x < out->width; x++) { | 882 | for (x = 0; x < out->width; x++) { |
| 733 | AV_WN32(out->data[3] + x * odesc->comp[3].step + y * out->linesize[3], | 883 | AV_WN32(out->data[3] + x * odesc->comp[3].step + y * out->linesize[3], |
| 734 | av_float2int(1.0f)); | 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 | fail: | 897 | fail: |
| 744 | av_frame_free(&in); | 898 | av_frame_free(&in); |
| 745 | if (ret) { | 899 | if (ret) { |
| @@ -754,10 +908,11 @@ static av_cold void uninit(AVFilterContext *ctx) · 8 unmodified lines | |||
| 754 | { | 908 | { |
| 755 | ZScaleContext *s = ctx->priv; | 909 | ZScaleContext *s = ctx->priv; |
| 756 | 910 | ||
| 757 | zimg_filter_graph_free(s->graph); | 911 | for (int i = 0; i < s->nb_threads; i++) { |
| 758 | zimg_filter_graph_free(s->alpha_graph); | 912 | av_freep(&s->tmp[i]); |
| 759 | av_freep(&s->tmp); | 913 | zimg_filter_graph_free(s->graph[i]); |
| 760 | s->tmp_size = 0; | 914 | zimg_filter_graph_free(s->alpha_graph[i]); |
| 915 | } | ||
| 761 | } | 916 | } |
| 762 | 917 | ||
| 763 | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, | 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 | FILTER_OUTPUTS(avfilter_vf_zscale_outputs), | 1096 | FILTER_OUTPUTS(avfilter_vf_zscale_outputs), |
| 942 | FILTER_QUERY_FUNC(query_formats), | 1097 | FILTER_QUERY_FUNC(query_formats), |
| 943 | .process_command = process_command, | 1098 | .process_command = process_command, |
| 1099 | .flags = AVFILTER_FLAG_SLICE_THREADS, | ||
| 944 | }; | 1100 | }; |