LCOV - code coverage report
Current view: top level - libavfilter - vf_convolution.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 686 0.0 %
Date: 2017-12-16 13:57:32 Functions: 0 19 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/opt.h"
      25             : #include "libavutil/pixdesc.h"
      26             : #include "avfilter.h"
      27             : #include "formats.h"
      28             : #include "internal.h"
      29             : #include "video.h"
      30             : 
      31             : typedef struct ConvolutionContext {
      32             :     const AVClass *class;
      33             : 
      34             :     char *matrix_str[4];
      35             :     float rdiv[4];
      36             :     float bias[4];
      37             :     float scale;
      38             :     float delta;
      39             :     int planes;
      40             : 
      41             :     int size[4];
      42             :     int depth;
      43             :     int bpc;
      44             :     int bstride;
      45             :     uint8_t *buffer;
      46             :     uint8_t **bptrs;
      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             :     int (*filter[4])(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
      56             : } ConvolutionContext;
      57             : 
      58             : #define OFFSET(x) offsetof(ConvolutionContext, x)
      59             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      60             : 
      61             : static const AVOption convolution_options[] = {
      62             :     { "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 },
      63             :     { "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 },
      64             :     { "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 },
      65             :     { "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 },
      66             :     { "0rdiv", "set rdiv for 1st plane", OFFSET(rdiv[0]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS},
      67             :     { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdiv[1]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS},
      68             :     { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdiv[2]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS},
      69             :     { "3rdiv", "set rdiv for 4th plane", OFFSET(rdiv[3]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS},
      70             :     { "0bias", "set bias for 1st plane", OFFSET(bias[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      71             :     { "1bias", "set bias for 2nd plane", OFFSET(bias[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      72             :     { "2bias", "set bias for 3rd plane", OFFSET(bias[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      73             :     { "3bias", "set bias for 4th plane", OFFSET(bias[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS},
      74             :     { NULL }
      75             : };
      76             : 
      77             : AVFILTER_DEFINE_CLASS(convolution);
      78             : 
      79             : static const int same3x3[9] = {0, 0, 0,
      80             :                                0, 1, 0,
      81             :                                0, 0, 0};
      82             : 
      83             : static const int same5x5[25] = {0, 0, 0, 0, 0,
      84             :                                 0, 0, 0, 0, 0,
      85             :                                 0, 0, 1, 0, 0,
      86             :                                 0, 0, 0, 0, 0,
      87             :                                 0, 0, 0, 0, 0};
      88             : 
      89             : static const int same7x7[49] = {0, 0, 0, 0, 0, 0, 0,
      90             :                                 0, 0, 0, 0, 0, 0, 0,
      91             :                                 0, 0, 0, 0, 0, 0, 0,
      92             :                                 0, 0, 0, 1, 0, 0, 0,
      93             :                                 0, 0, 0, 0, 0, 0, 0,
      94             :                                 0, 0, 0, 0, 0, 0, 0,
      95             :                                 0, 0, 0, 0, 0, 0, 0};
      96             : 
      97           0 : static int query_formats(AVFilterContext *ctx)
      98             : {
      99             :     static const enum AVPixelFormat pix_fmts[] = {
     100             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
     101             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
     102             :         AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
     103             :         AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
     104             :         AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
     105             :         AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
     106             :         AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
     107             :         AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
     108             :         AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
     109             :         AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
     110             :         AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
     111             :         AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
     112             :         AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
     113             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
     114             :         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
     115             :         AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
     116             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
     117             :         AV_PIX_FMT_NONE
     118             :     };
     119             : 
     120           0 :     return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
     121             : }
     122             : 
     123           0 : static inline void line_copy8(uint8_t *line, const uint8_t *srcp, int width, int mergin)
     124             : {
     125             :     int i;
     126             : 
     127           0 :     memcpy(line, srcp, width);
     128             : 
     129           0 :     for (i = mergin; i > 0; i--) {
     130           0 :         line[-i] = line[i];
     131           0 :         line[width - 1 + i] = line[width - 1 - i];
     132             :     }
     133           0 : }
     134             : 
     135           0 : static inline void line_copy16(uint16_t *line, const uint16_t *srcp, int width, int mergin)
     136             : {
     137             :     int i;
     138             : 
     139           0 :     memcpy(line, srcp, width * 2);
     140             : 
     141           0 :     for (i = mergin; i > 0; i--) {
     142           0 :         line[-i] = line[i];
     143           0 :         line[width - 1 + i] = line[width - 1 - i];
     144             :     }
     145           0 : }
     146             : 
     147             : typedef struct ThreadData {
     148             :     AVFrame *in, *out;
     149             :     int plane;
     150             : } ThreadData;
     151             : 
     152           0 : static int filter16_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     153             : {
     154           0 :     ConvolutionContext *s = ctx->priv;
     155           0 :     ThreadData *td = arg;
     156           0 :     AVFrame *in = td->in;
     157           0 :     AVFrame *out = td->out;
     158           0 :     const int plane = td->plane;
     159           0 :     const int peak = (1 << s->depth) - 1;
     160           0 :     const int stride = in->linesize[plane] / 2;
     161           0 :     const int bstride = s->bstride;
     162           0 :     const int height = s->planeheight[plane];
     163           0 :     const int width  = s->planewidth[plane];
     164           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     165           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     166           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     167           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     168           0 :     const float scale = s->scale;
     169           0 :     const float delta = s->delta;
     170           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16;
     171           0 :     uint16_t *p1 = p0 + bstride;
     172           0 :     uint16_t *p2 = p1 + bstride;
     173           0 :     uint16_t *orig = p0, *end = p2;
     174             :     int y, x;
     175             : 
     176           0 :     line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     177           0 :     line_copy16(p1, src, width, 1);
     178             : 
     179           0 :     for (y = slice_start; y < slice_end; y++) {
     180           0 :         src += stride * (y < height - 1 ? 1 : -1);
     181           0 :         line_copy16(p2, src, width, 1);
     182             : 
     183           0 :         for (x = 0; x < width; x++) {
     184           0 :             int suma = p0[x - 1] * -1 +
     185           0 :                        p0[x] *     -1 +
     186           0 :                        p0[x + 1] * -1 +
     187           0 :                        p2[x - 1] *  1 +
     188           0 :                        p2[x] *      1 +
     189           0 :                        p2[x + 1] *  1;
     190           0 :             int sumb = p0[x - 1] * -1 +
     191           0 :                        p0[x + 1] *  1 +
     192           0 :                        p1[x - 1] * -1 +
     193           0 :                        p1[x + 1] *  1 +
     194           0 :                        p2[x - 1] * -1 +
     195           0 :                        p2[x + 1] *  1;
     196             : 
     197           0 :             dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     198             :         }
     199             : 
     200           0 :         p0 = p1;
     201           0 :         p1 = p2;
     202           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     203           0 :         dst += out->linesize[plane] / 2;
     204             :     }
     205             : 
     206           0 :     return 0;
     207             : }
     208             : 
     209           0 : static int filter16_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     210             : {
     211           0 :     ConvolutionContext *s = ctx->priv;
     212           0 :     ThreadData *td = arg;
     213           0 :     AVFrame *in = td->in;
     214           0 :     AVFrame *out = td->out;
     215           0 :     const int plane = td->plane;
     216           0 :     const int peak = (1 << s->depth) - 1;
     217           0 :     const int stride = in->linesize[plane] / 2;
     218           0 :     const int bstride = s->bstride;
     219           0 :     const int height = s->planeheight[plane];
     220           0 :     const int width  = s->planewidth[plane];
     221           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     222           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     223           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     224           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     225           0 :     const float scale = s->scale;
     226           0 :     const float delta = s->delta;
     227           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16;
     228           0 :     uint16_t *p1 = p0 + bstride;
     229           0 :     uint16_t *p2 = p1 + bstride;
     230           0 :     uint16_t *orig = p0, *end = p2;
     231             :     int y, x;
     232             : 
     233           0 :     line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     234           0 :     line_copy16(p1, src, width, 1);
     235             : 
     236           0 :     for (y = slice_start; y < slice_end; y++) {
     237           0 :         src += stride * (y < height - 1 ? 1 : -1);
     238           0 :         line_copy16(p2, src, width, 1);
     239             : 
     240           0 :         for (x = 0; x < width; x++) {
     241           0 :             int suma = p0[x - 1] *  1 +
     242           0 :                        p1[x    ] * -1;
     243           0 :             int sumb = p0[x    ] *  1 +
     244           0 :                        p1[x - 1] * -1;
     245             : 
     246           0 :             dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     247             :         }
     248             : 
     249           0 :         p0 = p1;
     250           0 :         p1 = p2;
     251           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     252           0 :         dst += out->linesize[plane] / 2;
     253             :     }
     254             : 
     255           0 :     return 0;
     256             : }
     257             : 
     258           0 : static int filter16_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     259             : {
     260           0 :     ConvolutionContext *s = ctx->priv;
     261           0 :     ThreadData *td = arg;
     262           0 :     AVFrame *in = td->in;
     263           0 :     AVFrame *out = td->out;
     264           0 :     const int plane = td->plane;
     265           0 :     const int peak = (1 << s->depth) - 1;
     266           0 :     const int stride = in->linesize[plane] / 2;
     267           0 :     const int bstride = s->bstride;
     268           0 :     const int height = s->planeheight[plane];
     269           0 :     const int width  = s->planewidth[plane];
     270           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     271           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     272           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     273           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     274           0 :     const float scale = s->scale;
     275           0 :     const float delta = s->delta;
     276           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16;
     277           0 :     uint16_t *p1 = p0 + bstride;
     278           0 :     uint16_t *p2 = p1 + bstride;
     279           0 :     uint16_t *orig = p0, *end = p2;
     280             :     int y, x;
     281             : 
     282           0 :     line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     283           0 :     line_copy16(p1, src, width, 1);
     284             : 
     285           0 :     for (y = slice_start; y < slice_end; y++) {
     286           0 :         src += stride * (y < height - 1 ? 1 : -1);
     287           0 :         line_copy16(p2, src, width, 1);
     288             : 
     289           0 :         for (x = 0; x < width; x++) {
     290           0 :             int suma = p0[x - 1] * -1 +
     291           0 :                        p0[x] *     -2 +
     292           0 :                        p0[x + 1] * -1 +
     293           0 :                        p2[x - 1] *  1 +
     294           0 :                        p2[x] *      2 +
     295           0 :                        p2[x + 1] *  1;
     296           0 :             int sumb = p0[x - 1] * -1 +
     297           0 :                        p0[x + 1] *  1 +
     298           0 :                        p1[x - 1] * -2 +
     299           0 :                        p1[x + 1] *  2 +
     300           0 :                        p2[x - 1] * -1 +
     301           0 :                        p2[x + 1] *  1;
     302             : 
     303           0 :             dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
     304             :         }
     305             : 
     306           0 :         p0 = p1;
     307           0 :         p1 = p2;
     308           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     309           0 :         dst += out->linesize[plane] / 2;
     310             :     }
     311             : 
     312           0 :     return 0;
     313             : }
     314             : 
     315           0 : static int filter_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     316             : {
     317           0 :     ConvolutionContext *s = ctx->priv;
     318           0 :     ThreadData *td = arg;
     319           0 :     AVFrame *in = td->in;
     320           0 :     AVFrame *out = td->out;
     321           0 :     const int plane = td->plane;
     322           0 :     const int stride = in->linesize[plane];
     323           0 :     const int bstride = s->bstride;
     324           0 :     const int height = s->planeheight[plane];
     325           0 :     const int width  = s->planewidth[plane];
     326           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     327           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     328           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     329           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     330           0 :     const float scale = s->scale;
     331           0 :     const float delta = s->delta;
     332           0 :     uint8_t *p0 = s->bptrs[jobnr] + 16;
     333           0 :     uint8_t *p1 = p0 + bstride;
     334           0 :     uint8_t *p2 = p1 + bstride;
     335           0 :     uint8_t *orig = p0, *end = p2;
     336             :     int y, x;
     337             : 
     338           0 :     line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     339           0 :     line_copy8(p1, src, width, 1);
     340             : 
     341           0 :     for (y = slice_start; y < slice_end; y++) {
     342           0 :         src += stride * (y < height - 1 ? 1 : -1);
     343           0 :         line_copy8(p2, src, width, 1);
     344             : 
     345           0 :         for (x = 0; x < width; x++) {
     346           0 :             int suma = p0[x - 1] * -1 +
     347           0 :                        p0[x] *     -1 +
     348           0 :                        p0[x + 1] * -1 +
     349           0 :                        p2[x - 1] *  1 +
     350           0 :                        p2[x] *      1 +
     351           0 :                        p2[x + 1] *  1;
     352           0 :             int sumb = p0[x - 1] * -1 +
     353           0 :                        p0[x + 1] *  1 +
     354           0 :                        p1[x - 1] * -1 +
     355           0 :                        p1[x + 1] *  1 +
     356           0 :                        p2[x - 1] * -1 +
     357           0 :                        p2[x + 1] *  1;
     358             : 
     359           0 :             dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     360             :         }
     361             : 
     362           0 :         p0 = p1;
     363           0 :         p1 = p2;
     364           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     365           0 :         dst += out->linesize[plane];
     366             :     }
     367             : 
     368           0 :     return 0;
     369             : }
     370             : 
     371           0 : static int filter_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     372             : {
     373           0 :     ConvolutionContext *s = ctx->priv;
     374           0 :     ThreadData *td = arg;
     375           0 :     AVFrame *in = td->in;
     376           0 :     AVFrame *out = td->out;
     377           0 :     const int plane = td->plane;
     378           0 :     const int stride = in->linesize[plane];
     379           0 :     const int bstride = s->bstride;
     380           0 :     const int height = s->planeheight[plane];
     381           0 :     const int width  = s->planewidth[plane];
     382           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     383           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     384           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     385           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     386           0 :     const float scale = s->scale;
     387           0 :     const float delta = s->delta;
     388           0 :     uint8_t *p0 = s->bptrs[jobnr] + 16;
     389           0 :     uint8_t *p1 = p0 + bstride;
     390           0 :     uint8_t *p2 = p1 + bstride;
     391           0 :     uint8_t *orig = p0, *end = p2;
     392             :     int y, x;
     393             : 
     394           0 :     line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     395           0 :     line_copy8(p1, src, width, 1);
     396             : 
     397           0 :     for (y = slice_start; y < slice_end; y++) {
     398           0 :         src += stride * (y < height - 1 ? 1 : -1);
     399           0 :         line_copy8(p2, src, width, 1);
     400             : 
     401           0 :         for (x = 0; x < width; x++) {
     402           0 :             int suma = p0[x - 1] *  1 +
     403           0 :                        p1[x    ] * -1;
     404           0 :             int sumb = p0[x    ] *  1 +
     405           0 :                        p1[x - 1] * -1;
     406             : 
     407           0 :             dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     408             :         }
     409             : 
     410           0 :         p0 = p1;
     411           0 :         p1 = p2;
     412           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     413           0 :         dst += out->linesize[plane];
     414             :     }
     415             : 
     416           0 :     return 0;
     417             : }
     418             : 
     419           0 : static int filter_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     420             : {
     421           0 :     ConvolutionContext *s = ctx->priv;
     422           0 :     ThreadData *td = arg;
     423           0 :     AVFrame *in = td->in;
     424           0 :     AVFrame *out = td->out;
     425           0 :     const int plane = td->plane;
     426           0 :     const int stride = in->linesize[plane];
     427           0 :     const int bstride = s->bstride;
     428           0 :     const int height = s->planeheight[plane];
     429           0 :     const int width  = s->planewidth[plane];
     430           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     431           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     432           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     433           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     434           0 :     const float scale = s->scale;
     435           0 :     const float delta = s->delta;
     436           0 :     uint8_t *p0 = s->bptrs[jobnr] + 16;
     437           0 :     uint8_t *p1 = p0 + bstride;
     438           0 :     uint8_t *p2 = p1 + bstride;
     439           0 :     uint8_t *orig = p0, *end = p2;
     440             :     int y, x;
     441             : 
     442           0 :     line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     443           0 :     line_copy8(p1, src, width, 1);
     444             : 
     445           0 :     for (y = slice_start; y < slice_end; y++) {
     446           0 :         src += stride * (y < height - 1 ? 1 : -1);
     447           0 :         line_copy8(p2, src, width, 1);
     448             : 
     449           0 :         for (x = 0; x < width; x++) {
     450           0 :             int suma = p0[x - 1] * -1 +
     451           0 :                        p0[x] *     -2 +
     452           0 :                        p0[x + 1] * -1 +
     453           0 :                        p2[x - 1] *  1 +
     454           0 :                        p2[x] *      2 +
     455           0 :                        p2[x + 1] *  1;
     456           0 :             int sumb = p0[x - 1] * -1 +
     457           0 :                        p0[x + 1] *  1 +
     458           0 :                        p1[x - 1] * -2 +
     459           0 :                        p1[x + 1] *  2 +
     460           0 :                        p2[x - 1] * -1 +
     461           0 :                        p2[x + 1] *  1;
     462             : 
     463           0 :             dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
     464             :         }
     465             : 
     466           0 :         p0 = p1;
     467           0 :         p1 = p2;
     468           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     469           0 :         dst += out->linesize[plane];
     470             :     }
     471             : 
     472           0 :     return 0;
     473             : }
     474             : 
     475           0 : static int filter16_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     476             : {
     477           0 :     ConvolutionContext *s = ctx->priv;
     478           0 :     ThreadData *td = arg;
     479           0 :     AVFrame *in = td->in;
     480           0 :     AVFrame *out = td->out;
     481           0 :     const int plane = td->plane;
     482           0 :     const int peak = (1 << s->depth) - 1;
     483           0 :     const int stride = in->linesize[plane] / 2;
     484           0 :     const int bstride = s->bstride;
     485           0 :     const int height = s->planeheight[plane];
     486           0 :     const int width  = s->planewidth[plane];
     487           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     488           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     489           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     490           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     491           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16;
     492           0 :     uint16_t *p1 = p0 + bstride;
     493           0 :     uint16_t *p2 = p1 + bstride;
     494           0 :     uint16_t *orig = p0, *end = p2;
     495           0 :     const int *matrix = s->matrix[plane];
     496           0 :     const float rdiv = s->rdiv[plane];
     497           0 :     const float bias = s->bias[plane];
     498             :     int y, x;
     499             : 
     500           0 :     line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     501           0 :     line_copy16(p1, src, width, 1);
     502             : 
     503           0 :     for (y = slice_start; y < slice_end; y++) {
     504           0 :         src += stride * (y < height - 1 ? 1 : -1);
     505           0 :         line_copy16(p2, src, width, 1);
     506             : 
     507           0 :         for (x = 0; x < width; x++) {
     508           0 :             int sum = p0[x - 1] * matrix[0] +
     509           0 :                       p0[x] *     matrix[1] +
     510           0 :                       p0[x + 1] * matrix[2] +
     511           0 :                       p1[x - 1] * matrix[3] +
     512           0 :                       p1[x] *     matrix[4] +
     513           0 :                       p1[x + 1] * matrix[5] +
     514           0 :                       p2[x - 1] * matrix[6] +
     515           0 :                       p2[x] *     matrix[7] +
     516           0 :                       p2[x + 1] * matrix[8];
     517           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     518           0 :             dst[x] = av_clip(sum, 0, peak);
     519             :         }
     520             : 
     521           0 :         p0 = p1;
     522           0 :         p1 = p2;
     523           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     524           0 :         dst += out->linesize[plane] / 2;
     525             :     }
     526             : 
     527           0 :     return 0;
     528             : }
     529             : 
     530           0 : static int filter16_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     531             : {
     532           0 :     ConvolutionContext *s = ctx->priv;
     533           0 :     ThreadData *td = arg;
     534           0 :     AVFrame *in = td->in;
     535           0 :     AVFrame *out = td->out;
     536           0 :     const int plane = td->plane;
     537           0 :     const int peak = (1 << s->depth) - 1;
     538           0 :     const int stride = in->linesize[plane] / 2;
     539           0 :     const int bstride = s->bstride;
     540           0 :     const int height = s->planeheight[plane];
     541           0 :     const int width  = s->planewidth[plane];
     542           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     543           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     544           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     545           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     546           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16;
     547           0 :     uint16_t *p1 = p0 + bstride;
     548           0 :     uint16_t *p2 = p1 + bstride;
     549           0 :     uint16_t *p3 = p2 + bstride;
     550           0 :     uint16_t *p4 = p3 + bstride;
     551           0 :     uint16_t *orig = p0, *end = p4;
     552           0 :     const int *matrix = s->matrix[plane];
     553           0 :     float rdiv = s->rdiv[plane];
     554           0 :     float bias = s->bias[plane];
     555             :     int y, x, i;
     556             : 
     557           0 :     line_copy16(p0, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 2);
     558           0 :     line_copy16(p1, src + stride * (slice_start == 0 ? 1 : -1), width, 2);
     559           0 :     line_copy16(p2, src, width, 2);
     560           0 :     src += stride;
     561           0 :     line_copy16(p3, src, width, 2);
     562             : 
     563           0 :     for (y = slice_start; y < slice_end; y++) {
     564           0 :         uint16_t *array[] = {
     565           0 :             p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2,
     566           0 :             p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2,
     567           0 :             p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2,
     568           0 :             p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2,
     569           0 :             p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2
     570             :         };
     571             : 
     572           0 :         src += stride * (y < height - 2 ? 1 : -1);
     573           0 :         line_copy16(p4, src, width, 2);
     574             : 
     575           0 :         for (x = 0; x < width; x++) {
     576           0 :             int sum = 0;
     577             : 
     578           0 :             for (i = 0; i < 25; i++) {
     579           0 :                 sum += *(array[i] + x) * matrix[i];
     580             :             }
     581           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     582           0 :             dst[x] = av_clip(sum, 0, peak);
     583             :         }
     584             : 
     585           0 :         p0 = p1;
     586           0 :         p1 = p2;
     587           0 :         p2 = p3;
     588           0 :         p3 = p4;
     589           0 :         p4 = (p4 == end) ? orig: p4 + bstride;
     590           0 :         dst += out->linesize[plane] / 2;
     591             :     }
     592             : 
     593           0 :     return 0;
     594             : }
     595             : 
     596           0 : static int filter16_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     597             : {
     598           0 :     ConvolutionContext *s = ctx->priv;
     599           0 :     ThreadData *td = arg;
     600           0 :     AVFrame *in = td->in;
     601           0 :     AVFrame *out = td->out;
     602           0 :     const int plane = td->plane;
     603           0 :     const int peak = (1 << s->depth) - 1;
     604           0 :     const int stride = in->linesize[plane] / 2;
     605           0 :     const int bstride = s->bstride;
     606           0 :     const int height = s->planeheight[plane];
     607           0 :     const int width  = s->planewidth[plane];
     608           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     609           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     610           0 :     const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride;
     611           0 :     uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2);
     612           0 :     uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 32;
     613           0 :     uint16_t *p1 = p0 + bstride;
     614           0 :     uint16_t *p2 = p1 + bstride;
     615           0 :     uint16_t *p3 = p2 + bstride;
     616           0 :     uint16_t *p4 = p3 + bstride;
     617           0 :     uint16_t *p5 = p4 + bstride;
     618           0 :     uint16_t *p6 = p5 + bstride;
     619           0 :     uint16_t *orig = p0, *end = p6;
     620           0 :     const int *matrix = s->matrix[plane];
     621           0 :     float rdiv = s->rdiv[plane];
     622           0 :     float bias = s->bias[plane];
     623             :     int y, x, i;
     624             : 
     625           0 :     line_copy16(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3);
     626           0 :     line_copy16(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3);
     627           0 :     line_copy16(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3);
     628           0 :     line_copy16(p3, src, width, 3);
     629           0 :     src += stride;
     630           0 :     line_copy16(p4, src, width, 3);
     631           0 :     src += stride;
     632           0 :     line_copy16(p5, src, width, 3);
     633             : 
     634           0 :     for (y = slice_start; y < slice_end; y++) {
     635           0 :         uint16_t *array[] = {
     636           0 :             p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3,
     637           0 :             p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3,
     638           0 :             p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3,
     639           0 :             p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3,
     640           0 :             p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3,
     641           0 :             p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3,
     642           0 :             p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3,
     643             :         };
     644             : 
     645           0 :         src += stride * (y < height - 3 ? 1 : -1);
     646           0 :         line_copy16(p6, src, width, 3);
     647             : 
     648           0 :         for (x = 0; x < width; x++) {
     649           0 :             int sum = 0;
     650             : 
     651           0 :             for (i = 0; i < 25; i++) {
     652           0 :                 sum += *(array[i] + x) * matrix[i];
     653             :             }
     654           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     655           0 :             dst[x] = av_clip(sum, 0, peak);
     656             :         }
     657             : 
     658           0 :         p0 = p1;
     659           0 :         p1 = p2;
     660           0 :         p2 = p3;
     661           0 :         p3 = p4;
     662           0 :         p4 = p5;
     663           0 :         p5 = p6;
     664           0 :         p6 = (p6 == end) ? orig: p6 + bstride;
     665           0 :         dst += out->linesize[plane] / 2;
     666             :     }
     667             : 
     668           0 :     return 0;
     669             : }
     670             : 
     671           0 : static int filter_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     672             : {
     673           0 :     ConvolutionContext *s = ctx->priv;
     674           0 :     ThreadData *td = arg;
     675           0 :     AVFrame *in = td->in;
     676           0 :     AVFrame *out = td->out;
     677           0 :     const int plane = td->plane;
     678           0 :     const int stride = in->linesize[plane];
     679           0 :     const int bstride = s->bstride;
     680           0 :     const int height = s->planeheight[plane];
     681           0 :     const int width  = s->planewidth[plane];
     682           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     683           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     684           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     685           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     686           0 :     uint8_t *p0 = s->bptrs[jobnr] + 16;
     687           0 :     uint8_t *p1 = p0 + bstride;
     688           0 :     uint8_t *p2 = p1 + bstride;
     689           0 :     uint8_t *orig = p0, *end = p2;
     690           0 :     const int *matrix = s->matrix[plane];
     691           0 :     const float rdiv = s->rdiv[plane];
     692           0 :     const float bias = s->bias[plane];
     693             :     int y, x;
     694             : 
     695           0 :     line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1);
     696           0 :     line_copy8(p1, src, width, 1);
     697             : 
     698           0 :     for (y = slice_start; y < slice_end; y++) {
     699           0 :         src += stride * (y < height - 1 ? 1 : -1);
     700           0 :         line_copy8(p2, src, width, 1);
     701             : 
     702           0 :         for (x = 0; x < width; x++) {
     703           0 :             int sum = p0[x - 1] * matrix[0] +
     704           0 :                       p0[x] *     matrix[1] +
     705           0 :                       p0[x + 1] * matrix[2] +
     706           0 :                       p1[x - 1] * matrix[3] +
     707           0 :                       p1[x] *     matrix[4] +
     708           0 :                       p1[x + 1] * matrix[5] +
     709           0 :                       p2[x - 1] * matrix[6] +
     710           0 :                       p2[x] *     matrix[7] +
     711           0 :                       p2[x + 1] * matrix[8];
     712           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     713           0 :             dst[x] = av_clip_uint8(sum);
     714             :         }
     715             : 
     716           0 :         p0 = p1;
     717           0 :         p1 = p2;
     718           0 :         p2 = (p2 == end) ? orig: p2 + bstride;
     719           0 :         dst += out->linesize[plane];
     720             :     }
     721             : 
     722           0 :     return 0;
     723             : }
     724             : 
     725           0 : static int filter_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     726             : {
     727           0 :     ConvolutionContext *s = ctx->priv;
     728           0 :     ThreadData *td = arg;
     729           0 :     AVFrame *in = td->in;
     730           0 :     AVFrame *out = td->out;
     731           0 :     const int plane = td->plane;
     732           0 :     const int stride = in->linesize[plane];
     733           0 :     const int bstride = s->bstride;
     734           0 :     const int height = s->planeheight[plane];
     735           0 :     const int width  = s->planewidth[plane];
     736           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     737           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     738           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     739           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     740           0 :     uint8_t *p0 = s->bptrs[jobnr] + 16;
     741           0 :     uint8_t *p1 = p0 + bstride;
     742           0 :     uint8_t *p2 = p1 + bstride;
     743           0 :     uint8_t *p3 = p2 + bstride;
     744           0 :     uint8_t *p4 = p3 + bstride;
     745           0 :     uint8_t *orig = p0, *end = p4;
     746           0 :     const int *matrix = s->matrix[plane];
     747           0 :     float rdiv = s->rdiv[plane];
     748           0 :     float bias = s->bias[plane];
     749             :     int y, x, i;
     750             : 
     751           0 :     line_copy8(p0, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 2);
     752           0 :     line_copy8(p1, src + stride * (slice_start == 0 ? 1 : -1), width, 2);
     753           0 :     line_copy8(p2, src, width, 2);
     754           0 :     src += stride;
     755           0 :     line_copy8(p3, src, width, 2);
     756             : 
     757             : 
     758           0 :     for (y = slice_start; y < slice_end; y++) {
     759           0 :         uint8_t *array[] = {
     760           0 :             p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2,
     761           0 :             p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2,
     762           0 :             p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2,
     763           0 :             p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2,
     764           0 :             p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2
     765             :         };
     766             : 
     767           0 :         src += stride * (y < height - 2 ? 1 : -1);
     768           0 :         line_copy8(p4, src, width, 2);
     769             : 
     770           0 :         for (x = 0; x < width; x++) {
     771           0 :             int sum = 0;
     772             : 
     773           0 :             for (i = 0; i < 25; i++) {
     774           0 :                 sum += *(array[i] + x) * matrix[i];
     775             :             }
     776           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     777           0 :             dst[x] = av_clip_uint8(sum);
     778             :         }
     779             : 
     780           0 :         p0 = p1;
     781           0 :         p1 = p2;
     782           0 :         p2 = p3;
     783           0 :         p3 = p4;
     784           0 :         p4 = (p4 == end) ? orig: p4 + bstride;
     785           0 :         dst += out->linesize[plane];
     786             :     }
     787             : 
     788           0 :     return 0;
     789             : }
     790             : 
     791           0 : static int filter_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     792             : {
     793           0 :     ConvolutionContext *s = ctx->priv;
     794           0 :     ThreadData *td = arg;
     795           0 :     AVFrame *in = td->in;
     796           0 :     AVFrame *out = td->out;
     797           0 :     const int plane = td->plane;
     798           0 :     const int stride = in->linesize[plane];
     799           0 :     const int bstride = s->bstride;
     800           0 :     const int height = s->planeheight[plane];
     801           0 :     const int width  = s->planewidth[plane];
     802           0 :     const int slice_start = (height * jobnr) / nb_jobs;
     803           0 :     const int slice_end = (height * (jobnr+1)) / nb_jobs;
     804           0 :     const uint8_t *src = in->data[plane] + slice_start * stride;
     805           0 :     uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane];
     806           0 :     uint8_t *p0 = s->bptrs[jobnr] + 32;
     807           0 :     uint8_t *p1 = p0 + bstride;
     808           0 :     uint8_t *p2 = p1 + bstride;
     809           0 :     uint8_t *p3 = p2 + bstride;
     810           0 :     uint8_t *p4 = p3 + bstride;
     811           0 :     uint8_t *p5 = p4 + bstride;
     812           0 :     uint8_t *p6 = p5 + bstride;
     813           0 :     uint8_t *orig = p0, *end = p6;
     814           0 :     const int *matrix = s->matrix[plane];
     815           0 :     float rdiv = s->rdiv[plane];
     816           0 :     float bias = s->bias[plane];
     817             :     int y, x, i;
     818             : 
     819           0 :     line_copy8(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3);
     820           0 :     line_copy8(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3);
     821           0 :     line_copy8(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3);
     822           0 :     line_copy8(p3, src, width, 3);
     823           0 :     src += stride;
     824           0 :     line_copy8(p4, src, width, 3);
     825           0 :     src += stride;
     826           0 :     line_copy8(p5, src, width, 3);
     827             : 
     828           0 :     for (y = slice_start; y < slice_end; y++) {
     829           0 :         uint8_t *array[] = {
     830           0 :             p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3,
     831           0 :             p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3,
     832           0 :             p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3,
     833           0 :             p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3,
     834           0 :             p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3,
     835           0 :             p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3,
     836           0 :             p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3,
     837             :         };
     838             : 
     839           0 :         src += stride * (y < height - 3 ? 1 : -1);
     840           0 :         line_copy8(p6, src, width, 3);
     841             : 
     842           0 :         for (x = 0; x < width; x++) {
     843           0 :             int sum = 0;
     844             : 
     845           0 :             for (i = 0; i < 49; i++) {
     846           0 :                 sum += *(array[i] + x) * matrix[i];
     847             :             }
     848           0 :             sum = (int)(sum * rdiv + bias + 0.5f);
     849           0 :             dst[x] = av_clip_uint8(sum);
     850             :         }
     851             : 
     852           0 :         p0 = p1;
     853           0 :         p1 = p2;
     854           0 :         p2 = p3;
     855           0 :         p3 = p4;
     856           0 :         p4 = p5;
     857           0 :         p5 = p6;
     858           0 :         p6 = (p6 == end) ? orig: p6 + bstride;
     859           0 :         dst += out->linesize[plane];
     860             :     }
     861             : 
     862           0 :     return 0;
     863             : }
     864             : 
     865           0 : static int config_input(AVFilterLink *inlink)
     866             : {
     867           0 :     AVFilterContext *ctx = inlink->dst;
     868           0 :     ConvolutionContext *s = ctx->priv;
     869           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     870             :     int p;
     871             : 
     872           0 :     s->depth = desc->comp[0].depth;
     873             : 
     874           0 :     s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
     875           0 :     s->planewidth[0] = s->planewidth[3] = inlink->w;
     876           0 :     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
     877           0 :     s->planeheight[0] = s->planeheight[3] = inlink->h;
     878             : 
     879           0 :     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
     880           0 :     s->nb_threads = ff_filter_get_nb_threads(ctx);
     881           0 :     s->bptrs = av_calloc(s->nb_threads, sizeof(*s->bptrs));
     882           0 :     if (!s->bptrs)
     883           0 :         return AVERROR(ENOMEM);
     884             : 
     885           0 :     s->bstride = s->planewidth[0] + 64;
     886           0 :     s->bpc = (s->depth + 7) / 8;
     887           0 :     s->buffer = av_malloc_array(7 * s->bstride * s->nb_threads, s->bpc);
     888           0 :     if (!s->buffer)
     889           0 :         return AVERROR(ENOMEM);
     890             : 
     891           0 :     for (p = 0; p < s->nb_threads; p++) {
     892           0 :         s->bptrs[p] = s->buffer + 7 * s->bstride * s->bpc * p;
     893             :     }
     894             : 
     895           0 :     if (!strcmp(ctx->filter->name, "convolution")) {
     896           0 :         if (s->depth > 8) {
     897           0 :             for (p = 0; p < s->nb_planes; p++) {
     898           0 :                 if (s->size[p] == 3)
     899           0 :                     s->filter[p] = filter16_3x3;
     900           0 :                 else if (s->size[p] == 5)
     901           0 :                     s->filter[p] = filter16_5x5;
     902           0 :                 else if (s->size[p] == 7)
     903           0 :                     s->filter[p] = filter16_7x7;
     904             :             }
     905             :         }
     906           0 :     } else if (!strcmp(ctx->filter->name, "prewitt")) {
     907           0 :         if (s->depth > 8)
     908           0 :             for (p = 0; p < s->nb_planes; p++)
     909           0 :                 s->filter[p] = filter16_prewitt;
     910           0 :     } else if (!strcmp(ctx->filter->name, "roberts")) {
     911           0 :         if (s->depth > 8)
     912           0 :             for (p = 0; p < s->nb_planes; p++)
     913           0 :                 s->filter[p] = filter16_roberts;
     914           0 :     } else if (!strcmp(ctx->filter->name, "sobel")) {
     915           0 :         if (s->depth > 8)
     916           0 :             for (p = 0; p < s->nb_planes; p++)
     917           0 :                 s->filter[p] = filter16_sobel;
     918             :     }
     919             : 
     920           0 :     return 0;
     921             : }
     922             : 
     923           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     924             : {
     925           0 :     AVFilterContext *ctx = inlink->dst;
     926           0 :     ConvolutionContext *s = ctx->priv;
     927           0 :     AVFilterLink *outlink = ctx->outputs[0];
     928             :     AVFrame *out;
     929             :     int plane;
     930             : 
     931           0 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     932           0 :     if (!out) {
     933           0 :         av_frame_free(&in);
     934           0 :         return AVERROR(ENOMEM);
     935             :     }
     936           0 :     av_frame_copy_props(out, in);
     937             : 
     938           0 :     for (plane = 0; plane < s->nb_planes; plane++) {
     939             :         ThreadData td;
     940             : 
     941           0 :         if (s->copy[plane]) {
     942           0 :             av_image_copy_plane(out->data[plane], out->linesize[plane],
     943           0 :                                 in->data[plane], in->linesize[plane],
     944           0 :                                 s->planewidth[plane] * s->bpc,
     945             :                                 s->planeheight[plane]);
     946           0 :             continue;
     947             :         }
     948             : 
     949           0 :         td.in = in;
     950           0 :         td.out = out;
     951           0 :         td.plane = plane;
     952           0 :         ctx->internal->execute(ctx, s->filter[plane], &td, NULL, FFMIN(s->planeheight[plane], s->nb_threads));
     953             :     }
     954             : 
     955           0 :     av_frame_free(&in);
     956           0 :     return ff_filter_frame(outlink, out);
     957             : }
     958             : 
     959           0 : static av_cold int init(AVFilterContext *ctx)
     960             : {
     961           0 :     ConvolutionContext *s = ctx->priv;
     962             :     int i;
     963             : 
     964           0 :     if (!strcmp(ctx->filter->name, "convolution")) {
     965           0 :         for (i = 0; i < 4; i++) {
     966           0 :             int *matrix = (int *)s->matrix[i];
     967           0 :             char *p, *arg, *saveptr = NULL;
     968             : 
     969           0 :             p = s->matrix_str[i];
     970           0 :             while (s->matrix_length[i] < 49) {
     971           0 :                 if (!(arg = av_strtok(p, " ", &saveptr)))
     972           0 :                     break;
     973             : 
     974           0 :                 p = NULL;
     975           0 :                 sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
     976           0 :                 s->matrix_length[i]++;
     977             :             }
     978             : 
     979           0 :             if (s->matrix_length[i] == 9) {
     980           0 :                 s->size[i] = 3;
     981           0 :                 if (!memcmp(matrix, same3x3, sizeof(same3x3)))
     982           0 :                     s->copy[i] = 1;
     983             :                 else
     984           0 :                     s->filter[i] = filter_3x3;
     985           0 :             } else if (s->matrix_length[i] == 25) {
     986           0 :                 s->size[i] = 5;
     987           0 :                 if (!memcmp(matrix, same5x5, sizeof(same5x5)))
     988           0 :                     s->copy[i] = 1;
     989             :                 else
     990           0 :                     s->filter[i] = filter_5x5;
     991           0 :             } else if (s->matrix_length[i] == 49) {
     992           0 :                 s->size[i] = 7;
     993           0 :                 if (!memcmp(matrix, same7x7, sizeof(same7x7)))
     994           0 :                     s->copy[i] = 1;
     995             :                 else
     996           0 :                     s->filter[i] = filter_7x7;
     997             :             } else {
     998           0 :                 return AVERROR(EINVAL);
     999             :             }
    1000             :         }
    1001           0 :     } else if (!strcmp(ctx->filter->name, "prewitt")) {
    1002           0 :         for (i = 0; i < 4; i++) {
    1003           0 :             if ((1 << i) & s->planes)
    1004           0 :                 s->filter[i] = filter_prewitt;
    1005             :             else
    1006           0 :                 s->copy[i] = 1;
    1007             :         }
    1008           0 :     } else if (!strcmp(ctx->filter->name, "roberts")) {
    1009           0 :         for (i = 0; i < 4; i++) {
    1010           0 :             if ((1 << i) & s->planes)
    1011           0 :                 s->filter[i] = filter_roberts;
    1012             :             else
    1013           0 :                 s->copy[i] = 1;
    1014             :         }
    1015           0 :     } else if (!strcmp(ctx->filter->name, "sobel")) {
    1016           0 :         for (i = 0; i < 4; i++) {
    1017           0 :             if ((1 << i) & s->planes)
    1018           0 :                 s->filter[i] = filter_sobel;
    1019             :             else
    1020           0 :                 s->copy[i] = 1;
    1021             :         }
    1022             :     }
    1023             : 
    1024           0 :     return 0;
    1025             : }
    1026             : 
    1027           0 : static av_cold void uninit(AVFilterContext *ctx)
    1028             : {
    1029           0 :     ConvolutionContext *s = ctx->priv;
    1030             : 
    1031           0 :     av_freep(&s->bptrs);
    1032           0 :     av_freep(&s->buffer);
    1033           0 : }
    1034             : 
    1035             : static const AVFilterPad convolution_inputs[] = {
    1036             :     {
    1037             :         .name         = "default",
    1038             :         .type         = AVMEDIA_TYPE_VIDEO,
    1039             :         .config_props = config_input,
    1040             :         .filter_frame = filter_frame,
    1041             :     },
    1042             :     { NULL }
    1043             : };
    1044             : 
    1045             : static const AVFilterPad convolution_outputs[] = {
    1046             :     {
    1047             :         .name = "default",
    1048             :         .type = AVMEDIA_TYPE_VIDEO,
    1049             :     },
    1050             :     { NULL }
    1051             : };
    1052             : 
    1053             : #if CONFIG_CONVOLUTION_FILTER
    1054             : 
    1055             : AVFilter ff_vf_convolution = {
    1056             :     .name          = "convolution",
    1057             :     .description   = NULL_IF_CONFIG_SMALL("Apply convolution filter."),
    1058             :     .priv_size     = sizeof(ConvolutionContext),
    1059             :     .priv_class    = &convolution_class,
    1060             :     .init          = init,
    1061             :     .uninit        = uninit,
    1062             :     .query_formats = query_formats,
    1063             :     .inputs        = convolution_inputs,
    1064             :     .outputs       = convolution_outputs,
    1065             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
    1066             : };
    1067             : 
    1068             : #endif /* CONFIG_CONVOLUTION_FILTER */
    1069             : 
    1070             : #if CONFIG_PREWITT_FILTER
    1071             : 
    1072             : static const AVOption prewitt_options[] = {
    1073             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
    1074             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
    1075             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
    1076             :     { NULL }
    1077             : };
    1078             : 
    1079             : AVFILTER_DEFINE_CLASS(prewitt);
    1080             : 
    1081             : AVFilter ff_vf_prewitt = {
    1082             :     .name          = "prewitt",
    1083             :     .description   = NULL_IF_CONFIG_SMALL("Apply prewitt operator."),
    1084             :     .priv_size     = sizeof(ConvolutionContext),
    1085             :     .priv_class    = &prewitt_class,
    1086             :     .init          = init,
    1087             :     .uninit        = uninit,
    1088             :     .query_formats = query_formats,
    1089             :     .inputs        = convolution_inputs,
    1090             :     .outputs       = convolution_outputs,
    1091             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
    1092             : };
    1093             : 
    1094             : #endif /* CONFIG_PREWITT_FILTER */
    1095             : 
    1096             : #if CONFIG_SOBEL_FILTER
    1097             : 
    1098             : static const AVOption sobel_options[] = {
    1099             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
    1100             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
    1101             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
    1102             :     { NULL }
    1103             : };
    1104             : 
    1105             : AVFILTER_DEFINE_CLASS(sobel);
    1106             : 
    1107             : AVFilter ff_vf_sobel = {
    1108             :     .name          = "sobel",
    1109             :     .description   = NULL_IF_CONFIG_SMALL("Apply sobel operator."),
    1110             :     .priv_size     = sizeof(ConvolutionContext),
    1111             :     .priv_class    = &sobel_class,
    1112             :     .init          = init,
    1113             :     .uninit        = uninit,
    1114             :     .query_formats = query_formats,
    1115             :     .inputs        = convolution_inputs,
    1116             :     .outputs       = convolution_outputs,
    1117             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
    1118             : };
    1119             : 
    1120             : #endif /* CONFIG_SOBEL_FILTER */
    1121             : 
    1122             : #if CONFIG_ROBERTS_FILTER
    1123             : 
    1124             : static const AVOption roberts_options[] = {
    1125             :     { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT,  {.i64=15}, 0, 15, FLAGS},
    1126             :     { "scale",  "set scale",            OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0,  65535, FLAGS},
    1127             :     { "delta",  "set delta",            OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
    1128             :     { NULL }
    1129             : };
    1130             : 
    1131             : AVFILTER_DEFINE_CLASS(roberts);
    1132             : 
    1133             : AVFilter ff_vf_roberts = {
    1134             :     .name          = "roberts",
    1135             :     .description   = NULL_IF_CONFIG_SMALL("Apply roberts cross operator."),
    1136             :     .priv_size     = sizeof(ConvolutionContext),
    1137             :     .priv_class    = &roberts_class,
    1138             :     .init          = init,
    1139             :     .uninit        = uninit,
    1140             :     .query_formats = query_formats,
    1141             :     .inputs        = convolution_inputs,
    1142             :     .outputs       = convolution_outputs,
    1143             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
    1144             : };
    1145             : 
    1146             : #endif /* CONFIG_ROBERTS_FILTER */

Generated by: LCOV version 1.13