Tested using a simple command (apply edge enhance): ./ffmpeg_g -i ~/Downloads/bbb_sunflower_1080p_30fps_normal.mp4 \ -vf convolution="0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:5:1:1:1:0:128:128:128" \ -an -vframes 1000 -f null /dev/null The fps increase from 151 to 270 on my local machine.
Unified · Split
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012-2013 Oka Motofumi (chikuzen.mo at gmail dot com) | ||
| 3 | * Copyright (c) 2015 Paul B Mahol | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | #ifndef AVFILTER_CONVOLUTION_H | ||
| 22 | #define AVFILTER_CONVOLUTION_H | ||
| 23 | #include "avfilter.h" | ||
| 24 | |||
| 25 | enum MatrixMode { | ||
| 26 | MATRIX_SQUARE, | ||
| 27 | MATRIX_ROW, | ||
| 28 | MATRIX_COLUMN, | ||
| 29 | MATRIX_NBMODES, | ||
| 30 | }; | ||
| 31 | |||
| 32 | typedef struct ConvolutionContext { | ||
| 33 | const AVClass *class; | ||
| 34 | |||
| 35 | char *matrix_str[4]; | ||
| 36 | float rdiv[4]; | ||
| 37 | float bias[4]; | ||
| 38 | int mode[4]; | ||
| 39 | float scale; | ||
| 40 | float delta; | ||
| 41 | int planes; | ||
| 42 | |||
| 43 | int size[4]; | ||
| 44 | int depth; | ||
| 45 | int max; | ||
| 46 | int bpc; | ||
| 47 | int nb_planes; | ||
| 48 | int nb_threads; | ||
| 49 | int planewidth[4]; | ||
| 50 | int planeheight[4]; | ||
| 51 | int matrix[4][49]; | ||
| 52 | int matrix_length[4]; | ||
| 53 | int copy[4]; | ||
| 54 | |||
| 55 | void (*setup[4])(int radius, const uint8_t *c[], const uint8_t *src, int stride, | ||
| 56 | int x, int width, int y, int height, int bpc); | ||
| 57 | void (*filter[4])(uint8_t *dst, int width, | ||
| 58 | float rdiv, float bias, const int *const matrix, | ||
| 59 | const uint8_t *c[], int peak, int radius, | ||
| 60 | int dstride, int stride); | ||
| 61 | } ConvolutionContext; | ||
| 62 | |||
| 63 | void ff_convolution_init_x86(ConvolutionContext *s); | ||
| 64 | #endif | ||
| @@ -25,48 +25,11 @@ · 24 unmodified lines | |||
| 25 | #include "libavutil/opt.h" | 25 | #include "libavutil/opt.h" |
| 26 | #include "libavutil/pixdesc.h" | 26 | #include "libavutil/pixdesc.h" |
| 27 | #include "avfilter.h" | 27 | #include "avfilter.h" |
| 28 | #include "convolution.h" | ||
| 28 | #include "formats.h" | 29 | #include "formats.h" |
| 29 | #include "internal.h" | 30 | #include "internal.h" |
| 30 | #include "video.h" | 31 | #include "video.h" |
| 31 | 32 | ||
| 32 | enum MatrixMode { | ||
| 33 | MATRIX_SQUARE, | ||
| 34 | MATRIX_ROW, | ||
| 35 | MATRIX_COLUMN, | ||
| 36 | MATRIX_NBMODES, | ||
| 37 | }; | ||
| 38 | |||
| 39 | typedef struct ConvolutionContext { | ||
| 40 | const AVClass *class; | ||
| 41 | |||
| 42 | char *matrix_str[4]; | ||
| 43 | float rdiv[4]; | ||
| 44 | float bias[4]; | ||
| 45 | int mode[4]; | ||
| 46 | float scale; | ||
| 47 | float delta; | ||
| 48 | int planes; | ||
| 49 | |||
| 50 | int size[4]; | ||
| 51 | int depth; | ||
| 52 | int max; | ||
| 53 | int bpc; | ||
| 54 | int nb_planes; | ||
| 55 | int nb_threads; | ||
| 56 | int planewidth[4]; | ||
| 57 | int planeheight[4]; | ||
| 58 | int matrix[4][49]; | ||
| 59 | int matrix_length[4]; | ||
| 60 | int copy[4]; | ||
| 61 | |||
| 62 | void (*setup[4])(int radius, const uint8_t *c[], const uint8_t *src, int stride, | ||
| 63 | int x, int width, int y, int height, int bpc); | ||
| 64 | void (*filter[4])(uint8_t *dst, int width, | ||
| 65 | float rdiv, float bias, const int *const matrix, | ||
| 66 | const uint8_t *c[], int peak, int radius, | ||
| 67 | int dstride, int stride); | ||
| 68 | } ConvolutionContext; | ||
| 69 | |||
| 70 | #define OFFSET(x) offsetof(ConvolutionContext, x) | 33 | #define OFFSET(x) offsetof(ConvolutionContext, x) |
| 71 | #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | 34 | #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
| 72 | 35 | ||
| @@ -625,6 +588,8 @@ static int config_input(AVFilterLink *inlink) · 552 unmodified lines | |||
| 625 | s->filter[p] = filter16_7x7; | 588 | s->filter[p] = filter16_7x7; |
| 626 | } | 589 | } |
| 627 | } | 590 | } |
| 591 | if (ARCH_X86_64) | ||
| 592 | ff_convolution_init_x86(s); | ||
| 628 | } else if (!strcmp(ctx->filter->name, "prewitt")) { | 593 | } else if (!strcmp(ctx->filter->name, "prewitt")) { |
| 629 | if (s->depth > 8) | 594 | if (s->depth > 8) |
| 630 | for (p = 0; p < s->nb_planes; p++) | 595 | for (p = 0; p < s->nb_planes; p++) |
| @@ -5,6 +5,7 @@ OBJS-$(CONFIG_ANLMDN_FILTER) += x86/af_anlmdn_init.o · 4 unmodified lines | |||
| 5 | OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend_init.o | 5 | OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend_init.o |
| 6 | OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif_init.o | 6 | OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif_init.o |
| 7 | OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp_init.o | 7 | OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp_init.o |
| 8 | OBJS-$(CONFIG_CONVOLUTION_FILTER) += x86/vf_convolution_init.o | ||
| 8 | OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o | 9 | OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o |
| 9 | OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o | 10 | OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o |
| 10 | OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur_init.o | 11 | OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur_init.o |
| @@ -40,6 +41,7 @@ X86ASM-OBJS-$(CONFIG_ANLMDN_FILTER) += x86/af_anlmdn.o · 29 unmodified lines | |||
| 40 | X86ASM-OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend.o | 41 | X86ASM-OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend.o |
| 41 | X86ASM-OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif.o | 42 | X86ASM-OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif.o |
| 42 | X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp.o | 43 | X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp.o |
| 44 | X86ASM-OBJS-$(CONFIG_CONVOLUTION_FILTER) += x86/vf_convolution.o | ||
| 43 | X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate.o | 45 | X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate.o |
| 44 | X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o | 46 | X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o |
| 45 | X86ASM-OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur.o | 47 | X86ASM-OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur.o |
| @@ -0,0 +1,156 @@ | |||
| 1 | ;***************************************************************************** | ||
| 2 | ;* x86-optimized functions for convolution filter | ||
| 3 | ;* | ||
| 4 | ;* This file is part of FFmpeg. | ||
| 5 | ;* | ||
| 6 | ;* FFmpeg is free software; you can redistribute it and/or | ||
| 7 | ;* modify it under the terms of the GNU Lesser General Public | ||
| 8 | ;* License as published by the Free Software Foundation; either | ||
| 9 | ;* version 2.1 of the License, or (at your option) any later version. | ||
| 10 | ;* | ||
| 11 | ;* FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | ;* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | ;* Lesser General Public License for more details. | ||
| 15 | ;* | ||
| 16 | ;* You should have received a copy of the GNU Lesser General Public | ||
| 17 | ;* License along with FFmpeg; if not, write to the Free Software | ||
| 18 | ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | ;****************************************************************************** | ||
| 20 | |||
| 21 | %include "libavutil/x86/x86util.asm" | ||
| 22 | |||
| 23 | SECTION_RODATA | ||
| 24 | half: dd 0.5 | ||
| 25 | |||
| 26 | SECTION .text | ||
| 27 | |||
| 28 | ; void filter_3x3_sse4(uint8_t *dst, int width, | ||
| 29 | ; float rdiv, float bias, const int *const matrix, | ||
| 30 | ; const uint8_t *c[], int peak, int radius, | ||
| 31 | ; int dstride, int stride) | ||
| 32 | |||
| 33 | |||
| 34 | %macro PROCESS_V 1 | ||
| 35 | movss m2, [matrixq + 4 * %1] | ||
| 36 | VBROADCASTSS m2, m2 | ||
| 37 | movss m3, [c%1q + xq] | ||
| 38 | punpcklbw m3, m6 | ||
| 39 | punpcklwd m3, m6 | ||
| 40 | pmulld m2, m3 | ||
| 41 | paddd m4, m2 | ||
| 42 | %endmacro | ||
| 43 | |||
| 44 | %macro PROCESS_S 1 | ||
| 45 | movzx ptrd, byte [c%1q + xq] | ||
| 46 | imul ptrd, [matrixq + 4 * %1] | ||
| 47 | add rd, ptrd | ||
| 48 | %endmacro | ||
| 49 | |||
| 50 | %macro FILTER_3X3 0 | ||
| 51 | %if UNIX64 | ||
| 52 | cglobal filter_3x3, 4, 15, 7, dst, width, matrix, ptr, c0, c1, c2, c3, c4, c5, c6, c7, c8, r, x | ||
| 53 | %else | ||
| 54 | cglobal filter_3x3, 4, 15, 7, dst, width, rdiv, bias, matrix, ptr, c0, c1, c2, c3, c4, c5, c6, c7, c8, r, x | ||
| 55 | %endif | ||
| 56 | |||
| 57 | %if WIN64 | ||
| 58 | SWAP m0, m2 | ||
| 59 | SWAP m1, m3 | ||
| 60 | mov r2q, matrixmp | ||
| 61 | mov r3q, ptrmp | ||
| 62 | DEFINE_ARGS dst, width, matrix, ptr, c0, c1, c2, c3, c4, c5, c6, c7, c8, r, x | ||
| 63 | %endif | ||
| 64 | movsxdifnidn widthq, widthd | ||
| 65 | VBROADCASTSS m0, m0 | ||
| 66 | VBROADCASTSS m1, m1 | ||
| 67 | pxor m6, m6 | ||
| 68 | movss m5, [half] | ||
| 69 | VBROADCASTSS m5, m5 | ||
| 70 | mov c0q, [ptrq + 0*gprsize] | ||
| 71 | mov c1q, [ptrq + 1*gprsize] | ||
| 72 | mov c2q, [ptrq + 2*gprsize] | ||
| 73 | mov c3q, [ptrq + 3*gprsize] | ||
| 74 | mov c4q, [ptrq + 4*gprsize] | ||
| 75 | mov c5q, [ptrq + 5*gprsize] | ||
| 76 | mov c6q, [ptrq + 6*gprsize] | ||
| 77 | mov c7q, [ptrq + 7*gprsize] | ||
| 78 | mov c8q, [ptrq + 8*gprsize] | ||
| 79 | |||
| 80 | xor xq, xq | ||
| 81 | cmp widthq, mmsize/4 | ||
| 82 | jl .loop2 | ||
| 83 | |||
| 84 | mov rq, widthq | ||
| 85 | and rq, mmsize/4-1 | ||
| 86 | sub widthq, rq | ||
| 87 | |||
| 88 | .loop1: | ||
| 89 | pxor m4, m4 ; sum = 0; | ||
| 90 | |||
| 91 | PROCESS_V 0 | ||
| 92 | PROCESS_V 1 | ||
| 93 | PROCESS_V 2 | ||
| 94 | PROCESS_V 3 | ||
| 95 | PROCESS_V 4 | ||
| 96 | PROCESS_V 5 | ||
| 97 | PROCESS_V 6 | ||
| 98 | PROCESS_V 7 | ||
| 99 | PROCESS_V 8 | ||
| 100 | |||
| 101 | cvtdq2ps m4, m4 | ||
| 102 | mulps m4, m0 ; sum *= rdiv | ||
| 103 | addps m4, m1 ; sum += bias | ||
| 104 | addps m4, m5 ; sum += 0.5 | ||
| 105 | cvttps2dq m4, m4 | ||
| 106 | packssdw m4, m4 | ||
| 107 | packuswb m4, m4 | ||
| 108 | movss [dstq + xq], m4 | ||
| 109 | |||
| 110 | add xq, mmsize/4 | ||
| 111 | cmp xq, widthq | ||
| 112 | jl .loop1 | ||
| 113 | |||
| 114 | add widthq, rq | ||
| 115 | cmp xq, widthq | ||
| 116 | jge .end | ||
| 117 | |||
| 118 | .loop2: | ||
| 119 | ; reuse r to hold sum, init with zero | ||
| 120 | xor rd, rd | ||
| 121 | |||
| 122 | PROCESS_S 0 | ||
| 123 | PROCESS_S 1 | ||
| 124 | PROCESS_S 2 | ||
| 125 | PROCESS_S 3 | ||
| 126 | PROCESS_S 4 | ||
| 127 | PROCESS_S 5 | ||
| 128 | PROCESS_S 6 | ||
| 129 | PROCESS_S 7 | ||
| 130 | PROCESS_S 8 | ||
| 131 | |||
| 132 | pxor m4, m4 | ||
| 133 | cvtsi2ss m4, rd | ||
| 134 | mulss m4, m0 ; sum *= rdiv | ||
| 135 | addss m4, m1 ; sum += bias | ||
| 136 | addss m4, m5 ; sum += 0.5 | ||
| 137 | ; we don't have simple scalar instructions to convert | ||
| 138 | ; from 32bit to 8bit with saturation, so here | ||
| 139 | ; just use packed version SSE instructions for simplicity. | ||
| 140 | cvttps2dq m4, m4 ; trunc to integer | ||
| 141 | packssdw m4, m4 | ||
| 142 | packuswb m4, m4 | ||
| 143 | movd rd, m4 | ||
| 144 | mov [dstq + xq], rb | ||
| 145 | |||
| 146 | add xq, 1 | ||
| 147 | cmp xq, widthq | ||
| 148 | jl .loop2 | ||
| 149 | .end: | ||
| 150 | RET | ||
| 151 | %endmacro | ||
| 152 | |||
| 153 | %if ARCH_X86_64 | ||
| 154 | INIT_XMM sse4 | ||
| 155 | FILTER_3X3 | ||
| 156 | %endif | ||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * This file is part of FFmpeg. | ||
| 4 | * | ||
| 5 | * FFmpeg is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; either | ||
| 8 | * version 2.1 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with FFmpeg; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include "config.h" | ||
| 21 | |||
| 22 | #include "libavutil/attributes.h" | ||
| 23 | #include "libavutil/cpu.h" | ||
| 24 | #include "libavutil/x86/cpu.h" | ||
| 25 | #include "libavfilter/convolution.h" | ||
| 26 | |||
| 27 | void ff_filter_3x3_sse4(uint8_t *dst, int width, | ||
| 28 | float rdiv, float bias, const int *const matrix, | ||
| 29 | const uint8_t *c[], int peak, int radius, | ||
| 30 | int dstride, int stride); | ||
| 31 | |||
| 32 | av_cold void ff_convolution_init_x86(ConvolutionContext *s) | ||
| 33 | { | ||
| 34 | #if ARCH_X86_64 | ||
| 35 | int i; | ||
| 36 | int cpu_flags = av_get_cpu_flags(); | ||
| 37 | for (i = 0; i < 4; i++) { | ||
| 38 | if (s->mode[i] == MATRIX_SQUARE) { | ||
| 39 | if (s->matrix_length[i] == 9) { | ||
| 40 | if (EXTERNAL_SSE4(cpu_flags)) | ||
| 41 | s->filter[i] = ff_filter_3x3_sse4; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | #endif | ||
| 46 | } | ||