LCOV - code coverage report
Current view: top level - libavfilter - vf_convolution.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 366 0.0 %
Date: 2018-05-20 11:54:08 Functions: 0 26 0.0 %

          Line data    Source code
       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             : 
      22             : #include "libavutil/avstring.h"
      23             : #include "libavutil/imgutils.h"
      24             : #include "libavutil/intreadwrite.h"
      25             : #include "libavutil/opt.h"
      26             : #include "libavutil/pixdesc.h"
      27             : #include "avfilter.h"
      28             : #include "formats.h"
      29             : #include "internal.h"
      30             : #include "video.h"
      31             : 
      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)
      71             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      72             : 
      73             : static const AVOption convolution_options[] = {
      74             :     { "0m", "set matrix for 1st plane", OFFSET(matrix_str[0]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS },
      75             :     { "1m", "set matrix for 2nd plane", OFFSET(matrix_str[1]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS },
      76             :     { "2m", "set matrix for 3rd plane", OFFSET(matrix_str[2]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS },
      77             :     { "3m", "set matrix for 4th plane", OFFSET(matrix_str[3]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS },
      78             :     { "0rdiv", "set rdiv for 1st plane", OFFSET(rdiv[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      79             :     { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdiv[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      80             :     { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdiv[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      81             :     { "3rdiv", "set rdiv for 4th plane", OFFSET(rdiv[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      82             :     { "0bias", "set bias for 1st plane", OFFSET(bias[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      83             :     { "1bias", "set bias for 2nd plane", OFFSET(bias[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      84             :     { "2bias", "set bias for 3rd plane", OFFSET(bias[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      85             :     { "3bias", "set bias for 4th plane", OFFSET(bias[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      86             :     { "0mode", "set matrix mode for 1st plane", OFFSET(mode[0]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" },
      87             :     { "1mode", "set matrix mode for 2nd plane", OFFSET(mode[1]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" },
      88             :     { "2mode", "set matrix mode for 3rd plane", OFFSET(mode[2]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" },
      89             :     { "3mode", "set matrix mode for 4th plane", OFFSET(mode[3]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" },
      90             :     { "square", "square matrix",     0, AV_OPT_TYPE_CONST, {.i64=MATRIX_SQUARE}, 0, 0, FLAGS, "mode" },
      91             :     { "row",    "single row matrix", 0, AV_OPT_TYPE_CONST, {.i64=MATRIX_ROW}   , 0, 0, FLAGS, "mode" },
      92             :     { "column", "single column matrix", 0, AV_OPT_TYPE_CONST, {.i64=MATRIX_COLUMN}, 0, 0, FLAGS, "mode" },
      93             :     { NULL }
      94             : };
      95             : 
      96             : AVFILTER_DEFINE_CLASS(convolution);
      97             : 
      98             : static const int same3x3[9] = {0, 0, 0,
      99             :                                0, 1, 0,
     100             :                                0, 0, 0};
     101             : 
     102             : static const int same5x5[25] = {0, 0, 0, 0, 0,
     103             :                                 0, 0, 0, 0, 0,
     104             :                                 0, 0, 1, 0, 0,
     105             :                                 0, 0, 0, 0, 0,
     106             :                                 0, 0, 0, 0, 0};
     107             : 
     108             : static const int same7x7[49] = {0, 0, 0, 0, 0, 0, 0,
     109             :                                 0, 0, 0, 0, 0, 0, 0,
     110             :                                 0, 0, 0, 0, 0, 0, 0,
     111             :                                 0, 0, 0, 1, 0, 0, 0,
     112             :                                 0, 0, 0, 0, 0, 0, 0,
     113             :                                 0, 0, 0, 0, 0, 0, 0,
     114             :                                 0, 0, 0, 0, 0, 0, 0};
     115             : 
     116           0 : static int query_formats(AVFilterContext *ctx)
     117             : {
     118             :     static const enum AVPixelFormat pix_fmts[] = {
     119             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
     120             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
     121             :         AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
     122             :         AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
     123             :         AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
     124             :         AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
     125             :         AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
     126             :         AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
     127             :         AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
     128             :         AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
     129             :         AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
     130             :         AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
     131             :         AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
     132             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
     133             :         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
     134             :         AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
     135             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
     136             :         AV_PIX_FMT_NONE
     137             :     };
     138             : 
     139           0 :     return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
     140             : }
     141             : 
     142             : typedef struct ThreadData {
     143             :     AVFrame *in, *out;
     144             : } ThreadData;
     145             : 
     146           0 : static void filter16_prewitt(uint8_t *dstp, int width,
     147             :                              float scale, float delta, const int *const matrix,
     148             :                              const uint8_t *c[], int peak, int radius,
     149             :                              int dstride, int stride)
     150             : {
     151           0 :     uint16_t *dst = (uint16_t *)dstp;
     152             :     int x;
     153             : 
     154           0 :     for (x = 0; x < width; x++) {
     155           0 :         int suma = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[1][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) * -1 +
     156           0 :                    AV_RN16A(&c[6][2 * x]) *  1 + AV_RN16A(&c[7][2 * x]) *  1 + AV_RN16A(&c[8][2 * x]) *  1;
     157           0 :         int sumb = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) *  1 + AV_RN16A(&c[3][2 * x]) * -1 +
     158           0 :                    AV_RN16A(&c[5][2 * x]) *  1 + AV_RN16A(&c[6][2 * x]) * -1 + AV_RN16A(&c[8][2 * x]) *  1;
     159             : 
     160           0 :         dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     161             :     }
     162           0 : }
     163             : 
     164           0 : static void filter16_roberts(uint8_t *dstp, int width,
     165             :                              float scale, float delta, const int *const matrix,
     166             :                              const uint8_t *c[], int peak, int radius,
     167             :                              int dstride, int stride)
     168             : {
     169           0 :     uint16_t *dst = (uint16_t *)dstp;
     170             :     int x;
     171             : 
     172           0 :     for (x = 0; x < width; x++) {
     173           0 :         int suma = AV_RN16A(&c[0][2 * x]) *  1 + AV_RN16A(&c[1][2 * x]) * -1;
     174           0 :         int sumb = AV_RN16A(&c[4][2 * x]) *  1 + AV_RN16A(&c[3][2 * x]) * -1;
     175             : 
     176           0 :         dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     177             :     }
     178           0 : }
     179             : 
     180           0 : static void filter16_sobel(uint8_t *dstp, int width,
     181             :                            float scale, float delta, const int *const matrix,
     182             :                            const uint8_t *c[], int peak, int radius,
     183             :                            int dstride, int stride)
     184             : {
     185           0 :     uint16_t *dst = (uint16_t *)dstp;
     186             :     int x;
     187             : 
     188           0 :     for (x = 0; x < width; x++) {
     189           0 :         int suma = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[1][2 * x]) * -2 + AV_RN16A(&c[2][2 * x]) * -1 +
     190           0 :                    AV_RN16A(&c[6][2 * x]) *  1 + AV_RN16A(&c[7][2 * x]) *  2 + AV_RN16A(&c[8][2 * x]) *  1;
     191           0 :         int sumb = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) *  1 + AV_RN16A(&c[3][2 * x]) * -2 +
     192           0 :                    AV_RN16A(&c[5][2 * x]) *  2 + AV_RN16A(&c[6][2 * x]) * -1 + AV_RN16A(&c[8][2 * x]) *  1;
     193             : 
     194           0 :         dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     195             :     }
     196           0 : }
     197             : 
     198           0 : static void filter_prewitt(uint8_t *dst, int width,
     199             :                            float scale, float delta, const int *const matrix,
     200             :                            const uint8_t *c[], int peak, int radius,
     201             :                            int dstride, int stride)
     202             : {
     203           0 :     const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2];
     204           0 :     const uint8_t *c3 = c[3], *c5 = c[5];
     205           0 :     const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8];
     206             :     int x;
     207             : 
     208           0 :     for (x = 0; x < width; x++) {
     209           0 :         int suma = c0[x] * -1 + c1[x] * -1 + c2[x] * -1 +
     210           0 :                    c6[x] *  1 + c7[x] *  1 + c8[x] *  1;
     211           0 :         int sumb = c0[x] * -1 + c2[x] *  1 + c3[x] * -1 +
     212           0 :                    c5[x] *  1 + c6[x] * -1 + c8[x] *  1;
     213             : 
     214           0 :         dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     215             :     }
     216           0 : }
     217             : 
     218           0 : static void filter_roberts(uint8_t *dst, int width,
     219             :                            float scale, float delta, const int *const matrix,
     220             :                            const uint8_t *c[], int peak, int radius,
     221             :                            int dstride, int stride)
     222             : {
     223             :     int x;
     224             : 
     225           0 :     for (x = 0; x < width; x++) {
     226           0 :         int suma = c[0][x] *  1 + c[1][x] * -1;
     227           0 :         int sumb = c[4][x] *  1 + c[3][x] * -1;
     228             : 
     229           0 :         dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     230             :     }
     231           0 : }
     232             : 
     233           0 : static void filter_sobel(uint8_t *dst, int width,
     234             :                          float scale, float delta, const int *const matrix,
     235             :                          const uint8_t *c[], int peak, int radius,
     236             :                          int dstride, int stride)
     237             : {
     238           0 :     const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2];
     239           0 :     const uint8_t *c3 = c[3], *c5 = c[5];
     240           0 :     const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8];
     241             :     int x;
     242             : 
     243           0 :     for (x = 0; x < width; x++) {
     244           0 :         int suma = c0[x] * -1 + c1[x] * -2 + c2[x] * -1 +
     245           0 :                    c6[x] *  1 + c7[x] *  2 + c8[x] *  1;
     246           0 :         int sumb = c0[x] * -1 + c2[x] *  1 + c3[x] * -2 +
     247           0 :                    c5[x] *  2 + c6[x] * -1 + c8[x] *  1;
     248             : 
     249           0 :         dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     250             :     }
     251           0 : }
     252             : 
     253           0 : static void filter16_3x3(uint8_t *dstp, int width,
     254             :                          float rdiv, float bias, const int *const matrix,
     255             :                          const uint8_t *c[], int peak, int radius,
     256             :                          int dstride, int stride)
     257             : {
     258           0 :     uint16_t *dst = (uint16_t *)dstp;
     259             :     int x;
     260             : 
     261           0 :     for (x = 0; x < width; x++) {
     262           0 :         int sum = AV_RN16A(&c[0][2 * x]) * matrix[0] +
     263           0 :                   AV_RN16A(&c[1][2 * x]) * matrix[1] +
     264           0 :                   AV_RN16A(&c[2][2 * x]) * matrix[2] +
     265           0 :                   AV_RN16A(&c[3][2 * x]) * matrix[3] +
     266           0 :                   AV_RN16A(&c[4][2 * x]) * matrix[4] +
     267           0 :                   AV_RN16A(&c[5][2 * x]) * matrix[5] +
     268           0 :                   AV_RN16A(&c[6][2 * x]) * matrix[6] +
     269           0 :                   AV_RN16A(&c[7][2 * x]) * matrix[7] +
     270           0 :                   AV_RN16A(&c[8][2 * x]) * matrix[8];
     271           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     272           0 :         dst[x] = av_clip(sum, 0, peak);
     273             :     }
     274           0 : }
     275             : 
     276           0 : static void filter16_5x5(uint8_t *dstp, int width,
     277             :                          float rdiv, float bias, const int *const matrix,
     278             :                          const uint8_t *c[], int peak, int radius,
     279             :                          int dstride, int stride)
     280             : {
     281           0 :     uint16_t *dst = (uint16_t *)dstp;
     282             :     int x;
     283             : 
     284           0 :     for (x = 0; x < width; x++) {
     285           0 :         int i, sum = 0;
     286             : 
     287           0 :         for (i = 0; i < 25; i++)
     288           0 :             sum += AV_RN16A(&c[i][2 * x]) * matrix[i];
     289             : 
     290           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     291           0 :         dst[x] = av_clip(sum, 0, peak);
     292             :     }
     293           0 : }
     294             : 
     295           0 : static void filter16_7x7(uint8_t *dstp, int width,
     296             :                          float rdiv, float bias, const int *const matrix,
     297             :                          const uint8_t *c[], int peak, int radius,
     298             :                          int dstride, int stride)
     299             : {
     300           0 :     uint16_t *dst = (uint16_t *)dstp;
     301             :     int x;
     302             : 
     303           0 :     for (x = 0; x < width; x++) {
     304           0 :         int i, sum = 0;
     305             : 
     306           0 :         for (i = 0; i < 49; i++)
     307           0 :             sum += AV_RN16A(&c[i][2 * x]) * matrix[i];
     308             : 
     309           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     310           0 :         dst[x] = av_clip(sum, 0, peak);
     311             :     }
     312           0 : }
     313             : 
     314           0 : static void filter16_row(uint8_t *dstp, int width,
     315             :                          float rdiv, float bias, const int *const matrix,
     316             :                          const uint8_t *c[], int peak, int radius,
     317             :                          int dstride, int stride)
     318             : {
     319           0 :     uint16_t *dst = (uint16_t *)dstp;
     320             :     int x;
     321             : 
     322           0 :     for (x = 0; x < width; x++) {
     323           0 :         int i, sum = 0;
     324             : 
     325           0 :         for (i = 0; i < 2 * radius + 1; i++)
     326           0 :             sum += AV_RN16A(&c[i][2 * x]) * matrix[i];
     327             : 
     328           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     329           0 :         dst[x] = av_clip(sum, 0, peak);
     330             :     }
     331           0 : }
     332             : 
     333           0 : static void filter16_column(uint8_t *dstp, int height,
     334             :                             float rdiv, float bias, const int *const matrix,
     335             :                             const uint8_t *c[], int peak, int radius,
     336             :                             int dstride, int stride)
     337             : {
     338           0 :     uint16_t *dst = (uint16_t *)dstp;
     339             :     int y;
     340             : 
     341           0 :     for (y = 0; y < height; y++) {
     342           0 :         int i, sum = 0;
     343             : 
     344           0 :         for (i = 0; i < 2 * radius + 1; i++)
     345           0 :             sum += AV_RN16A(&c[i][0 + y * stride]) * matrix[i];
     346             : 
     347           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     348           0 :         dst[0] = av_clip(sum, 0, peak);
     349           0 :         dst += dstride / 2;
     350             :     }
     351           0 : }
     352             : 
     353           0 : static void filter_7x7(uint8_t *dst, int width,
     354             :                        float rdiv, float bias, const int *const matrix,
     355             :                        const uint8_t *c[], int peak, int radius,
     356             :                        int dstride, int stride)
     357             : {
     358             :     int x;
     359             : 
     360           0 :     for (x = 0; x < width; x++) {
     361           0 :         int i, sum = 0;
     362             : 
     363           0 :         for (i = 0; i < 49; i++)
     364           0 :             sum += c[i][x] * matrix[i];
     365             : 
     366           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     367           0 :         dst[x] = av_clip_uint8(sum);
     368             :     }
     369           0 : }
     370             : 
     371           0 : static void filter_5x5(uint8_t *dst, int width,
     372             :                        float rdiv, float bias, const int *const matrix,
     373             :                        const uint8_t *c[], int peak, int radius,
     374             :                        int dstride, int stride)
     375             : {
     376             :     int x;
     377             : 
     378           0 :     for (x = 0; x < width; x++) {
     379           0 :         int i, sum = 0;
     380             : 
     381           0 :         for (i = 0; i < 25; i++)
     382           0 :             sum += c[i][x] * matrix[i];
     383             : 
     384           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     385           0 :         dst[x] = av_clip_uint8(sum);
     386             :     }
     387           0 : }
     388             : 
     389           0 : static void filter_3x3(uint8_t *dst, int width,
     390             :                        float rdiv, float bias, const int *const matrix,
     391             :                        const uint8_t *c[], int peak, int radius,
     392             :                        int dstride, int stride)
     393             : {
     394           0 :     const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2];
     395           0 :     const uint8_t *c3 = c[3], *c4 = c[4], *c5 = c[5];
     396           0 :     const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8];
     397             :     int x;
     398             : 
     399           0 :     for (x = 0; x < width; x++) {
     400           0 :         int sum = c0[x] * matrix[0] + c1[x] * matrix[1] + c2[x] * matrix[2] +
     401           0 :                   c3[x] * matrix[3] + c4[x] * matrix[4] + c5[x] * matrix[5] +
     402           0 :                   c6[x] * matrix[6] + c7[x] * matrix[7] + c8[x] * matrix[8];
     403           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     404           0 :         dst[x] = av_clip_uint8(sum);
     405             :     }
     406           0 : }
     407             : 
     408           0 : static void filter_row(uint8_t *dst, int width,
     409             :                        float rdiv, float bias, const int *const matrix,
     410             :                        const uint8_t *c[], int peak, int radius,
     411             :                        int dstride, int stride)
     412             : {
     413             :     int x;
     414             : 
     415           0 :     for (x = 0; x < width; x++) {
     416           0 :         int i, sum = 0;
     417             : 
     418           0 :         for (i = 0; i < 2 * radius + 1; i++)
     419           0 :             sum += c[i][x] * matrix[i];
     420             : 
     421           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     422           0 :         dst[x] = av_clip_uint8(sum);
     423             :     }
     424           0 : }
     425             : 
     426           0 : static void filter_column(uint8_t *dst, int height,
     427             :                           float rdiv, float bias, const int *const matrix,
     428             :                           const uint8_t *c[], int peak, int radius,
     429             :                           int dstride, int stride)
     430             : {
     431             :     int y;
     432             : 
     433           0 :     for (y = 0; y < height; y++) {
     434           0 :         int i, sum = 0;
     435             : 
     436           0 :         for (i = 0; i < 2 * radius + 1; i++)
     437           0 :             sum += c[i][0 + y * stride] * matrix[i];
     438             : 
     439           0 :         sum = (int)(sum * rdiv + bias + 0.5f);
     440           0 :         dst[0] = av_clip_uint8(sum);
     441           0 :         dst += dstride;
     442             :     }
     443           0 : }
     444             : 
     445           0 : static void setup_3x3(int radius, const uint8_t *c[], const uint8_t *src, int stride,
     446             :                       int x, int w, int y, int h, int bpc)
     447             : {
     448             :     int i;
     449             : 
     450           0 :     for (i = 0; i < 9; i++) {
     451           0 :         int xoff = FFABS(x + ((i % 3) - 1));
     452           0 :         int yoff = FFABS(y + (i / 3) - 1);
     453             : 
     454           0 :         xoff = xoff >= w ? 2 * w - 1 - xoff : xoff;
     455           0 :         yoff = yoff >= h ? 2 * h - 1 - yoff : yoff;
     456             : 
     457           0 :         c[i] = src + xoff * bpc + yoff * stride;
     458             :     }
     459           0 : }
     460             : 
     461           0 : static void setup_5x5(int radius, const uint8_t *c[], const uint8_t *src, int stride,
     462             :                       int x, int w, int y, int h, int bpc)
     463             : {
     464             :     int i;
     465             : 
     466           0 :     for (i = 0; i < 25; i++) {
     467           0 :         int xoff = FFABS(x + ((i % 5) - 2));
     468           0 :         int yoff = FFABS(y + (i / 5) - 2);
     469             : 
     470           0 :         xoff = xoff >= w ? 2 * w - 1 - xoff : xoff;
     471           0 :         yoff = yoff >= h ? 2 * h - 1 - yoff : yoff;
     472             : 
     473           0 :         c[i] = src + xoff * bpc + yoff * stride;
     474             :     }
     475           0 : }
     476             : 
     477           0 : static void setup_7x7(int radius, const uint8_t *c[], const uint8_t *src, int stride,
     478             :                       int x, int w, int y, int h, int bpc)
     479             : {
     480             :     int i;
     481             : 
     482           0 :     for (i = 0; i < 49; i++) {
     483           0 :         int xoff = FFABS(x + ((i % 7) - 3));
     484           0 :         int yoff = FFABS(y + (i / 7) - 3);
     485             : 
     486           0 :         xoff = xoff >= w ? 2 * w - 1 - xoff : xoff;
     487           0 :         yoff = yoff >= h ? 2 * h - 1 - yoff : yoff;
     488             : 
     489           0 :         c[i] = src + xoff * bpc + yoff * stride;
     490             :     }
     491           0 : }
     492             : 
     493           0 : static void setup_row(int radius, const uint8_t *c[], const uint8_t *src, int stride,
     494             :                       int x, int w, int y, int h, int bpc)
     495             : {
     496             :     int i;
     497             : 
     498           0 :     for (i = 0; i < radius * 2 + 1; i++) {
     499           0 :         int xoff = FFABS(x + i - radius);
     500             : 
     501           0 :         xoff = xoff >= w ? 2 * w - 1 - xoff : xoff;
     502             : 
     503           0 :         c[i] = src + xoff * bpc + y * stride;
     504             :     }
     505           0 : }
     506             : 
     507           0 : static void setup_column(int radius, const uint8_t *c[], const uint8_t *src, int stride,
     508             :                          int x, int w, int y, int h, int bpc)
     509             : {
     510             :     int i;
     511             : 
     512           0 :     for (i = 0; i < radius * 2 + 1; i++) {
     513           0 :         int xoff = FFABS(x + i - radius);
     514             : 
     515           0 :         xoff = xoff >= h ? 2 * h - 1 - xoff : xoff;
     516             : 
     517           0 :         c[i] = src + y * bpc + xoff * stride;
     518             :     }
     519           0 : }
     520             : 
     521           0 : static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     522             : {
     523           0 :     ConvolutionContext *s = ctx->priv;
     524           0 :     ThreadData *td = arg;
     525           0 :     AVFrame *in = td->in;
     526           0 :     AVFrame *out = td->out;
     527             :     int plane;
     528             : 
     529           0 :     for (plane = 0; plane < s->nb_planes; plane++) {
     530           0 :         const int mode = s->mode[plane];
     531           0 :         const int bpc = s->bpc;
     532           0 :         const int radius = s->size[plane] / 2;
     533           0 :         const int height = s->planeheight[plane];
     534           0 :         const int width  = s->planewidth[plane];
     535           0 :         const int stride = in->linesize[plane];
     536           0 :         const int dstride = out->linesize[plane];
     537           0 :         const int sizeh = mode == MATRIX_COLUMN ? width : height;
     538           0 :         const int sizew = mode == MATRIX_COLUMN ? height : width;
     539           0 :         const int slice_start = (sizeh * jobnr) / nb_jobs;
     540           0 :         const int slice_end = (sizeh * (jobnr+1)) / nb_jobs;
     541           0 :         const float rdiv = s->rdiv[plane];
     542           0 :         const float bias = s->bias[plane];
     543           0 :         const uint8_t *src = in->data[plane];
     544           0 :         const int dst_pos = slice_start * (mode == MATRIX_COLUMN ? bpc : dstride);
     545           0 :         uint8_t *dst = out->data[plane] + dst_pos;
     546           0 :         const int *matrix = s->matrix[plane];
     547             :         const uint8_t *c[49];
     548             :         int y, x;
     549             : 
     550           0 :         if (s->copy[plane]) {
     551           0 :             if (mode == MATRIX_COLUMN)
     552           0 :                 av_image_copy_plane(dst, dstride, src + slice_start * bpc, stride,
     553           0 :                                     (slice_end - slice_start) * bpc, height);
     554             :             else
     555           0 :                 av_image_copy_plane(dst, dstride, src + slice_start * stride, stride,
     556             :                                     width * bpc, slice_end - slice_start);
     557           0 :             continue;
     558             :         }
     559             : 
     560           0 :         for (y = slice_start; y < slice_end; y++) {
     561           0 :             const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : radius * bpc;
     562           0 :             const int yoff = mode == MATRIX_COLUMN ? radius * stride : 0;
     563             : 
     564           0 :             for (x = 0; x < radius; x++) {
     565           0 :                 const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : x * bpc;
     566           0 :                 const int yoff = mode == MATRIX_COLUMN ? x * stride : 0;
     567             : 
     568           0 :                 s->setup[plane](radius, c, src, stride, x, width, y, height, bpc);
     569           0 :                 s->filter[plane](dst + yoff + xoff, 1, rdiv,
     570             :                                  bias, matrix, c, s->max, radius,
     571             :                                  dstride, stride);
     572             :             }
     573           0 :             s->setup[plane](radius, c, src, stride, radius, width, y, height, bpc);
     574           0 :             s->filter[plane](dst + yoff + xoff, sizew - 2 * radius,
     575             :                              rdiv, bias, matrix, c, s->max, radius,
     576             :                              dstride, stride);
     577           0 :             for (x = sizew - radius; x < sizew; x++) {
     578           0 :                 const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : x * bpc;
     579           0 :                 const int yoff = mode == MATRIX_COLUMN ? x * stride : 0;
     580             : 
     581           0 :                 s->setup[plane](radius, c, src, stride, x, width, y, height, bpc);
     582           0 :                 s->filter[plane](dst + yoff + xoff, 1, rdiv,
     583             :                                  bias, matrix, c, s->max, radius,
     584             :                                  dstride, stride);
     585             :             }
     586           0 :             if (mode != MATRIX_COLUMN)
     587           0 :                 dst += dstride;
     588             :         }
     589             :     }
     590             : 
     591           0 :     return 0;
     592             : }
     593             : 
     594           0 : static int config_input(AVFilterLink *inlink)
     595             : {
     596           0 :     AVFilterContext *ctx = inlink->dst;
     597           0 :     ConvolutionContext *s = ctx->priv;
     598           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     599             :     int p;
     600             : 
     601           0 :     s->depth = desc->comp[0].depth;
     602           0 :     s->max = (1 << s->depth) - 1;
     603             : 
     604           0 :     s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
     605           0 :     s->planewidth[0] = s->planewidth[3] = inlink->w;
     606           0 :     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
     607           0 :     s->planeheight[0] = s->planeheight[3] = inlink->h;
     608             : 
     609           0 :     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
     610           0 :     s->nb_threads = ff_filter_get_nb_threads(ctx);
     611           0 :     s->bpc = (s->depth + 7) / 8;
     612             : 
     613           0 :     if (!strcmp(ctx->filter->name, "convolution")) {
     614           0 :         if (s->depth > 8) {
     615           0 :             for (p = 0; p < s->nb_planes; p++) {
     616           0 :                 if (s->mode[p] == MATRIX_ROW)
     617           0 :                     s->filter[p] = filter16_row;
     618           0 :                 else if (s->mode[p] == MATRIX_COLUMN)
     619           0 :                     s->filter[p] = filter16_column;
     620           0 :                 else if (s->size[p] == 3)
     621           0 :                     s->filter[p] = filter16_3x3;
     622           0 :                 else if (s->size[p] == 5)
     623           0 :                     s->filter[p] = filter16_5x5;
     624           0 :                 else if (s->size[p] == 7)
     625           0 :                     s->filter[p] = filter16_7x7;
     626             :             }
     627             :         }
     628           0 :     } else if (!strcmp(ctx->filter->name, "prewitt")) {
     629           0 :         if (s->depth > 8)
     630           0 :             for (p = 0; p < s->nb_planes; p++)
     631           0 :                 s->filter[p] = filter16_prewitt;
     632           0 :     } else if (!strcmp(ctx->filter->name, "roberts")) {
     633           0 :         if (s->depth > 8)
     634           0 :             for (p = 0; p < s->nb_planes; p++)
     635           0 :                 s->filter[p] = filter16_roberts;
     636           0 :     } else if (!strcmp(ctx->filter->name, "sobel")) {
     637           0 :         if (s->depth > 8)
     638           0 :             for (p = 0; p < s->nb_planes; p++)
     639           0 :                 s->filter[p] = filter16_sobel;
     640             :     }
     641             : 
     642           0 :     return 0;
     643             : }
     644             : 
     645           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     646             : {
     647           0 :     AVFilterContext *ctx = inlink->dst;
     648           0 :     ConvolutionContext *s = ctx->priv;
     649           0 :     AVFilterLink *outlink = ctx->outputs[0];
     650             :     AVFrame *out;
     651             :     ThreadData td;
     652             : 
     653           0 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     654           0 :     if (!out) {
     655           0 :         av_frame_free(&in);
     656           0 :         return AVERROR(ENOMEM);
     657             :     }
     658           0 :     av_frame_copy_props(out, in);
     659             : 
     660           0 :     td.in = in;
     661           0 :     td.out = out;
     662           0 :     ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN3(s->planeheight[1], s->planewidth[1], s->nb_threads));
     663             : 
     664           0 :     av_frame_free(&in);
     665           0 :     return ff_filter_frame(outlink, out);
     666             : }
     667             : 
     668           0 : static av_cold int init(AVFilterContext *ctx)
     669             : {
     670           0 :     ConvolutionContext *s = ctx->priv;
     671             :     int i;
     672             : 
     673           0 :     if (!strcmp(ctx->filter->name, "convolution")) {
     674           0 :         for (i = 0; i < 4; i++) {
     675           0 :             int *matrix = (int *)s->matrix[i];
     676           0 :             char *p, *arg, *saveptr = NULL;
     677           0 :             float sum = 0;
     678             : 
     679           0 :             p = s->matrix_str[i];
     680           0 :             while (s->matrix_length[i] < 49) {
     681           0 :                 if (!(arg = av_strtok(p, " ", &saveptr)))
     682           0 :                     break;
     683             : 
     684           0 :                 p = NULL;
     685           0 :                 sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
     686           0 :                 sum += matrix[s->matrix_length[i]];
     687           0 :                 s->matrix_length[i]++;
     688             :             }
     689             : 
     690           0 :             if (!(s->matrix_length[i] & 1)) {
     691           0 :                 av_log(ctx, AV_LOG_ERROR, "number of matrix elements must be odd\n");
     692           0 :                 return AVERROR(EINVAL);
     693             :             }
     694           0 :             if (s->mode[i] == MATRIX_ROW) {
     695           0 :                 s->filter[i] = filter_row;
     696           0 :                 s->setup[i] = setup_row;
     697           0 :                 s->size[i] = s->matrix_length[i];
     698           0 :             } else if (s->mode[i] == MATRIX_COLUMN) {
     699           0 :                 s->filter[i] = filter_column;
     700           0 :                 s->setup[i] = setup_column;
     701           0 :                 s->size[i] = s->matrix_length[i];
     702           0 :             } else if (s->matrix_length[i] == 9) {
     703           0 :                 s->size[i] = 3;
     704           0 :                 if (!memcmp(matrix, same3x3, sizeof(same3x3)))
     705           0 :                     s->copy[i] = 1;
     706             :                 else
     707           0 :                     s->filter[i] = filter_3x3;
     708           0 :                 s->setup[i] = setup_3x3;
     709           0 :             } else if (s->matrix_length[i] == 25) {
     710           0 :                 s->size[i] = 5;
     711           0 :                 if (!memcmp(matrix, same5x5, sizeof(same5x5)))
     712           0 :                     s->copy[i] = 1;
     713             :                 else
     714           0 :                     s->filter[i] = filter_5x5;
     715           0 :                 s->setup[i] = setup_5x5;
     716           0 :             } else if (s->matrix_length[i] == 49) {
     717           0 :                 s->size[i] = 7;
     718           0 :                 if (!memcmp(matrix, same7x7, sizeof(same7x7)))
     719           0 :                     s->copy[i] = 1;
     720             :                 else
     721           0 :                     s->filter[i] = filter_7x7;
     722           0 :                 s->setup[i] = setup_7x7;
     723             :             } else {
     724           0 :                 return AVERROR(EINVAL);
     725             :             }
     726             : 
     727           0 :             if (sum == 0)
     728           0 :                 sum = 1;
     729           0 :             if (s->rdiv[i] == 0)
     730           0 :                 s->rdiv[i] = 1. / sum;
     731             : 
     732           0 :             if (s->copy[i] && (s->rdiv[i] != 1. || s->bias[i] != 0.))
     733           0 :                 s->copy[i] = 0;
     734             :         }
     735           0 :     } else if (!strcmp(ctx->filter->name, "prewitt")) {
     736           0 :         for (i = 0; i < 4; i++) {
     737           0 :             if ((1 << i) & s->planes)
     738           0 :                 s->filter[i] = filter_prewitt;
     739             :             else
     740           0 :                 s->copy[i] = 1;
     741           0 :             s->size[i] = 3;
     742           0 :             s->setup[i] = setup_3x3;
     743           0 :             s->rdiv[i] = s->scale;
     744           0 :             s->bias[i] = s->delta;
     745             :         }
     746           0 :     } else if (!strcmp(ctx->filter->name, "roberts")) {
     747           0 :         for (i = 0; i < 4; i++) {
     748           0 :             if ((1 << i) & s->planes)
     749           0 :                 s->filter[i] = filter_roberts;
     750             :             else
     751           0 :                 s->copy[i] = 1;
     752           0 :             s->size[i] = 3;
     753           0 :             s->setup[i] = setup_3x3;
     754           0 :             s->rdiv[i] = s->scale;
     755           0 :             s->bias[i] = s->delta;
     756             :         }
     757           0 :     } else if (!strcmp(ctx->filter->name, "sobel")) {
     758           0 :         for (i = 0; i < 4; i++) {
     759           0 :             if ((1 << i) & s->planes)
     760           0 :                 s->filter[i] = filter_sobel;
     761             :             else
     762           0 :                 s->copy[i] = 1;
     763           0 :             s->size[i] = 3;
     764           0 :             s->setup[i] = setup_3x3;
     765           0 :             s->rdiv[i] = s->scale;
     766           0 :             s->bias[i] = s->delta;
     767             :         }
     768             :     }
     769             : 
     770           0 :     return 0;
     771             : }
     772             : 
     773             : static const AVFilterPad convolution_inputs[] = {
     774             :     {
     775             :         .name         = "default",
     776             :         .type         = AVMEDIA_TYPE_VIDEO,
     777             :         .config_props = config_input,
     778             :         .filter_frame = filter_frame,
     779             :     },
     780             :     { NULL }
     781             : };
     782             : 
     783             : static const AVFilterPad convolution_outputs[] = {
     784             :     {
     785             :         .name = "default",
     786             :         .type = AVMEDIA_TYPE_VIDEO,
     787             :     },
     788             :     { NULL }
     789             : };
     790             : 
     791             : #if CONFIG_CONVOLUTION_FILTER
     792             : 
     793             : AVFilter ff_vf_convolution = {
     794             :     .name          = "convolution",
     795             :     .description   = NULL_IF_CONFIG_SMALL("Apply convolution filter."),
     796             :     .priv_size     = sizeof(ConvolutionContext),
     797             :     .priv_class    = &convolution_class,
     798             :     .init          = init,
     799             :     .query_formats = query_formats,
     800             :     .inputs        = convolution_inputs,
     801             :     .outputs       = convolution_outputs,
     802             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     803             : };
     804             : 
     805             : #endif /* CONFIG_CONVOLUTION_FILTER */
     806             : 
     807             : #if CONFIG_PREWITT_FILTER
     808             : 
     809             : static const AVOption prewitt_options[] = {
     810             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
     811             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
     812             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
     813             :     { NULL }
     814             : };
     815             : 
     816             : AVFILTER_DEFINE_CLASS(prewitt);
     817             : 
     818             : AVFilter ff_vf_prewitt = {
     819             :     .name          = "prewitt",
     820             :     .description   = NULL_IF_CONFIG_SMALL("Apply prewitt operator."),
     821             :     .priv_size     = sizeof(ConvolutionContext),
     822             :     .priv_class    = &prewitt_class,
     823             :     .init          = init,
     824             :     .query_formats = query_formats,
     825             :     .inputs        = convolution_inputs,
     826             :     .outputs       = convolution_outputs,
     827             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     828             : };
     829             : 
     830             : #endif /* CONFIG_PREWITT_FILTER */
     831             : 
     832             : #if CONFIG_SOBEL_FILTER
     833             : 
     834             : static const AVOption sobel_options[] = {
     835             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
     836             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
     837             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
     838             :     { NULL }
     839             : };
     840             : 
     841             : AVFILTER_DEFINE_CLASS(sobel);
     842             : 
     843             : AVFilter ff_vf_sobel = {
     844             :     .name          = "sobel",
     845             :     .description   = NULL_IF_CONFIG_SMALL("Apply sobel operator."),
     846             :     .priv_size     = sizeof(ConvolutionContext),
     847             :     .priv_class    = &sobel_class,
     848             :     .init          = init,
     849             :     .query_formats = query_formats,
     850             :     .inputs        = convolution_inputs,
     851             :     .outputs       = convolution_outputs,
     852             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     853             : };
     854             : 
     855             : #endif /* CONFIG_SOBEL_FILTER */
     856             : 
     857             : #if CONFIG_ROBERTS_FILTER
     858             : 
     859             : static const AVOption roberts_options[] = {
     860             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
     861             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
     862             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
     863             :     { NULL }
     864             : };
     865             : 
     866             : AVFILTER_DEFINE_CLASS(roberts);
     867             : 
     868             : AVFilter ff_vf_roberts = {
     869             :     .name          = "roberts",
     870             :     .description   = NULL_IF_CONFIG_SMALL("Apply roberts cross operator."),
     871             :     .priv_size     = sizeof(ConvolutionContext),
     872             :     .priv_class    = &roberts_class,
     873             :     .init          = init,
     874             :     .query_formats = query_formats,
     875             :     .inputs        = convolution_inputs,
     876             :     .outputs       = convolution_outputs,
     877             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     878             : };
     879             : 
     880             : #endif /* CONFIG_ROBERTS_FILTER */

Generated by: LCOV version 1.13