LCOV - code coverage report
Current view: top level - libavfilter - vf_waveform.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 252 1475 17.1 %
Date: 2018-05-20 11:54:08 Functions: 13 94 13.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012-2016 Paul B Mahol
       3             :  * Copyright (c) 2013 Marton Balint
       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/avassert.h"
      23             : #include "libavutil/opt.h"
      24             : #include "libavutil/parseutils.h"
      25             : #include "libavutil/pixdesc.h"
      26             : #include "libavutil/xga_font_data.h"
      27             : #include "avfilter.h"
      28             : #include "formats.h"
      29             : #include "internal.h"
      30             : #include "video.h"
      31             : 
      32             : typedef struct ThreadData {
      33             :     AVFrame *in;
      34             :     AVFrame *out;
      35             :     int component;
      36             :     int offset_y;
      37             :     int offset_x;
      38             : } ThreadData;
      39             : 
      40             : enum FilterType {
      41             :     LOWPASS,
      42             :     FLAT,
      43             :     AFLAT,
      44             :     CHROMA,
      45             :     COLOR,
      46             :     ACOLOR,
      47             :     XFLAT,
      48             :     NB_FILTERS
      49             : };
      50             : 
      51             : enum DisplayType {
      52             :     OVERLAY,
      53             :     STACK,
      54             :     PARADE,
      55             :     NB_DISPLAYS
      56             : };
      57             : 
      58             : enum ScaleType {
      59             :     DIGITAL,
      60             :     MILLIVOLTS,
      61             :     IRE,
      62             :     NB_SCALES
      63             : };
      64             : 
      65             : typedef struct GraticuleLine {
      66             :     const char *name;
      67             :     uint16_t pos;
      68             : } GraticuleLine;
      69             : 
      70             : typedef struct GraticuleLines {
      71             :     struct GraticuleLine line[4];
      72             : } GraticuleLines;
      73             : 
      74             : typedef struct WaveformContext {
      75             :     const AVClass *class;
      76             :     int            mode;
      77             :     int            acomp;
      78             :     int            dcomp;
      79             :     int            ncomp;
      80             :     int            pcomp;
      81             :     uint8_t        bg_color[4];
      82             :     float          fintensity;
      83             :     int            intensity;
      84             :     int            mirror;
      85             :     int            display;
      86             :     int            envelope;
      87             :     int            graticule;
      88             :     float          opacity;
      89             :     float          bgopacity;
      90             :     int            estart[4];
      91             :     int            eend[4];
      92             :     int            *emax[4][4];
      93             :     int            *emin[4][4];
      94             :     int            *peak;
      95             :     int            filter;
      96             :     int            flags;
      97             :     int            bits;
      98             :     int            max;
      99             :     int            size;
     100             :     int            scale;
     101             :     uint8_t        grat_yuva_color[4];
     102             :     int            shift_w[4], shift_h[4];
     103             :     GraticuleLines *glines;
     104             :     int            nb_glines;
     105             : 
     106             :     int (*waveform_slice)(AVFilterContext *ctx, void *arg,
     107             :                           int jobnr, int nb_jobs);
     108             :     void (*graticulef)(struct WaveformContext *s, AVFrame *out);
     109             :     const AVPixFmtDescriptor *desc;
     110             :     const AVPixFmtDescriptor *odesc;
     111             : } WaveformContext;
     112             : 
     113             : #define OFFSET(x) offsetof(WaveformContext, x)
     114             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
     115             : 
     116             : static const AVOption waveform_options[] = {
     117             :     { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
     118             :     { "m",    "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
     119             :         { "row",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
     120             :         { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
     121             :     { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
     122             :     { "i",         "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
     123             :     { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
     124             :     { "r",      "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
     125             :     { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
     126             :     { "d",       "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
     127             :         { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY}, 0, 0, FLAGS, "display" },
     128             :         { "stack",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=STACK},   0, 0, FLAGS, "display" },
     129             :         { "parade",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=PARADE},  0, 0, FLAGS, "display" },
     130             :     { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
     131             :     { "c",          "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
     132             :     { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
     133             :     { "e",        "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
     134             :         { "none",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
     135             :         { "instant",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
     136             :         { "peak",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
     137             :         { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
     138             :     { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
     139             :     { "f",      "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
     140             :         { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, "filter" },
     141             :         { "flat"   , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT},    0, 0, FLAGS, "filter" },
     142             :         { "aflat"  , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT},   0, 0, FLAGS, "filter" },
     143             :         { "chroma",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA},  0, 0, FLAGS, "filter" },
     144             :         { "color",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR},   0, 0, FLAGS, "filter" },
     145             :         { "acolor",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACOLOR},  0, 0, FLAGS, "filter" },
     146             :         { "xflat",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=XFLAT},   0, 0, FLAGS, "filter" },
     147             :     { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule" },
     148             :     { "g",         "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule" },
     149             :         { "none",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "graticule" },
     150             :         { "green",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "graticule" },
     151             :         { "orange", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "graticule" },
     152             :     { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
     153             :     { "o",       "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
     154             :     { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
     155             :     { "fl",    "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
     156             :         { "numbers",  "draw numbers", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "flags" },
     157             :         { "dots",     "draw dots instead of lines", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
     158             :     { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
     159             :     { "s",     "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
     160             :         { "digital",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=DIGITAL},    0, 0, FLAGS, "scale" },
     161             :         { "millivolts", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MILLIVOLTS}, 0, 0, FLAGS, "scale" },
     162             :         { "ire",        NULL, 0, AV_OPT_TYPE_CONST, {.i64=IRE},        0, 0, FLAGS, "scale" },
     163             :     { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
     164             :     { "b",         "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
     165             :     { NULL }
     166             : };
     167             : 
     168             : AVFILTER_DEFINE_CLASS(waveform);
     169             : 
     170             : static const enum AVPixelFormat in_lowpass_pix_fmts[] = {
     171             :     AV_PIX_FMT_GBRP,     AV_PIX_FMT_GBRAP,
     172             :     AV_PIX_FMT_GBRP9,    AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
     173             :     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
     174             :     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
     175             :     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
     176             :     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
     177             :     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
     178             :     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
     179             :     AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
     180             :     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
     181             :     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
     182             :     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
     183             :     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
     184             :     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
     185             :     AV_PIX_FMT_NONE
     186             : };
     187             : 
     188             : static const enum AVPixelFormat in_color_pix_fmts[] = {
     189             :     AV_PIX_FMT_GBRP,     AV_PIX_FMT_GBRAP,
     190             :     AV_PIX_FMT_GBRP9,    AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
     191             :     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
     192             :     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
     193             :     AV_PIX_FMT_YUV411P,
     194             :     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
     195             :     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
     196             :     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
     197             :     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
     198             :     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
     199             :     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
     200             :     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
     201             :     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
     202             :     AV_PIX_FMT_NONE
     203             : };
     204             : 
     205             : static const enum AVPixelFormat in_flat_pix_fmts[] = {
     206             :     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
     207             :     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
     208             :     AV_PIX_FMT_YUV411P,
     209             :     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
     210             :     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
     211             :     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
     212             :     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
     213             :     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
     214             :     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
     215             :     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
     216             :     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
     217             :     AV_PIX_FMT_NONE
     218             : };
     219             : 
     220             : static const enum AVPixelFormat out_rgb8_lowpass_pix_fmts[] = {
     221             :     AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
     222             :     AV_PIX_FMT_NONE
     223             : };
     224             : 
     225             : static const enum AVPixelFormat out_rgb9_lowpass_pix_fmts[] = {
     226             :     AV_PIX_FMT_GBRP9,
     227             :     AV_PIX_FMT_NONE
     228             : };
     229             : 
     230             : static const enum AVPixelFormat out_rgb10_lowpass_pix_fmts[] = {
     231             :     AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
     232             :     AV_PIX_FMT_NONE
     233             : };
     234             : 
     235             : static const enum AVPixelFormat out_rgb12_lowpass_pix_fmts[] = {
     236             :     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
     237             :     AV_PIX_FMT_NONE
     238             : };
     239             : 
     240             : static const enum AVPixelFormat out_yuv8_lowpass_pix_fmts[] = {
     241             :     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P,
     242             :     AV_PIX_FMT_NONE
     243             : };
     244             : 
     245             : static const enum AVPixelFormat out_yuv9_lowpass_pix_fmts[] = {
     246             :     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9,
     247             :     AV_PIX_FMT_NONE
     248             : };
     249             : 
     250             : static const enum AVPixelFormat out_yuv10_lowpass_pix_fmts[] = {
     251             :     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
     252             :     AV_PIX_FMT_NONE
     253             : };
     254             : 
     255             : static const enum AVPixelFormat out_yuv12_lowpass_pix_fmts[] = {
     256             :     AV_PIX_FMT_YUV444P12,
     257             :     AV_PIX_FMT_NONE
     258             : };
     259             : 
     260             : static const enum AVPixelFormat out_gray8_lowpass_pix_fmts[] = {
     261             :     AV_PIX_FMT_GRAY8,
     262             :     AV_PIX_FMT_NONE
     263             : };
     264             : 
     265             : static const enum AVPixelFormat out_gray9_lowpass_pix_fmts[] = {
     266             :     AV_PIX_FMT_GRAY9,
     267             :     AV_PIX_FMT_NONE
     268             : };
     269             : 
     270             : static const enum AVPixelFormat out_gray10_lowpass_pix_fmts[] = {
     271             :     AV_PIX_FMT_GRAY10,
     272             :     AV_PIX_FMT_NONE
     273             : };
     274             : 
     275             : static const enum AVPixelFormat out_gray12_lowpass_pix_fmts[] = {
     276             :     AV_PIX_FMT_GRAY12,
     277             :     AV_PIX_FMT_NONE
     278             : };
     279             : 
     280             : static const enum AVPixelFormat flat_pix_fmts[] = {
     281             :     AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
     282             :     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
     283             :     AV_PIX_FMT_YUV444P12,
     284             :     AV_PIX_FMT_NONE
     285             : };
     286             : 
     287           8 : static int query_formats(AVFilterContext *ctx)
     288             : {
     289           8 :     WaveformContext *s = ctx->priv;
     290             :     const enum AVPixelFormat *out_pix_fmts;
     291             :     const enum AVPixelFormat *in_pix_fmts;
     292             :     const AVPixFmtDescriptor *desc;
     293             :     AVFilterFormats *avff;
     294             :     int depth, rgb, i, ret, ncomp;
     295             : 
     296          12 :     if (!ctx->inputs[0]->in_formats ||
     297           4 :         !ctx->inputs[0]->in_formats->nb_formats) {
     298           4 :         return AVERROR(EAGAIN);
     299             :     }
     300             : 
     301           4 :     switch (s->filter) {
     302           4 :     case LOWPASS: in_pix_fmts = in_lowpass_pix_fmts; break;
     303           0 :     case CHROMA:
     304             :     case XFLAT:
     305             :     case AFLAT:
     306           0 :     case FLAT:    in_pix_fmts = in_flat_pix_fmts;    break;
     307           0 :     case ACOLOR:
     308           0 :     case COLOR:   in_pix_fmts = in_color_pix_fmts;   break;
     309           0 :     default: return AVERROR_BUG;
     310             :     }
     311             : 
     312           4 :     if (!ctx->inputs[0]->out_formats) {
     313           4 :         if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->out_formats)) < 0)
     314           0 :             return ret;
     315             :     }
     316             : 
     317           4 :     avff = ctx->inputs[0]->in_formats;
     318           4 :     desc = av_pix_fmt_desc_get(avff->formats[0]);
     319           4 :     ncomp = desc->nb_components;
     320           4 :     rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
     321           4 :     depth = desc->comp[0].depth;
     322           4 :     for (i = 1; i < avff->nb_formats; i++) {
     323           0 :         desc = av_pix_fmt_desc_get(avff->formats[i]);
     324           0 :         if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
     325           0 :             depth != desc->comp[0].depth)
     326           0 :             return AVERROR(EAGAIN);
     327             :     }
     328             : 
     329           4 :     if (s->filter == LOWPASS && ncomp == 1 && depth == 8)
     330           0 :         out_pix_fmts = out_gray8_lowpass_pix_fmts;
     331           4 :     else if (s->filter == LOWPASS && ncomp == 1 && depth == 9)
     332           0 :         out_pix_fmts = out_gray9_lowpass_pix_fmts;
     333           4 :     else if (s->filter == LOWPASS && ncomp == 1 && depth == 10)
     334           0 :         out_pix_fmts = out_gray10_lowpass_pix_fmts;
     335           4 :     else if (s->filter == LOWPASS && ncomp == 1 && depth == 12)
     336           0 :         out_pix_fmts = out_gray12_lowpass_pix_fmts;
     337           4 :     else if (rgb && depth == 8 && ncomp > 2)
     338           0 :         out_pix_fmts = out_rgb8_lowpass_pix_fmts;
     339           4 :     else if (rgb && depth == 9 && ncomp > 2)
     340           0 :         out_pix_fmts = out_rgb9_lowpass_pix_fmts;
     341           4 :     else if (rgb && depth == 10 && ncomp > 2)
     342           0 :         out_pix_fmts = out_rgb10_lowpass_pix_fmts;
     343           4 :     else if (rgb && depth == 12 && ncomp > 2)
     344           0 :         out_pix_fmts = out_rgb12_lowpass_pix_fmts;
     345           4 :     else if (depth == 8 && ncomp > 2)
     346           4 :         out_pix_fmts = out_yuv8_lowpass_pix_fmts;
     347           0 :     else if (depth == 9 && ncomp > 2)
     348           0 :         out_pix_fmts = out_yuv9_lowpass_pix_fmts;
     349           0 :     else if (depth == 10 && ncomp > 2)
     350           0 :         out_pix_fmts = out_yuv10_lowpass_pix_fmts;
     351           0 :     else if (depth == 12 && ncomp > 2)
     352           0 :         out_pix_fmts = out_yuv12_lowpass_pix_fmts;
     353             :     else
     354           0 :         return AVERROR(EAGAIN);
     355           4 :     if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats)) < 0)
     356           0 :         return ret;
     357             : 
     358           4 :     return 0;
     359             : }
     360             : 
     361           0 : static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     362             : {
     363           0 :     const int dst_linesize = out->linesize[component] / 2;
     364           0 :     const int bg = s->bg_color[component] * (s->max / 256);
     365           0 :     const int limit = s->max - 1;
     366           0 :     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
     367           0 :     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
     368           0 :     const int start = s->estart[plane];
     369           0 :     const int end = s->eend[plane];
     370             :     uint16_t *dst;
     371             :     int x, y;
     372             : 
     373           0 :     if (s->mode) {
     374           0 :         for (x = offset; x < offset + dst_w; x++) {
     375           0 :             for (y = start; y < end; y++) {
     376           0 :                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
     377           0 :                 if (dst[0] != bg) {
     378           0 :                     dst[0] = limit;
     379           0 :                     break;
     380             :                 }
     381             :             }
     382           0 :             for (y = end - 1; y >= start; y--) {
     383           0 :                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
     384           0 :                 if (dst[0] != bg) {
     385           0 :                     dst[0] = limit;
     386           0 :                     break;
     387             :                 }
     388             :             }
     389             :         }
     390             :     } else {
     391           0 :         for (y = offset; y < offset + dst_h; y++) {
     392           0 :             dst = (uint16_t *)out->data[component] + y * dst_linesize;
     393           0 :             for (x = start; x < end; x++) {
     394           0 :                 if (dst[x] != bg) {
     395           0 :                     dst[x] = limit;
     396           0 :                     break;
     397             :                 }
     398             :             }
     399           0 :             for (x = end - 1; x >= start; x--) {
     400           0 :                 if (dst[x] != bg) {
     401           0 :                     dst[x] = limit;
     402           0 :                     break;
     403             :                 }
     404             :             }
     405             :         }
     406             :     }
     407           0 : }
     408             : 
     409          50 : static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     410             : {
     411          50 :     const int dst_linesize = out->linesize[component];
     412          50 :     const uint8_t bg = s->bg_color[component];
     413          50 :     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
     414          50 :     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
     415          50 :     const int start = s->estart[plane];
     416          50 :     const int end = s->eend[plane];
     417             :     uint8_t *dst;
     418             :     int x, y;
     419             : 
     420          50 :     if (s->mode) {
     421       17650 :         for (x = offset; x < offset + dst_w; x++) {
     422      375540 :             for (y = start; y < end; y++) {
     423      375540 :                 dst = out->data[component] + y * dst_linesize + x;
     424      375540 :                 if (dst[0] != bg) {
     425       17600 :                     dst[0] = 255;
     426       17600 :                     break;
     427             :                 }
     428             :             }
     429      385656 :             for (y = end - 1; y >= start; y--) {
     430      385656 :                 dst = out->data[component] + y * dst_linesize + x;
     431      385656 :                 if (dst[0] != bg) {
     432       17600 :                     dst[0] = 255;
     433       17600 :                     break;
     434             :                 }
     435             :             }
     436             :         }
     437             :     } else {
     438           0 :         for (y = offset; y < offset + dst_h; y++) {
     439           0 :             dst = out->data[component] + y * dst_linesize;
     440           0 :             for (x = start; x < end; x++) {
     441           0 :                 if (dst[x] != bg) {
     442           0 :                     dst[x] = 255;
     443           0 :                     break;
     444             :                 }
     445             :             }
     446           0 :             for (x = end - 1; x >= start; x--) {
     447           0 :                 if (dst[x] != bg) {
     448           0 :                     dst[x] = 255;
     449           0 :                     break;
     450             :                 }
     451             :             }
     452             :         }
     453             :     }
     454          50 : }
     455             : 
     456           0 : static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     457             : {
     458           0 :     const int dst_linesize = out->linesize[component] / 2;
     459           0 :     const int bg = s->bg_color[component] * (s->max / 256);
     460           0 :     const int limit = s->max - 1;
     461           0 :     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
     462           0 :     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
     463           0 :     const int start = s->estart[plane];
     464           0 :     const int end = s->eend[plane];
     465           0 :     int *emax = s->emax[plane][component];
     466           0 :     int *emin = s->emin[plane][component];
     467             :     uint16_t *dst;
     468             :     int x, y;
     469             : 
     470           0 :     if (s->mode) {
     471           0 :         for (x = offset; x < offset + dst_w; x++) {
     472           0 :             for (y = start; y < end && y < emin[x - offset]; y++) {
     473           0 :                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
     474           0 :                 if (dst[0] != bg) {
     475           0 :                     emin[x - offset] = y;
     476           0 :                     break;
     477             :                 }
     478             :             }
     479           0 :             for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
     480           0 :                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
     481           0 :                 if (dst[0] != bg) {
     482           0 :                     emax[x - offset] = y;
     483           0 :                     break;
     484             :                 }
     485             :             }
     486             :         }
     487             : 
     488           0 :         if (s->envelope == 3)
     489           0 :             envelope_instant16(s, out, plane, component, offset);
     490             : 
     491           0 :         for (x = offset; x < offset + dst_w; x++) {
     492           0 :             dst = (uint16_t *)out->data[component] + emin[x - offset] * dst_linesize + x;
     493           0 :             dst[0] = limit;
     494           0 :             dst = (uint16_t *)out->data[component] + emax[x - offset] * dst_linesize + x;
     495           0 :             dst[0] = limit;
     496             :         }
     497             :     } else {
     498           0 :         for (y = offset; y < offset + dst_h; y++) {
     499           0 :             dst = (uint16_t *)out->data[component] + y * dst_linesize;
     500           0 :             for (x = start; x < end && x < emin[y - offset]; x++) {
     501           0 :                 if (dst[x] != bg) {
     502           0 :                     emin[y - offset] = x;
     503           0 :                     break;
     504             :                 }
     505             :             }
     506           0 :             for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
     507           0 :                 if (dst[x] != bg) {
     508           0 :                     emax[y - offset] = x;
     509           0 :                     break;
     510             :                 }
     511             :             }
     512             :         }
     513             : 
     514           0 :         if (s->envelope == 3)
     515           0 :             envelope_instant16(s, out, plane, component, offset);
     516             : 
     517           0 :         for (y = offset; y < offset + dst_h; y++) {
     518           0 :             dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y - offset];
     519           0 :             dst[0] = limit;
     520           0 :             dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y - offset];
     521           0 :             dst[0] = limit;
     522             :         }
     523             :     }
     524           0 : }
     525             : 
     526          50 : static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     527             : {
     528          50 :     const int dst_linesize = out->linesize[component];
     529          50 :     const int bg = s->bg_color[component];
     530          50 :     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
     531          50 :     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
     532          50 :     const int start = s->estart[plane];
     533          50 :     const int end = s->eend[plane];
     534          50 :     int *emax = s->emax[plane][component];
     535          50 :     int *emin = s->emin[plane][component];
     536             :     uint8_t *dst;
     537             :     int x, y;
     538             : 
     539          50 :     if (s->mode) {
     540       17650 :         for (x = offset; x < offset + dst_w; x++) {
     541      152559 :             for (y = start; y < end && y < emin[x - offset]; y++) {
     542      136288 :                 dst = out->data[component] + y * dst_linesize + x;
     543      136288 :                 if (dst[0] != bg) {
     544        1329 :                     emin[x - offset] = y;
     545        1329 :                     break;
     546             :                 }
     547             :             }
     548      159188 :             for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
     549      144269 :                 dst = out->data[component] + y * dst_linesize + x;
     550      144269 :                 if (dst[0] != bg) {
     551        2681 :                     emax[x - offset] = y;
     552        2681 :                     break;
     553             :                 }
     554             :             }
     555             :         }
     556             : 
     557          50 :         if (s->envelope == 3)
     558          50 :             envelope_instant(s, out, plane, component, offset);
     559             : 
     560       17650 :         for (x = offset; x < offset + dst_w; x++) {
     561       17600 :             dst = out->data[component] + emin[x - offset] * dst_linesize + x;
     562       17600 :             dst[0] = 255;
     563       17600 :             dst = out->data[component] + emax[x - offset] * dst_linesize + x;
     564       17600 :             dst[0] = 255;
     565             :         }
     566             :     } else {
     567           0 :         for (y = offset; y < offset + dst_h; y++) {
     568           0 :             dst = out->data[component] + y * dst_linesize;
     569           0 :             for (x = start; x < end && x < emin[y - offset]; x++) {
     570           0 :                 if (dst[x] != bg) {
     571           0 :                     emin[y - offset] = x;
     572           0 :                     break;
     573             :                 }
     574             :             }
     575           0 :             for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
     576           0 :                 if (dst[x] != bg) {
     577           0 :                     emax[y - offset] = x;
     578           0 :                     break;
     579             :                 }
     580             :             }
     581             :         }
     582             : 
     583           0 :         if (s->envelope == 3)
     584           0 :             envelope_instant(s, out, plane, component, offset);
     585             : 
     586           0 :         for (y = offset; y < offset + dst_h; y++) {
     587           0 :             dst = out->data[component] + y * dst_linesize + emin[y - offset];
     588           0 :             dst[0] = 255;
     589           0 :             dst = out->data[component] + y * dst_linesize + emax[y - offset];
     590           0 :             dst[0] = 255;
     591             :         }
     592             :     }
     593          50 : }
     594             : 
     595           0 : static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     596             : {
     597           0 :     if (s->envelope == 0) {
     598           0 :         return;
     599           0 :     } else if (s->envelope == 1) {
     600           0 :         envelope_instant16(s, out, plane, component, offset);
     601             :     } else {
     602           0 :         envelope_peak16(s, out, plane, component, offset);
     603             :     }
     604             : }
     605             : 
     606         250 : static void envelope(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
     607             : {
     608         250 :     if (s->envelope == 0) {
     609         200 :         return;
     610          50 :     } else if (s->envelope == 1) {
     611           0 :         envelope_instant(s, out, plane, component, offset);
     612             :     } else {
     613          50 :         envelope_peak(s, out, plane, component, offset);
     614             :     }
     615             : }
     616             : 
     617           0 : static void update16(uint16_t *target, int max, int intensity, int limit)
     618             : {
     619           0 :     if (*target <= max)
     620           0 :         *target += intensity;
     621             :     else
     622           0 :         *target = limit;
     623           0 : }
     624             : 
     625    17740800 : static void update(uint8_t *target, int max, int intensity)
     626             : {
     627    17740800 :     if (*target <= max)
     628    17740797 :         *target += intensity;
     629             :     else
     630           3 :         *target = 255;
     631    17740800 : }
     632             : 
     633           0 : static void update_cr(uint8_t *target, int unused, int intensity)
     634             : {
     635           0 :     if (*target - intensity > 0)
     636           0 :         *target -= intensity;
     637             :     else
     638           0 :         *target = 0;
     639           0 : }
     640             : 
     641           0 : static void update16_cr(uint16_t *target, int unused, int intensity, int limit)
     642             : {
     643           0 :     if (*target - intensity > 0)
     644           0 :         *target -= intensity;
     645             :     else
     646           0 :         *target = 0;
     647           0 : }
     648             : 
     649           0 : static av_always_inline void lowpass16(WaveformContext *s,
     650             :                                        AVFrame *in, AVFrame *out,
     651             :                                        int component, int intensity,
     652             :                                        int offset_y, int offset_x,
     653             :                                        int column, int mirror,
     654             :                                        int jobnr, int nb_jobs)
     655             : {
     656           0 :     const int plane = s->desc->comp[component].plane;
     657           0 :     const int shift_w = s->shift_w[component];
     658           0 :     const int shift_h = s->shift_h[component];
     659           0 :     const int src_linesize = in->linesize[plane] / 2;
     660           0 :     const int dst_linesize = out->linesize[plane] / 2;
     661           0 :     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
     662           0 :     const int limit = s->max - 1;
     663           0 :     const int max = limit - intensity;
     664           0 :     const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
     665           0 :     const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
     666           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
     667           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
     668           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
     669           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
     670           0 :     const int step = column ? 1 << shift_w : 1 << shift_h;
     671           0 :     const uint16_t *src_data = (const uint16_t *)in->data[plane] + sliceh_start * src_linesize;
     672           0 :     uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
     673           0 :     uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
     674           0 :     uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
     675             :     const uint16_t *p;
     676             :     int y;
     677             : 
     678           0 :     if (!column && mirror)
     679           0 :         dst_data += s->size;
     680             : 
     681           0 :     for (y = sliceh_start; y < sliceh_end; y++) {
     682           0 :         const uint16_t *src_data_end = src_data + slicew_end;
     683           0 :         uint16_t *dst = dst_line + slicew_start * step;
     684             : 
     685           0 :         for (p = src_data + slicew_start; p < src_data_end; p++) {
     686             :             uint16_t *target;
     687           0 :             int i = 0, v = FFMIN(*p, limit);
     688             : 
     689           0 :             if (column) {
     690             :                 do {
     691           0 :                     target = dst++ + dst_signed_linesize * v;
     692           0 :                     update16(target, max, intensity, limit);
     693           0 :                 } while (++i < step);
     694             :             } else {
     695           0 :                 uint16_t *row = dst_data;
     696             :                 do {
     697           0 :                     if (mirror)
     698           0 :                         target = row - v - 1;
     699             :                     else
     700           0 :                         target = row + v;
     701           0 :                     update16(target, max, intensity, limit);
     702           0 :                     row += dst_linesize;
     703           0 :                 } while (++i < step);
     704             :             }
     705             :         }
     706           0 :         src_data += src_linesize;
     707           0 :         dst_data += dst_linesize * step;
     708             :     }
     709           0 : }
     710             : 
     711             : #define LOWPASS16_FUNC(name, column, mirror)        \
     712             : static int lowpass16_##name(AVFilterContext *ctx,   \
     713             :                              void *arg, int jobnr,  \
     714             :                              int nb_jobs)           \
     715             : {                                                   \
     716             :     WaveformContext *s = ctx->priv;                 \
     717             :     ThreadData *td = arg;                           \
     718             :     AVFrame *in = td->in;                           \
     719             :     AVFrame *out = td->out;                         \
     720             :     int component = td->component;                  \
     721             :     int offset_y = td->offset_y;                    \
     722             :     int offset_x = td->offset_x;                    \
     723             :                                                     \
     724             :     lowpass16(s, in, out, component, s->intensity,  \
     725             :               offset_y, offset_x, column, mirror,   \
     726             :               jobnr, nb_jobs);                      \
     727             :                                                     \
     728             :     return 0;                                       \
     729             : }
     730             : 
     731           0 : LOWPASS16_FUNC(column_mirror, 1, 1)
     732           0 : LOWPASS16_FUNC(column,        1, 0)
     733           0 : LOWPASS16_FUNC(row_mirror,    0, 1)
     734           0 : LOWPASS16_FUNC(row,           0, 0)
     735             : 
     736        2250 : static av_always_inline void lowpass(WaveformContext *s,
     737             :                                      AVFrame *in, AVFrame *out,
     738             :                                      int component, int intensity,
     739             :                                      int offset_y, int offset_x,
     740             :                                      int column, int mirror,
     741             :                                      int jobnr, int nb_jobs)
     742             : {
     743        2250 :     const int plane = s->desc->comp[component].plane;
     744        2250 :     const int shift_w = s->shift_w[component];
     745        2250 :     const int shift_h = s->shift_h[component];
     746        2250 :     const int src_linesize = in->linesize[plane];
     747        2250 :     const int dst_linesize = out->linesize[plane];
     748        2250 :     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
     749        2250 :     const int max = 255 - intensity;
     750        2250 :     const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
     751        2250 :     const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
     752        2250 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
     753        2250 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
     754        2250 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
     755        2250 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
     756        2250 :     const int step = column ? 1 << shift_w : 1 << shift_h;
     757        2250 :     const uint8_t *src_data = in->data[plane] + sliceh_start * src_linesize;
     758        2250 :     uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
     759        2250 :     uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
     760        2250 :     uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
     761             :     const uint8_t *p;
     762             :     int y;
     763             : 
     764        2250 :     if (!column && mirror)
     765         450 :         dst_data += s->size;
     766             : 
     767      405450 :     for (y = sliceh_start; y < sliceh_end; y++) {
     768      403200 :         const uint8_t *src_data_end = src_data + slicew_end;
     769      403200 :         uint8_t *dst = dst_line + slicew_start * step;
     770             : 
     771    18144000 :         for (p = src_data + slicew_start; p < src_data_end; p++) {
     772             :             uint8_t *target;
     773    17740800 :             if (column) {
     774    12672000 :                 target = dst + dst_signed_linesize * *p;
     775    12672000 :                 dst += step;
     776    12672000 :                 update(target, max, intensity);
     777             :             } else {
     778     5068800 :                 uint8_t *row = dst_data;
     779     5068800 :                 if (mirror)
     780     5068800 :                     target = row - *p - 1;
     781             :                 else
     782           0 :                     target = row + *p;
     783     5068800 :                 update(target, max, intensity);
     784     5068800 :                 row += dst_linesize;
     785             :             }
     786             :         }
     787      403200 :         src_data += src_linesize;
     788      403200 :         dst_data += dst_linesize * step;
     789             :     }
     790             : 
     791        3150 :     if (column && step > 1) {
     792         900 :         const int dst_h = 256;
     793             :         uint8_t *dst;
     794             :         int x, z;
     795             : 
     796         900 :         dst = out->data[plane] + offset_y * dst_linesize + offset_x;
     797      231300 :         for (y = 0; y < dst_h; y++) {
     798     4736000 :             for (x = slicew_start * step; x < slicew_end * step; x+=step) {
     799     9011200 :                 for (z = 1; z < step; z++) {
     800     4505600 :                     dst[x + z] = dst[x];
     801             :                 }
     802             :             }
     803      230400 :             dst += dst_linesize;
     804             :         }
     805        1350 :     } else if (step > 1) {
     806           0 :         const int dst_w = 256;
     807             :         uint8_t *dst;
     808             :         int z;
     809             : 
     810           0 :         dst = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
     811           0 :         for (y = sliceh_start * step; y < sliceh_end * step; y+=step) {
     812           0 :             for (z = 1; z < step; z++)
     813           0 :                 memcpy(dst + dst_linesize * z, dst, dst_w);
     814           0 :             dst += dst_linesize * step;
     815             :         }
     816             :     }
     817        2250 : }
     818             : 
     819             : #define LOWPASS_FUNC(name, column, mirror)        \
     820             : static int lowpass_##name(AVFilterContext *ctx,   \
     821             :                           void *arg, int jobnr,   \
     822             :                           int nb_jobs)            \
     823             : {                                                 \
     824             :     WaveformContext *s = ctx->priv;               \
     825             :     ThreadData *td = arg;                         \
     826             :     AVFrame *in = td->in;                         \
     827             :     AVFrame *out = td->out;                       \
     828             :     int component = td->component;                \
     829             :     int offset_y = td->offset_y;                  \
     830             :     int offset_x = td->offset_x;                  \
     831             :                                                   \
     832             :     lowpass(s, in, out, component, s->intensity,  \
     833             :             offset_y, offset_x, column, mirror,   \
     834             :             jobnr, nb_jobs);                      \
     835             :                                                   \
     836             :     return 0;                                     \
     837             : }
     838             : 
     839        1800 : LOWPASS_FUNC(column_mirror, 1, 1)
     840           0 : LOWPASS_FUNC(column,        1, 0)
     841         450 : LOWPASS_FUNC(row_mirror,    0, 1)
     842           0 : LOWPASS_FUNC(row,           0, 0)
     843             : 
     844           0 : static av_always_inline void flat16(WaveformContext *s,
     845             :                                     AVFrame *in, AVFrame *out,
     846             :                                     int component, int intensity,
     847             :                                     int offset_y, int offset_x,
     848             :                                     int column, int mirror,
     849             :                                     int jobnr, int nb_jobs)
     850             : {
     851           0 :     const int plane = s->desc->comp[component].plane;
     852           0 :     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
     853           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
     854           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
     855           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
     856           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
     857           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
     858           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
     859           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
     860           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
     861           0 :     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
     862           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
     863           0 :     const int limit = s->max - 1;
     864           0 :     const int max = limit - intensity;
     865           0 :     const int mid = s->max / 2;
     866           0 :     const int src_h = in->height;
     867           0 :     const int src_w = in->width;
     868           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
     869           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
     870           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
     871           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
     872             :     int x, y;
     873             : 
     874           0 :     if (column) {
     875           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
     876           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
     877             : 
     878           0 :         for (x = slicew_start; x < slicew_end; x++) {
     879           0 :             const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];
     880           0 :             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
     881           0 :             const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
     882           0 :             uint16_t *d0_data = (uint16_t *)(out->data[plane]) + offset_y * d0_linesize + offset_x;
     883           0 :             uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + offset_y * d1_linesize + offset_x;
     884           0 :             uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
     885           0 :             uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
     886           0 :             uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
     887           0 :             uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
     888             : 
     889           0 :             for (y = 0; y < src_h; y++) {
     890           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
     891           0 :                 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
     892             :                 uint16_t *target;
     893             : 
     894           0 :                 target = d0 + x + d0_signed_linesize * c0;
     895           0 :                 update16(target, max, intensity, limit);
     896           0 :                 target = d1 + x + d1_signed_linesize * (c0 - c1);
     897           0 :                 update16(target, max, intensity, limit);
     898           0 :                 target = d1 + x + d1_signed_linesize * (c0 + c1);
     899           0 :                 update16(target, max, intensity, limit);
     900             : 
     901           0 :                 if (!c0_shift_h || (y & c0_shift_h))
     902           0 :                     c0_data += c0_linesize;
     903           0 :                 if (!c1_shift_h || (y & c1_shift_h))
     904           0 :                     c1_data += c1_linesize;
     905           0 :                 if (!c2_shift_h || (y & c2_shift_h))
     906           0 :                     c2_data += c2_linesize;
     907           0 :                 d0_data += d0_linesize;
     908           0 :                 d1_data += d1_linesize;
     909             :             }
     910             :         }
     911             :     } else {
     912           0 :         const uint16_t *c0_data = (uint16_t *)(in->data[plane]) +                  (sliceh_start >> c0_shift_h) * c0_linesize;
     913           0 :         const uint16_t *c1_data = (uint16_t *)(in->data[(plane + 1) % s->ncomp]) + (sliceh_start >> c1_shift_h) * c1_linesize;
     914           0 :         const uint16_t *c2_data = (uint16_t *)(in->data[(plane + 2) % s->ncomp]) + (sliceh_start >> c2_shift_h) * c2_linesize;
     915           0 :         uint16_t *d0_data = (uint16_t *)(out->data[plane]) + (offset_y + sliceh_start) * d0_linesize + offset_x;
     916           0 :         uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + (offset_y + sliceh_start) * d1_linesize + offset_x;
     917             : 
     918           0 :         if (mirror) {
     919           0 :             d0_data += s->size - 1;
     920           0 :             d1_data += s->size - 1;
     921             :         }
     922             : 
     923           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
     924           0 :             for (x = 0; x < src_w; x++) {
     925           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
     926           0 :                 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
     927             :                 uint16_t *target;
     928             : 
     929           0 :                 if (mirror) {
     930           0 :                     target = d0_data - c0;
     931           0 :                     update16(target, max, intensity, limit);
     932           0 :                     target = d1_data - (c0 - c1);
     933           0 :                     update16(target, max, intensity, limit);
     934           0 :                     target = d1_data - (c0 + c1);
     935           0 :                     update16(target, max, intensity, limit);
     936             :                 } else {
     937           0 :                     target = d0_data + c0;
     938           0 :                     update16(target, max, intensity, limit);
     939           0 :                     target = d1_data + (c0 - c1);
     940           0 :                     update16(target, max, intensity, limit);
     941           0 :                     target = d1_data + (c0 + c1);
     942           0 :                     update16(target, max, intensity, limit);
     943             :                 }
     944             :             }
     945             : 
     946           0 :             if (!c0_shift_h || (y & c0_shift_h))
     947           0 :                 c0_data += c0_linesize;
     948           0 :             if (!c1_shift_h || (y & c1_shift_h))
     949           0 :                 c1_data += c1_linesize;
     950           0 :             if (!c2_shift_h || (y & c2_shift_h))
     951           0 :                 c2_data += c2_linesize;
     952           0 :             d0_data += d0_linesize;
     953           0 :             d1_data += d1_linesize;
     954             :         }
     955             :     }
     956           0 : }
     957             : 
     958             : #define FLAT16_FUNC(name, column, mirror)        \
     959             : static int flat16_##name(AVFilterContext *ctx,   \
     960             :                          void *arg, int jobnr,   \
     961             :                          int nb_jobs)            \
     962             : {                                                \
     963             :     WaveformContext *s = ctx->priv;              \
     964             :     ThreadData *td = arg;                        \
     965             :     AVFrame *in = td->in;                        \
     966             :     AVFrame *out = td->out;                      \
     967             :     int component = td->component;               \
     968             :     int offset_y = td->offset_y;                 \
     969             :     int offset_x = td->offset_x;                 \
     970             :                                                  \
     971             :     flat16(s, in, out, component, s->intensity,  \
     972             :            offset_y, offset_x, column, mirror,   \
     973             :            jobnr, nb_jobs);                      \
     974             :                                                  \
     975             :     return 0;                                    \
     976             : }
     977             : 
     978           0 : FLAT16_FUNC(column_mirror, 1, 1)
     979           0 : FLAT16_FUNC(column,        1, 0)
     980           0 : FLAT16_FUNC(row_mirror,    0, 1)
     981           0 : FLAT16_FUNC(row,           0, 0)
     982             : 
     983           0 : static av_always_inline void flat(WaveformContext *s,
     984             :                                   AVFrame *in, AVFrame *out,
     985             :                                   int component, int intensity,
     986             :                                   int offset_y, int offset_x,
     987             :                                   int column, int mirror,
     988             :                                   int jobnr, int nb_jobs)
     989             : {
     990           0 :     const int plane = s->desc->comp[component].plane;
     991           0 :     const int c0_linesize = in->linesize[ plane + 0 ];
     992           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
     993           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
     994           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
     995           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
     996           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
     997           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
     998           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
     999           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1000           0 :     const int d0_linesize = out->linesize[ plane + 0 ];
    1001           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
    1002           0 :     const int max = 255 - intensity;
    1003           0 :     const int src_h = in->height;
    1004           0 :     const int src_w = in->width;
    1005           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1006           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1007           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1008           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1009             :     int x, y;
    1010             : 
    1011           0 :     if (column) {
    1012           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
    1013           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
    1014             : 
    1015           0 :         for (x = slicew_start; x < slicew_end; x++) {
    1016           0 :             const uint8_t *c0_data = in->data[plane + 0];
    1017           0 :             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
    1018           0 :             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
    1019           0 :             uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
    1020           0 :             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
    1021           0 :             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
    1022           0 :             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
    1023           0 :             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
    1024           0 :             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
    1025             : 
    1026           0 :             for (y = 0; y < src_h; y++) {
    1027           0 :                 const int c0 = c0_data[x >> c0_shift_w] + 256;
    1028           0 :                 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
    1029             :                 uint8_t *target;
    1030             : 
    1031           0 :                 target = d0 + x + d0_signed_linesize * c0;
    1032           0 :                 update(target, max, intensity);
    1033           0 :                 target = d1 + x + d1_signed_linesize * (c0 - c1);
    1034           0 :                 update(target, max, intensity);
    1035           0 :                 target = d1 + x + d1_signed_linesize * (c0 + c1);
    1036           0 :                 update(target, max, intensity);
    1037             : 
    1038           0 :                 if (!c0_shift_h || (y & c0_shift_h))
    1039           0 :                     c0_data += c0_linesize;
    1040           0 :                 if (!c1_shift_h || (y & c1_shift_h))
    1041           0 :                     c1_data += c1_linesize;
    1042           0 :                 if (!c2_shift_h || (y & c2_shift_h))
    1043           0 :                     c2_data += c2_linesize;
    1044           0 :                 d0_data += d0_linesize;
    1045           0 :                 d1_data += d1_linesize;
    1046             :             }
    1047             :         }
    1048             :     } else {
    1049           0 :         const uint8_t *c0_data = in->data[plane] +                  (sliceh_start >> c0_shift_h) * c0_linesize;
    1050           0 :         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1051           0 :         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
    1052           0 :         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
    1053           0 :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
    1054             : 
    1055           0 :         if (mirror) {
    1056           0 :             d0_data += s->size - 1;
    1057           0 :             d1_data += s->size - 1;
    1058             :         }
    1059             : 
    1060           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1061           0 :             for (x = 0; x < src_w; x++) {
    1062           0 :                 const int c0 = c0_data[x >> c0_shift_w] + 256;
    1063           0 :                 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
    1064             :                 uint8_t *target;
    1065             : 
    1066           0 :                 if (mirror) {
    1067           0 :                     target = d0_data - c0;
    1068           0 :                     update(target, max, intensity);
    1069           0 :                     target = d1_data - (c0 - c1);
    1070           0 :                     update(target, max, intensity);
    1071           0 :                     target = d1_data - (c0 + c1);
    1072           0 :                     update(target, max, intensity);
    1073             :                 } else {
    1074           0 :                     target = d0_data + c0;
    1075           0 :                     update(target, max, intensity);
    1076           0 :                     target = d1_data + (c0 - c1);
    1077           0 :                     update(target, max, intensity);
    1078           0 :                     target = d1_data + (c0 + c1);
    1079           0 :                     update(target, max, intensity);
    1080             :                 }
    1081             :             }
    1082             : 
    1083           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1084           0 :                 c0_data += c0_linesize;
    1085           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1086           0 :                 c1_data += c1_linesize;
    1087           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1088           0 :                 c2_data += c2_linesize;
    1089           0 :             d0_data += d0_linesize;
    1090           0 :             d1_data += d1_linesize;
    1091             :         }
    1092             :     }
    1093           0 : }
    1094             : 
    1095             : #define FLAT_FUNC(name, column, mirror)        \
    1096             : static int flat_##name(AVFilterContext *ctx,   \
    1097             :                        void *arg, int jobnr,   \
    1098             :                        int nb_jobs)            \
    1099             : {                                              \
    1100             :     WaveformContext *s = ctx->priv;            \
    1101             :     ThreadData *td = arg;                      \
    1102             :     AVFrame *in = td->in;                      \
    1103             :     AVFrame *out = td->out;                    \
    1104             :     int component = td->component;             \
    1105             :     int offset_y = td->offset_y;               \
    1106             :     int offset_x = td->offset_x;               \
    1107             :                                                \
    1108             :     flat(s, in, out, component, s->intensity,  \
    1109             :          offset_y, offset_x, column, mirror,   \
    1110             :          jobnr, nb_jobs);                      \
    1111             :                                                \
    1112             :     return 0;                                  \
    1113             : }
    1114             : 
    1115           0 : FLAT_FUNC(column_mirror, 1, 1)
    1116           0 : FLAT_FUNC(column,        1, 0)
    1117           0 : FLAT_FUNC(row_mirror,    0, 1)
    1118           0 : FLAT_FUNC(row,           0, 0)
    1119             : 
    1120             : #define AFLAT16(name, update_cr, column, mirror)                                                                   \
    1121             : static int name(AVFilterContext *ctx,                                                                              \
    1122             :                 void *arg, int jobnr,                                                                              \
    1123             :                 int nb_jobs)                                                                                       \
    1124             : {                                                                                                                  \
    1125             :     WaveformContext *s = ctx->priv;                                                                                \
    1126             :     ThreadData *td = arg;                                                                                          \
    1127             :     AVFrame *in = td->in;                                                                                          \
    1128             :     AVFrame *out = td->out;                                                                                        \
    1129             :     int component = td->component;                                                                                 \
    1130             :     int offset_y = td->offset_y;                                                                                   \
    1131             :     int offset_x = td->offset_x;                                                                                   \
    1132             :     const int intensity = s->intensity;                                                                            \
    1133             :     const int plane = s->desc->comp[component].plane;                                                              \
    1134             :     const int c0_linesize = in->linesize[ plane + 0 ] / 2;                                                         \
    1135             :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;                                              \
    1136             :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;                                              \
    1137             :     const int c0_shift_w = s->shift_w[ component + 0 ];                                                            \
    1138             :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];                                                 \
    1139             :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];                                                 \
    1140             :     const int c0_shift_h = s->shift_h[ component + 0 ];                                                            \
    1141             :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];                                                 \
    1142             :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];                                                 \
    1143             :     const int d0_linesize = out->linesize[ plane + 0 ] / 2;                                                        \
    1144             :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;                                             \
    1145             :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;                                             \
    1146             :     const int limit = s->max - 1;                                                                                  \
    1147             :     const int max = limit - intensity;                                                                             \
    1148             :     const int mid = s->max / 2;                                                                                    \
    1149             :     const int src_h = in->height;                                                                                  \
    1150             :     const int src_w = in->width;                                                                                   \
    1151             :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;                                              \
    1152             :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;                                        \
    1153             :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;                                               \
    1154             :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;                                         \
    1155             :     int x, y;                                                                                                      \
    1156             :                                                                                                                    \
    1157             :     if (column) {                                                                                                  \
    1158             :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);                                       \
    1159             :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);                                       \
    1160             :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);                                       \
    1161             :                                                                                                                    \
    1162             :         for (x = slicew_start; x < slicew_end; x++) {                                                              \
    1163             :             const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];                                             \
    1164             :             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];                                \
    1165             :             const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];                                \
    1166             :             uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;                  \
    1167             :             uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
    1168             :             uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
    1169             :             uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);                               \
    1170             :             uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);                                             \
    1171             :             uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);                               \
    1172             :             uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);                                             \
    1173             :             uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);                               \
    1174             :             uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);                                             \
    1175             :                                                                                                                    \
    1176             :             for (y = 0; y < src_h; y++) {                                                                          \
    1177             :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid;                                       \
    1178             :                 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid;                                       \
    1179             :                 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid;                                       \
    1180             :                 uint16_t *target;                                                                                  \
    1181             :                                                                                                                    \
    1182             :                 target = d0 + x + d0_signed_linesize * c0;                                                         \
    1183             :                 update16(target, max, intensity, limit);                                                           \
    1184             :                                                                                                                    \
    1185             :                 target = d1 + x + d1_signed_linesize * (c0 + c1);                                                  \
    1186             :                 update16(target, max, intensity, limit);                                                           \
    1187             :                                                                                                                    \
    1188             :                 target = d2 + x + d2_signed_linesize * (c0 + c2);                                                  \
    1189             :                 update_cr(target, max, intensity, limit);                                                          \
    1190             :                                                                                                                    \
    1191             :                 if (!c0_shift_h || (y & c0_shift_h))                                                               \
    1192             :                     c0_data += c0_linesize;                                                                        \
    1193             :                 if (!c1_shift_h || (y & c1_shift_h))                                                               \
    1194             :                     c1_data += c1_linesize;                                                                        \
    1195             :                 if (!c2_shift_h || (y & c2_shift_h))                                                               \
    1196             :                     c2_data += c2_linesize;                                                                        \
    1197             :                 d0_data += d0_linesize;                                                                            \
    1198             :                 d1_data += d1_linesize;                                                                            \
    1199             :                 d2_data += d2_linesize;                                                                            \
    1200             :             }                                                                                                      \
    1201             :         }                                                                                                          \
    1202             :     } else {                                                                                                       \
    1203             :         const uint16_t *c0_data = (uint16_t *)in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;        \
    1204             :         const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
    1205             :         const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
    1206             :         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;                      \
    1207             :         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;     \
    1208             :         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;     \
    1209             :                                                                                                                    \
    1210             :         if (mirror) {                                                                                              \
    1211             :             d0_data += s->size - 1;                                                                                \
    1212             :             d1_data += s->size - 1;                                                                                \
    1213             :             d2_data += s->size - 1;                                                                                \
    1214             :         }                                                                                                          \
    1215             :                                                                                                                    \
    1216             :         for (y = sliceh_start; y < sliceh_end; y++) {                                                              \
    1217             :             for (x = 0; x < src_w; x++) {                                                                          \
    1218             :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid;                                       \
    1219             :                 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid;                                       \
    1220             :                 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid;                                       \
    1221             :                 uint16_t *target;                                                                                  \
    1222             :                                                                                                                    \
    1223             :                 if (mirror) {                                                                                      \
    1224             :                     target = d0_data - c0;                                                                         \
    1225             :                     update16(target, max, intensity, limit);                                                       \
    1226             :                     target = d1_data - (c0 + c1);                                                                  \
    1227             :                     update16(target, max, intensity, limit);                                                       \
    1228             :                     target = d2_data - (c0 + c2);                                                                  \
    1229             :                     update_cr(target, max, intensity, limit);                                                      \
    1230             :                 } else {                                                                                           \
    1231             :                     target = d0_data + c0;                                                                         \
    1232             :                     update16(target, max, intensity, limit);                                                       \
    1233             :                     target = d1_data + (c0 + c1);                                                                  \
    1234             :                     update16(target, max, intensity, limit);                                                       \
    1235             :                     target = d2_data + (c0 + c2);                                                                  \
    1236             :                     update_cr(target, max, intensity, limit);                                                      \
    1237             :                 }                                                                                                  \
    1238             :             }                                                                                                      \
    1239             :                                                                                                                    \
    1240             :             if (!c0_shift_h || (y & c0_shift_h))                                                                   \
    1241             :                 c0_data += c0_linesize;                                                                            \
    1242             :             if (!c1_shift_h || (y & c1_shift_h))                                                                   \
    1243             :                 c1_data += c1_linesize;                                                                            \
    1244             :             if (!c2_shift_h || (y & c2_shift_h))                                                                   \
    1245             :                 c2_data += c2_linesize;                                                                            \
    1246             :             d0_data += d0_linesize;                                                                                \
    1247             :             d1_data += d1_linesize;                                                                                \
    1248             :             d2_data += d2_linesize;                                                                                \
    1249             :         }                                                                                                          \
    1250             :     }                                                                                                              \
    1251             :     return 0;                                                                                                      \
    1252             : }
    1253             : 
    1254             : #define AFLAT(name, update_cr, column, mirror)                                                        \
    1255             : static int name(AVFilterContext *ctx,                                                                 \
    1256             :                 void *arg, int jobnr,                                                                 \
    1257             :                 int nb_jobs)                                                                          \
    1258             : {                                                                                                     \
    1259             :     WaveformContext *s = ctx->priv;                                                                   \
    1260             :     ThreadData *td = arg;                                                                             \
    1261             :     AVFrame *in = td->in;                                                                             \
    1262             :     AVFrame *out = td->out;                                                                           \
    1263             :     int component = td->component;                                                                    \
    1264             :     int offset_y = td->offset_y;                                                                      \
    1265             :     int offset_x = td->offset_x;                                                                      \
    1266             :     const int src_h = in->height;                                                                     \
    1267             :     const int src_w = in->width;                                                                      \
    1268             :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;                                 \
    1269             :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;                           \
    1270             :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;                                  \
    1271             :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;                            \
    1272             :     const int intensity = s->intensity;                                                               \
    1273             :     const int plane = s->desc->comp[component].plane;                                                 \
    1274             :     const int c0_linesize = in->linesize[ plane + 0 ];                                                \
    1275             :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];                                     \
    1276             :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];                                     \
    1277             :     const int c0_shift_w = s->shift_w[ component + 0 ];                                               \
    1278             :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];                                    \
    1279             :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];                                    \
    1280             :     const int c0_shift_h = s->shift_h[ component + 0 ];                                               \
    1281             :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];                                    \
    1282             :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];                                    \
    1283             :     const int d0_linesize = out->linesize[ plane + 0 ];                                               \
    1284             :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];                                    \
    1285             :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];                                    \
    1286             :     const int max = 255 - intensity;                                                                  \
    1287             :     int x, y;                                                                                         \
    1288             :                                                                                                       \
    1289             :     if (column) {                                                                                     \
    1290             :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);                          \
    1291             :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);                          \
    1292             :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);                          \
    1293             :                                                                                                       \
    1294             :         for (x = slicew_start; x < slicew_end; x++) {                                                 \
    1295             :             const uint8_t *c0_data = in->data[plane + 0];                                             \
    1296             :             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];                                \
    1297             :             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];                                \
    1298             :             uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;                  \
    1299             :             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
    1300             :             uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
    1301             :             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);                   \
    1302             :             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);                                 \
    1303             :             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);                   \
    1304             :             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);                                 \
    1305             :             uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);                   \
    1306             :             uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);                                 \
    1307             :                                                                                                       \
    1308             :             for (y = 0; y < src_h; y++) {                                                             \
    1309             :                 const int c0 = c0_data[x >> c0_shift_w] + 128;                                        \
    1310             :                 const int c1 = c1_data[x >> c1_shift_w] - 128;                                        \
    1311             :                 const int c2 = c2_data[x >> c2_shift_w] - 128;                                        \
    1312             :                 uint8_t *target;                                                                      \
    1313             :                                                                                                       \
    1314             :                 target = d0 + x + d0_signed_linesize * c0;                                            \
    1315             :                 update(target, max, intensity);                                                       \
    1316             :                                                                                                       \
    1317             :                 target = d1 + x + d1_signed_linesize * (c0 + c1);                                     \
    1318             :                 update(target, max, intensity);                                                       \
    1319             :                                                                                                       \
    1320             :                 target = d2 + x + d2_signed_linesize * (c0 + c2);                                     \
    1321             :                 update_cr(target, max, intensity);                                                    \
    1322             :                                                                                                       \
    1323             :                 if (!c0_shift_h || (y & c0_shift_h))                                                  \
    1324             :                     c0_data += c0_linesize;                                                           \
    1325             :                 if (!c1_shift_h || (y & c1_shift_h))                                                  \
    1326             :                     c1_data += c1_linesize;                                                           \
    1327             :                 if (!c1_shift_h || (y & c1_shift_h))                                                  \
    1328             :                     c2_data += c1_linesize;                                                           \
    1329             :                 d0_data += d0_linesize;                                                               \
    1330             :                 d1_data += d1_linesize;                                                               \
    1331             :                 d2_data += d2_linesize;                                                               \
    1332             :             }                                                                                         \
    1333             :         }                                                                                             \
    1334             :     } else {                                                                                          \
    1335             :         const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;        \
    1336             :         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
    1337             :         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
    1338             :         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;     \
    1339             :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
    1340             :         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
    1341             :                                                                                                       \
    1342             :         if (mirror) {                                                                                 \
    1343             :             d0_data += s->size - 1;                                                                   \
    1344             :             d1_data += s->size - 1;                                                                   \
    1345             :             d2_data += s->size - 1;                                                                   \
    1346             :         }                                                                                             \
    1347             :                                                                                                       \
    1348             :         for (y = sliceh_start; y < sliceh_end; y++) {                                                 \
    1349             :             for (x = 0; x < src_w; x++) {                                                             \
    1350             :                 const int c0 = c0_data[x >> c0_shift_w] + 128;                                        \
    1351             :                 const int c1 = c1_data[x >> c1_shift_w] - 128;                                        \
    1352             :                 const int c2 = c2_data[x >> c2_shift_w] - 128;                                        \
    1353             :                 uint8_t *target;                                                                      \
    1354             :                                                                                                       \
    1355             :                 if (mirror) {                                                                         \
    1356             :                     target = d0_data - c0;                                                            \
    1357             :                     update(target, max, intensity);                                                   \
    1358             :                     target = d1_data - (c0 + c1);                                                     \
    1359             :                     update(target, max, intensity);                                                   \
    1360             :                     target = d2_data - (c0 + c2);                                                     \
    1361             :                     update_cr(target, max, intensity);                                                \
    1362             :                 } else {                                                                              \
    1363             :                     target = d0_data + c0;                                                            \
    1364             :                     update(target, max, intensity);                                                   \
    1365             :                     target = d1_data + (c0 + c1);                                                     \
    1366             :                     update(target, max, intensity);                                                   \
    1367             :                     target = d2_data + (c0 + c2);                                                     \
    1368             :                     update_cr(target, max, intensity);                                                \
    1369             :                 }                                                                                     \
    1370             :             }                                                                                         \
    1371             :                                                                                                       \
    1372             :             if (!c0_shift_h || (y & c0_shift_h))                                                      \
    1373             :                 c0_data += c0_linesize;                                                               \
    1374             :             if (!c1_shift_h || (y & c1_shift_h))                                                      \
    1375             :                 c1_data += c1_linesize;                                                               \
    1376             :             if (!c2_shift_h || (y & c2_shift_h))                                                      \
    1377             :                 c2_data += c2_linesize;                                                               \
    1378             :             d0_data += d0_linesize;                                                                   \
    1379             :             d1_data += d1_linesize;                                                                   \
    1380             :             d2_data += d2_linesize;                                                                   \
    1381             :         }                                                                                             \
    1382             :     }                                                                                                 \
    1383             :     return 0;                                                                                         \
    1384             : }
    1385             : 
    1386           0 : AFLAT16(aflat16_row,           update16,    0, 0)
    1387           0 : AFLAT16(aflat16_row_mirror,    update16,    0, 1)
    1388           0 : AFLAT16(aflat16_column,        update16,    1, 0)
    1389           0 : AFLAT16(aflat16_column_mirror, update16,    1, 1)
    1390           0 : AFLAT16(xflat16_row,           update16_cr, 0, 0)
    1391           0 : AFLAT16(xflat16_row_mirror,    update16_cr, 0, 1)
    1392           0 : AFLAT16(xflat16_column,        update16_cr, 1, 0)
    1393           0 : AFLAT16(xflat16_column_mirror, update16_cr, 1, 1)
    1394             : 
    1395           0 : AFLAT(aflat_row,           update,    0, 0)
    1396           0 : AFLAT(aflat_row_mirror,    update,    0, 1)
    1397           0 : AFLAT(aflat_column,        update,    1, 0)
    1398           0 : AFLAT(aflat_column_mirror, update,    1, 1)
    1399           0 : AFLAT(xflat_row,           update_cr, 0, 0)
    1400           0 : AFLAT(xflat_row_mirror,    update_cr, 0, 1)
    1401           0 : AFLAT(xflat_column,        update_cr, 1, 0)
    1402           0 : AFLAT(xflat_column_mirror, update_cr, 1, 1)
    1403             : 
    1404           0 : static av_always_inline void chroma16(WaveformContext *s,
    1405             :                                       AVFrame *in, AVFrame *out,
    1406             :                                       int component, int intensity,
    1407             :                                       int offset_y, int offset_x,
    1408             :                                       int column, int mirror,
    1409             :                                       int jobnr, int nb_jobs)
    1410             : {
    1411           0 :     const int plane = s->desc->comp[component].plane;
    1412           0 :     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
    1413           0 :     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
    1414           0 :     const int dst_linesize = out->linesize[plane] / 2;
    1415           0 :     const int limit = s->max - 1;
    1416           0 :     const int max = limit - intensity;
    1417           0 :     const int mid = s->max / 2;
    1418           0 :     const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
    1419           0 :     const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
    1420           0 :     const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
    1421           0 :     const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1422           0 :     const int src_h = in->height;
    1423           0 :     const int src_w = in->width;
    1424           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1425           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1426           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1427           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1428             :     int x, y;
    1429             : 
    1430           0 :     if (column) {
    1431           0 :         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
    1432             : 
    1433           0 :         for (x = slicew_start; x < slicew_end; x++) {
    1434           0 :             const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
    1435           0 :             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
    1436           0 :             uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x;
    1437           0 :             uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
    1438           0 :             uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
    1439           0 :             uint16_t *dst = dst_line;
    1440             : 
    1441           0 :             for (y = 0; y < src_h; y++) {
    1442           0 :                 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
    1443             :                 uint16_t *target;
    1444             : 
    1445           0 :                 target = dst + x + dst_signed_linesize * sum;
    1446           0 :                 update16(target, max, intensity, limit);
    1447             : 
    1448           0 :                 if (!c0_shift_h || (y & c0_shift_h))
    1449           0 :                     c0_data += c0_linesize;
    1450           0 :                 if (!c1_shift_h || (y & c1_shift_h))
    1451           0 :                     c1_data += c1_linesize;
    1452           0 :                 dst_data += dst_linesize;
    1453             :             }
    1454             :         }
    1455             :     } else {
    1456           0 :         const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
    1457           0 :         const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1458           0 :         uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
    1459             : 
    1460           0 :         if (mirror)
    1461           0 :             dst_data += s->size - 1;
    1462           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1463           0 :             for (x = 0; x < src_w; x++) {
    1464           0 :                 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
    1465             :                 uint16_t *target;
    1466             : 
    1467           0 :                 if (mirror) {
    1468           0 :                     target = dst_data - sum;
    1469           0 :                     update16(target, max, intensity, limit);
    1470             :                 } else {
    1471           0 :                     target = dst_data + sum;
    1472           0 :                     update16(target, max, intensity, limit);
    1473             :                 }
    1474             :             }
    1475             : 
    1476           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1477           0 :                 c0_data += c0_linesize;
    1478           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1479           0 :                 c1_data += c1_linesize;
    1480           0 :             dst_data += dst_linesize;
    1481             :         }
    1482             :     }
    1483           0 : }
    1484             : 
    1485             : #define CHROMA16_FUNC(name, column, mirror)      \
    1486             : static int chroma16_##name(AVFilterContext *ctx, \
    1487             :                            void *arg, int jobnr, \
    1488             :                            int nb_jobs)          \
    1489             : {                                                \
    1490             :     WaveformContext *s = ctx->priv;              \
    1491             :     ThreadData *td = arg;                        \
    1492             :     AVFrame *in = td->in;                        \
    1493             :     AVFrame *out = td->out;                      \
    1494             :     int component = td->component;               \
    1495             :     int offset_y = td->offset_y;                 \
    1496             :     int offset_x = td->offset_x;                 \
    1497             :                                                  \
    1498             :     chroma16(s, in, out, component, s->intensity,\
    1499             :            offset_y, offset_x, column, mirror,   \
    1500             :            jobnr, nb_jobs);                      \
    1501             :                                                  \
    1502             :     return 0;                                    \
    1503             : }
    1504             : 
    1505           0 : CHROMA16_FUNC(column_mirror, 1, 1)
    1506           0 : CHROMA16_FUNC(column,        1, 0)
    1507           0 : CHROMA16_FUNC(row_mirror,    0, 1)
    1508           0 : CHROMA16_FUNC(row,           0, 0)
    1509             : 
    1510           0 : static av_always_inline void chroma(WaveformContext *s,
    1511             :                                     AVFrame *in, AVFrame *out,
    1512             :                                     int component, int intensity,
    1513             :                                     int offset_y, int offset_x,
    1514             :                                     int column, int mirror,
    1515             :                                     int jobnr, int nb_jobs)
    1516             : {
    1517           0 :     const int plane = s->desc->comp[component].plane;
    1518           0 :     const int src_h = in->height;
    1519           0 :     const int src_w = in->width;
    1520           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1521           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1522           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1523           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1524           0 :     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
    1525           0 :     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
    1526           0 :     const int dst_linesize = out->linesize[plane];
    1527           0 :     const int max = 255 - intensity;
    1528           0 :     const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
    1529           0 :     const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
    1530           0 :     const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
    1531           0 :     const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1532             :     int x, y;
    1533             : 
    1534           0 :     if (column) {
    1535           0 :         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
    1536             : 
    1537           0 :         for (x = slicew_start; x < slicew_end; x++) {
    1538           0 :             const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
    1539           0 :             const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
    1540           0 :             uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x;
    1541           0 :             uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
    1542           0 :             uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
    1543           0 :             uint8_t *dst = dst_line;
    1544             : 
    1545           0 :             for (y = 0; y < src_h; y++) {
    1546           0 :                 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
    1547             :                 uint8_t *target;
    1548             : 
    1549           0 :                 target = dst + x + dst_signed_linesize * sum;
    1550           0 :                 update(target, max, intensity);
    1551             : 
    1552           0 :                 if (!c0_shift_h || (y & c0_shift_h))
    1553           0 :                     c0_data += c0_linesize;
    1554           0 :                 if (!c1_shift_h || (y & c1_shift_h))
    1555           0 :                     c1_data += c1_linesize;
    1556           0 :                 dst_data += dst_linesize;
    1557             :             }
    1558             :         }
    1559             :     } else {
    1560           0 :         const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
    1561           0 :         const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1562           0 :         uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
    1563             : 
    1564           0 :         if (mirror)
    1565           0 :             dst_data += s->size - 1;
    1566           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1567           0 :             for (x = 0; x < src_w; x++) {
    1568           0 :                 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
    1569             :                 uint8_t *target;
    1570             : 
    1571           0 :                 if (mirror) {
    1572           0 :                     target = dst_data - sum;
    1573           0 :                     update(target, max, intensity);
    1574             :                 } else {
    1575           0 :                     target = dst_data + sum;
    1576           0 :                     update(target, max, intensity);
    1577             :                 }
    1578             :             }
    1579             : 
    1580           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1581           0 :                 c0_data += c0_linesize;
    1582           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1583           0 :                 c1_data += c1_linesize;
    1584           0 :             dst_data += dst_linesize;
    1585             :         }
    1586             :     }
    1587           0 : }
    1588             : 
    1589             : #define CHROMA_FUNC(name, column, mirror)        \
    1590             : static int chroma_##name(AVFilterContext *ctx,   \
    1591             :                          void *arg, int jobnr,   \
    1592             :                          int nb_jobs)            \
    1593             : {                                                \
    1594             :     WaveformContext *s = ctx->priv;              \
    1595             :     ThreadData *td = arg;                        \
    1596             :     AVFrame *in = td->in;                        \
    1597             :     AVFrame *out = td->out;                      \
    1598             :     int component = td->component;               \
    1599             :     int offset_y = td->offset_y;                 \
    1600             :     int offset_x = td->offset_x;                 \
    1601             :                                                  \
    1602             :     chroma(s, in, out, component, s->intensity,  \
    1603             :            offset_y, offset_x, column, mirror,   \
    1604             :            jobnr, nb_jobs);                      \
    1605             :                                                  \
    1606             :     return 0;                                    \
    1607             : }
    1608             : 
    1609           0 : CHROMA_FUNC(column_mirror, 1, 1)
    1610           0 : CHROMA_FUNC(column,        1, 0)
    1611           0 : CHROMA_FUNC(row_mirror,    0, 1)
    1612           0 : CHROMA_FUNC(row,           0, 0)
    1613             : 
    1614           0 : static av_always_inline void color16(WaveformContext *s,
    1615             :                                      AVFrame *in, AVFrame *out,
    1616             :                                      int component, int intensity,
    1617             :                                      int offset_y, int offset_x,
    1618             :                                      int column, int mirror,
    1619             :                                      int jobnr, int nb_jobs)
    1620             : {
    1621           0 :     const int plane = s->desc->comp[component].plane;
    1622           0 :     const int limit = s->max - 1;
    1623           0 :     const int src_h = in->height;
    1624           0 :     const int src_w = in->width;
    1625           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1626           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1627           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1628           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1629           0 :     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
    1630           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
    1631           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
    1632           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
    1633           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
    1634           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1635           0 :     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
    1636           0 :     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1637           0 :     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
    1638           0 :     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
    1639           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
    1640           0 :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
    1641           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
    1642           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
    1643           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
    1644             :     int x, y;
    1645             : 
    1646           0 :     if (column) {
    1647           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
    1648           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
    1649           0 :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
    1650           0 :         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
    1651           0 :         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
    1652           0 :         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
    1653           0 :         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
    1654           0 :         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
    1655           0 :         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
    1656           0 :         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
    1657           0 :         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
    1658           0 :         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
    1659             : 
    1660           0 :         for (y = 0; y < src_h; y++) {
    1661           0 :             for (x = slicew_start; x < slicew_end; x++) {
    1662           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
    1663           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1664           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1665             : 
    1666           0 :                 *(d0 + d0_signed_linesize * c0 + x) = c0;
    1667           0 :                 *(d1 + d1_signed_linesize * c0 + x) = c1;
    1668           0 :                 *(d2 + d2_signed_linesize * c0 + x) = c2;
    1669             :             }
    1670             : 
    1671           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1672           0 :                 c0_data += c0_linesize;
    1673           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1674           0 :                 c1_data += c1_linesize;
    1675           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1676           0 :                 c2_data += c2_linesize;
    1677           0 :             d0_data += d0_linesize;
    1678           0 :             d1_data += d1_linesize;
    1679           0 :             d2_data += d2_linesize;
    1680             :         }
    1681             :     } else {
    1682           0 :         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
    1683           0 :         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
    1684           0 :         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
    1685             : 
    1686           0 :         if (mirror) {
    1687           0 :             d0_data += s->size - 1;
    1688           0 :             d1_data += s->size - 1;
    1689           0 :             d2_data += s->size - 1;
    1690             :         }
    1691             : 
    1692           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1693           0 :             for (x = 0; x < src_w; x++) {
    1694           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
    1695           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1696           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1697             : 
    1698           0 :                 if (mirror) {
    1699           0 :                     *(d0_data - c0) = c0;
    1700           0 :                     *(d1_data - c0) = c1;
    1701           0 :                     *(d2_data - c0) = c2;
    1702             :                 } else {
    1703           0 :                     *(d0_data + c0) = c0;
    1704           0 :                     *(d1_data + c0) = c1;
    1705           0 :                     *(d2_data + c0) = c2;
    1706             :                 }
    1707             :             }
    1708             : 
    1709           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1710           0 :                 c0_data += c0_linesize;
    1711           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1712           0 :                 c1_data += c1_linesize;
    1713           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1714           0 :                 c2_data += c2_linesize;
    1715           0 :             d0_data += d0_linesize;
    1716           0 :             d1_data += d1_linesize;
    1717           0 :             d2_data += d2_linesize;
    1718             :         }
    1719             :     }
    1720           0 : }
    1721             : 
    1722             : #define COLOR16_FUNC(name, column, mirror)       \
    1723             : static int color16_##name(AVFilterContext *ctx,  \
    1724             :                           void *arg, int jobnr,  \
    1725             :                           int nb_jobs)           \
    1726             : {                                                \
    1727             :     WaveformContext *s = ctx->priv;              \
    1728             :     ThreadData *td = arg;                        \
    1729             :     AVFrame *in = td->in;                        \
    1730             :     AVFrame *out = td->out;                      \
    1731             :     int component = td->component;               \
    1732             :     int offset_y = td->offset_y;                 \
    1733             :     int offset_x = td->offset_x;                 \
    1734             :                                                  \
    1735             :     color16(s, in, out, component, s->intensity, \
    1736             :             offset_y, offset_x, column, mirror,  \
    1737             :             jobnr, nb_jobs);                     \
    1738             :                                                  \
    1739             :     return 0;                                    \
    1740             : }
    1741             : 
    1742           0 : COLOR16_FUNC(column_mirror, 1, 1)
    1743           0 : COLOR16_FUNC(column,        1, 0)
    1744           0 : COLOR16_FUNC(row_mirror,    0, 1)
    1745           0 : COLOR16_FUNC(row,           0, 0)
    1746             : 
    1747           0 : static av_always_inline void color(WaveformContext *s,
    1748             :                                    AVFrame *in, AVFrame *out,
    1749             :                                    int component, int intensity,
    1750             :                                    int offset_y, int offset_x,
    1751             :                                    int column, int mirror,
    1752             :                                    int jobnr, int nb_jobs)
    1753             : {
    1754           0 :     const int plane = s->desc->comp[component].plane;
    1755           0 :     const int src_h = in->height;
    1756           0 :     const int src_w = in->width;
    1757           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1758           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1759           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1760           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1761           0 :     const int c0_linesize = in->linesize[ plane + 0 ];
    1762           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
    1763           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
    1764           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
    1765           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
    1766           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1767           0 :     const uint8_t *c0_data = in->data[plane] +                  (sliceh_start >> c0_shift_h) * c0_linesize;
    1768           0 :     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1769           0 :     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
    1770           0 :     const int d0_linesize = out->linesize[ plane + 0 ];
    1771           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
    1772           0 :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
    1773           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
    1774           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
    1775           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
    1776             :     int x, y;
    1777             : 
    1778           0 :     if (column) {
    1779           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
    1780           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
    1781           0 :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
    1782           0 :         uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
    1783           0 :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
    1784           0 :         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
    1785           0 :         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
    1786           0 :         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
    1787           0 :         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
    1788           0 :         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
    1789           0 :         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
    1790           0 :         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
    1791             : 
    1792           0 :         for (y = 0; y < src_h; y++) {
    1793           0 :             for (x = slicew_start; x < slicew_end; x++) {
    1794           0 :                 const int c0 = c0_data[x >> c0_shift_w];
    1795           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1796           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1797             : 
    1798           0 :                 *(d0 + d0_signed_linesize * c0 + x) = c0;
    1799           0 :                 *(d1 + d1_signed_linesize * c0 + x) = c1;
    1800           0 :                 *(d2 + d2_signed_linesize * c0 + x) = c2;
    1801             :             }
    1802             : 
    1803           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1804           0 :                 c0_data += c0_linesize;
    1805           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1806           0 :                 c1_data += c1_linesize;
    1807           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1808           0 :                 c2_data += c2_linesize;
    1809           0 :             d0_data += d0_linesize;
    1810           0 :             d1_data += d1_linesize;
    1811           0 :             d2_data += d2_linesize;
    1812             :         }
    1813             :     } else {
    1814           0 :         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
    1815           0 :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
    1816           0 :         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
    1817             : 
    1818           0 :         if (mirror) {
    1819           0 :             d0_data += s->size - 1;
    1820           0 :             d1_data += s->size - 1;
    1821           0 :             d2_data += s->size - 1;
    1822             :         }
    1823             : 
    1824           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1825           0 :             for (x = 0; x < src_w; x++) {
    1826           0 :                 const int c0 = c0_data[x >> c0_shift_w];
    1827           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1828           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1829             : 
    1830           0 :                 if (mirror) {
    1831           0 :                     *(d0_data - c0) = c0;
    1832           0 :                     *(d1_data - c0) = c1;
    1833           0 :                     *(d2_data - c0) = c2;
    1834             :                 } else {
    1835           0 :                     *(d0_data + c0) = c0;
    1836           0 :                     *(d1_data + c0) = c1;
    1837           0 :                     *(d2_data + c0) = c2;
    1838             :                 }
    1839             :             }
    1840             : 
    1841           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1842           0 :                 c0_data += c0_linesize;
    1843           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1844           0 :                 c1_data += c1_linesize;
    1845           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1846           0 :                 c2_data += c2_linesize;
    1847           0 :             d0_data += d0_linesize;
    1848           0 :             d1_data += d1_linesize;
    1849           0 :             d2_data += d2_linesize;
    1850             :         }
    1851             :     }
    1852           0 : }
    1853             : 
    1854             : #define COLOR_FUNC(name, column, mirror)       \
    1855             : static int color_##name(AVFilterContext *ctx,  \
    1856             :                         void *arg, int jobnr,  \
    1857             :                         int nb_jobs)           \
    1858             : {                                              \
    1859             :     WaveformContext *s = ctx->priv;            \
    1860             :     ThreadData *td = arg;                      \
    1861             :     AVFrame *in = td->in;                      \
    1862             :     AVFrame *out = td->out;                    \
    1863             :     int component = td->component;             \
    1864             :     int offset_y = td->offset_y;               \
    1865             :     int offset_x = td->offset_x;               \
    1866             :                                                \
    1867             :     color(s, in, out, component, s->intensity, \
    1868             :           offset_y, offset_x, column, mirror,  \
    1869             :           jobnr, nb_jobs);                     \
    1870             :                                                \
    1871             :     return 0;                                  \
    1872             : }
    1873             : 
    1874           0 : COLOR_FUNC(column_mirror, 1, 1)
    1875           0 : COLOR_FUNC(column,        1, 0)
    1876           0 : COLOR_FUNC(row_mirror,    0, 1)
    1877           0 : COLOR_FUNC(row,           0, 0)
    1878             : 
    1879           0 : static av_always_inline void acolor16(WaveformContext *s,
    1880             :                                       AVFrame *in, AVFrame *out,
    1881             :                                       int component, int intensity,
    1882             :                                       int offset_y, int offset_x,
    1883             :                                       int column, int mirror,
    1884             :                                       int jobnr, int nb_jobs)
    1885             : {
    1886           0 :     const int plane = s->desc->comp[component].plane;
    1887           0 :     const int limit = s->max - 1;
    1888           0 :     const int max = limit - intensity;
    1889           0 :     const int src_h = in->height;
    1890           0 :     const int src_w = in->width;
    1891           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    1892           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    1893           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    1894           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    1895           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
    1896           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
    1897           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
    1898           0 :     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
    1899           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
    1900           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
    1901           0 :     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
    1902           0 :     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    1903           0 :     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
    1904           0 :     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
    1905           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
    1906           0 :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
    1907           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
    1908           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
    1909           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
    1910             :     int x, y;
    1911             : 
    1912           0 :     if (column) {
    1913           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
    1914           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
    1915           0 :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
    1916           0 :         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
    1917           0 :         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
    1918           0 :         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
    1919           0 :         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
    1920           0 :         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
    1921           0 :         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
    1922           0 :         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
    1923           0 :         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
    1924           0 :         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
    1925             : 
    1926           0 :         for (y = 0; y < src_h; y++) {
    1927           0 :             for (x = slicew_start; x < slicew_end; x++) {
    1928           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
    1929           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1930           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1931             : 
    1932           0 :                 update16(d0 + d0_signed_linesize * c0 + x, max, intensity, limit);
    1933           0 :                 *(d1 + d1_signed_linesize * c0 + x) = c1;
    1934           0 :                 *(d2 + d2_signed_linesize * c0 + x) = c2;
    1935             :             }
    1936             : 
    1937           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1938           0 :                 c0_data += c0_linesize;
    1939           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1940           0 :                 c1_data += c1_linesize;
    1941           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1942           0 :                 c2_data += c2_linesize;
    1943           0 :             d0_data += d0_linesize;
    1944           0 :             d1_data += d1_linesize;
    1945           0 :             d2_data += d2_linesize;
    1946             :         }
    1947             :     } else {
    1948           0 :         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
    1949           0 :         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
    1950           0 :         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
    1951             : 
    1952           0 :         if (mirror) {
    1953           0 :             d0_data += s->size - 1;
    1954           0 :             d1_data += s->size - 1;
    1955           0 :             d2_data += s->size - 1;
    1956             :         }
    1957             : 
    1958           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    1959           0 :             for (x = 0; x < src_w; x++) {
    1960           0 :                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
    1961           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    1962           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    1963             : 
    1964           0 :                 if (mirror) {
    1965           0 :                     update16(d0_data - c0, max, intensity, limit);
    1966           0 :                     *(d1_data - c0) = c1;
    1967           0 :                     *(d2_data - c0) = c2;
    1968             :                 } else {
    1969           0 :                     update16(d0_data + c0, max, intensity, limit);
    1970           0 :                     *(d1_data + c0) = c1;
    1971           0 :                     *(d2_data + c0) = c2;
    1972             :                 }
    1973             :             }
    1974             : 
    1975           0 :             if (!c0_shift_h || (y & c0_shift_h))
    1976           0 :                 c0_data += c0_linesize;
    1977           0 :             if (!c1_shift_h || (y & c1_shift_h))
    1978           0 :                 c1_data += c1_linesize;
    1979           0 :             if (!c2_shift_h || (y & c2_shift_h))
    1980           0 :                 c2_data += c2_linesize;
    1981           0 :             d0_data += d0_linesize;
    1982           0 :             d1_data += d1_linesize;
    1983           0 :             d2_data += d2_linesize;
    1984             :         }
    1985             :     }
    1986           0 : }
    1987             : 
    1988             : #define ACOLOR16_FUNC(name, column, mirror)      \
    1989             : static int acolor16_##name(AVFilterContext *ctx, \
    1990             :                            void *arg, int jobnr, \
    1991             :                            int nb_jobs)          \
    1992             : {                                                \
    1993             :     WaveformContext *s = ctx->priv;              \
    1994             :     ThreadData *td = arg;                        \
    1995             :     AVFrame *in = td->in;                        \
    1996             :     AVFrame *out = td->out;                      \
    1997             :     int component = td->component;               \
    1998             :     int offset_y = td->offset_y;                 \
    1999             :     int offset_x = td->offset_x;                 \
    2000             :                                                  \
    2001             :     acolor16(s, in, out, component, s->intensity,\
    2002             :              offset_y, offset_x, column, mirror, \
    2003             :              jobnr, nb_jobs);                    \
    2004             :                                                  \
    2005             :     return 0;                                    \
    2006             : }
    2007             : 
    2008           0 : ACOLOR16_FUNC(column_mirror, 1, 1)
    2009           0 : ACOLOR16_FUNC(column,        1, 0)
    2010           0 : ACOLOR16_FUNC(row_mirror,    0, 1)
    2011           0 : ACOLOR16_FUNC(row,           0, 0)
    2012             : 
    2013           0 : static av_always_inline void acolor(WaveformContext *s,
    2014             :                                     AVFrame *in, AVFrame *out,
    2015             :                                     int component, int intensity,
    2016             :                                     int offset_y, int offset_x,
    2017             :                                     int column, int mirror,
    2018             :                                     int jobnr, int nb_jobs)
    2019             : {
    2020           0 :     const int plane = s->desc->comp[component].plane;
    2021           0 :     const int src_h = in->height;
    2022           0 :     const int src_w = in->width;
    2023           0 :     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
    2024           0 :     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
    2025           0 :     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
    2026           0 :     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
    2027           0 :     const int c0_shift_w = s->shift_w[ component + 0 ];
    2028           0 :     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
    2029           0 :     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
    2030           0 :     const int c0_shift_h = s->shift_h[ component + 0 ];
    2031           0 :     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
    2032           0 :     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
    2033           0 :     const int c0_linesize = in->linesize[ plane + 0 ];
    2034           0 :     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
    2035           0 :     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
    2036           0 :     const uint8_t *c0_data = in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
    2037           0 :     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
    2038           0 :     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
    2039           0 :     const int d0_linesize = out->linesize[ plane + 0 ];
    2040           0 :     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
    2041           0 :     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
    2042           0 :     const int max = 255 - intensity;
    2043             :     int x, y;
    2044             : 
    2045           0 :     if (column) {
    2046           0 :         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
    2047           0 :         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
    2048           0 :         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
    2049           0 :         uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
    2050           0 :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
    2051           0 :         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
    2052           0 :         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
    2053           0 :         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
    2054           0 :         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
    2055           0 :         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
    2056           0 :         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
    2057           0 :         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
    2058             : 
    2059           0 :         for (y = 0; y < src_h; y++) {
    2060           0 :             for (x = slicew_start; x < slicew_end; x++) {
    2061           0 :                 const int c0 = c0_data[x >> c0_shift_w];
    2062           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    2063           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    2064             : 
    2065           0 :                 update(d0 + d0_signed_linesize * c0 + x, max, intensity);
    2066           0 :                 *(d1 + d1_signed_linesize * c0 + x) = c1;
    2067           0 :                 *(d2 + d2_signed_linesize * c0 + x) = c2;
    2068             :             }
    2069             : 
    2070           0 :             if (!c0_shift_h || (y & c0_shift_h))
    2071           0 :                 c0_data += c0_linesize;
    2072           0 :             if (!c1_shift_h || (y & c1_shift_h))
    2073           0 :                 c1_data += c1_linesize;
    2074           0 :             if (!c2_shift_h || (y & c2_shift_h))
    2075           0 :                 c2_data += c2_linesize;
    2076           0 :             d0_data += d0_linesize;
    2077           0 :             d1_data += d1_linesize;
    2078           0 :             d2_data += d2_linesize;
    2079             :         }
    2080             :     } else {
    2081           0 :         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
    2082           0 :         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
    2083           0 :         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
    2084             : 
    2085           0 :         if (mirror) {
    2086           0 :             d0_data += s->size - 1;
    2087           0 :             d1_data += s->size - 1;
    2088           0 :             d2_data += s->size - 1;
    2089             :         }
    2090             : 
    2091           0 :         for (y = sliceh_start; y < sliceh_end; y++) {
    2092           0 :             for (x = 0; x < src_w; x++) {
    2093           0 :                 const int c0 = c0_data[x >> c0_shift_w];
    2094           0 :                 const int c1 = c1_data[x >> c1_shift_w];
    2095           0 :                 const int c2 = c2_data[x >> c2_shift_w];
    2096             : 
    2097           0 :                 if (mirror) {
    2098           0 :                     update(d0_data - c0, max, intensity);
    2099           0 :                     *(d1_data - c0) = c1;
    2100           0 :                     *(d2_data - c0) = c2;
    2101             :                 } else {
    2102           0 :                     update(d0_data + c0, max, intensity);
    2103           0 :                     *(d1_data + c0) = c1;
    2104           0 :                     *(d2_data + c0) = c2;
    2105             :                 }
    2106             :             }
    2107             : 
    2108           0 :             if (!c0_shift_h || (y & c0_shift_h))
    2109           0 :                 c0_data += c0_linesize;
    2110           0 :             if (!c1_shift_h || (y & c1_shift_h))
    2111           0 :                 c1_data += c1_linesize;
    2112           0 :             if (!c2_shift_h || (y & c2_shift_h))
    2113           0 :                 c2_data += c2_linesize;
    2114           0 :             d0_data += d0_linesize;
    2115           0 :             d1_data += d1_linesize;
    2116           0 :             d2_data += d2_linesize;
    2117             :         }
    2118             :     }
    2119           0 : }
    2120             : 
    2121             : #define ACOLOR_FUNC(name, column, mirror)        \
    2122             : static int acolor_##name(AVFilterContext *ctx,   \
    2123             :                          void *arg, int jobnr,   \
    2124             :                          int nb_jobs)            \
    2125             : {                                                \
    2126             :     WaveformContext *s = ctx->priv;              \
    2127             :     ThreadData *td = arg;                        \
    2128             :     AVFrame *in = td->in;                        \
    2129             :     AVFrame *out = td->out;                      \
    2130             :     int component = td->component;               \
    2131             :     int offset_y = td->offset_y;                 \
    2132             :     int offset_x = td->offset_x;                 \
    2133             :                                                  \
    2134             :     acolor(s, in, out, component, s->intensity,  \
    2135             :            offset_y, offset_x, column, mirror,   \
    2136             :            jobnr, nb_jobs);                      \
    2137             :                                                  \
    2138             :     return 0;                                    \
    2139             : }
    2140             : 
    2141           0 : ACOLOR_FUNC(column_mirror, 1, 1)
    2142           0 : ACOLOR_FUNC(column,        1, 0)
    2143           0 : ACOLOR_FUNC(row_mirror,    0, 1)
    2144           0 : ACOLOR_FUNC(row,           0, 0)
    2145             : 
    2146             : static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
    2147             : static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
    2148             : 
    2149             : static const GraticuleLines aflat_digital8[] = {
    2150             :     { { {  "16",  16+128 }, {  "16",  16+128 }, {  "16",  16+128 }, {   "0",   0+128 } } },
    2151             :     { { { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 } } },
    2152             :     { { { "235", 235+128 }, { "240", 240+128 }, { "240", 240+128 }, { "255", 255+128 } } },
    2153             : };
    2154             : 
    2155             : static const GraticuleLines aflat_digital9[] = {
    2156             :     { { {  "32",  32+256 }, {  "32",  32+256 }, {  "32",  32+256 }, {   "0",   0+256 } } },
    2157             :     { { { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 } } },
    2158             :     { { { "470", 470+256 }, { "480", 480+256 }, { "480", 480+256 }, { "511", 511+256 } } },
    2159             : };
    2160             : 
    2161             : static const GraticuleLines aflat_digital10[] = {
    2162             :     { { {  "64",  64+512 }, {  "64",  64+512 }, {  "64",  64+512 }, {    "0",    0+512 } } },
    2163             :     { { { "512", 512+512 }, { "512", 512+512 }, { "512", 512+512 }, {  "512",  512+512 } } },
    2164             :     { { { "940", 940+512 }, { "960", 960+512 }, { "960", 960+512 }, { "1023", 1023+512 } } },
    2165             : };
    2166             : 
    2167             : static const GraticuleLines aflat_digital12[] = {
    2168             :     { { {  "256",  256+2048 }, {  "256",  256+2048 }, {  "256",  256+2048 }, {    "0",    0+2048 } } },
    2169             :     { { { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 } } },
    2170             :     { { { "3760", 3760+2048 }, { "3840", 3840+2048 }, { "3840", 3840+2048 }, { "4095", 4095+2048 } } },
    2171             : };
    2172             : 
    2173             : static const GraticuleLines aflat_millivolts8[] = {
    2174             :     { { {   "0",  16+128 }, {   "0",  16+128 }, {   "0",  16+128 }, {   "0",   0+128 } } },
    2175             :     { { { "175",  71+128 }, { "175",  72+128 }, { "175",  72+128 }, { "175",  64+128 } } },
    2176             :     { { { "350", 126+128 }, { "350", 128+128 }, { "350", 128+128 }, { "350", 128+128 } } },
    2177             :     { { { "525", 180+128 }, { "525", 184+128 }, { "525", 184+128 }, { "525", 192+128 } } },
    2178             :     { { { "700", 235+128 }, { "700", 240+128 }, { "700", 240+128 }, { "700", 255+128 } } },
    2179             : };
    2180             : 
    2181             : static const GraticuleLines aflat_millivolts9[] = {
    2182             :     { { {   "0",  32+256 }, {   "0",  32+256 }, {   "0",  32+256 }, {   "0",   0+256 } } },
    2183             :     { { { "175", 142+256 }, { "175", 144+256 }, { "175", 144+256 }, { "175", 128+256 } } },
    2184             :     { { { "350", 251+256 }, { "350", 256+256 }, { "350", 256+256 }, { "350", 256+256 } } },
    2185             :     { { { "525", 361+256 }, { "525", 368+256 }, { "525", 368+256 }, { "525", 384+256 } } },
    2186             :     { { { "700", 470+256 }, { "700", 480+256 }, { "700", 480+256 }, { "700", 511+256 } } },
    2187             : };
    2188             : 
    2189             : static const GraticuleLines aflat_millivolts10[] = {
    2190             :     { { {   "0",  64+512 }, {   "0",  64+512 }, {   "0",  64+512 }, {   "0",    0+512 } } },
    2191             :     { { { "175", 283+512 }, { "175", 288+512 }, { "175", 288+512 }, { "175",  256+512 } } },
    2192             :     { { { "350", 502+512 }, { "350", 512+512 }, { "350", 512+512 }, { "350",  512+512 } } },
    2193             :     { { { "525", 721+512 }, { "525", 736+512 }, { "525", 736+512 }, { "525",  768+512 } } },
    2194             :     { { { "700", 940+512 }, { "700", 960+512 }, { "700", 960+512 }, { "700", 1023+512 } } },
    2195             : };
    2196             : 
    2197             : static const GraticuleLines aflat_millivolts12[] = {
    2198             :     { { {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",    0+2048 } } },
    2199             :     { { { "175", 1132+2048 }, { "175", 1152+2048 }, { "175", 1152+2048 }, { "175", 1024+2048 } } },
    2200             :     { { { "350", 2008+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 } } },
    2201             :     { { { "525", 2884+2048 }, { "525", 2944+2048 }, { "525", 2944+2048 }, { "525", 3072+2048 } } },
    2202             :     { { { "700", 3760+2048 }, { "700", 3840+2048 }, { "700", 3840+2048 }, { "700", 4095+2048 } } },
    2203             : };
    2204             : 
    2205             : static const GraticuleLines aflat_ire8[] = {
    2206             :     { { { "-25", -39+128 }, { "-25", -40+128 }, { "-25", -40+128 }, { "-25", -64+128 } } },
    2207             :     { { {   "0",  16+128 }, {   "0",  16+128 }, {   "0",  16+128 }, {   "0",   0+128 } } },
    2208             :     { { {  "25",  71+128 }, {  "25",  72+128 }, {  "25",  72+128 }, {  "25",  64+128 } } },
    2209             :     { { {  "50", 126+128 }, {  "50", 128+128 }, {  "50", 128+128 }, {  "50", 128+128 } } },
    2210             :     { { {  "75", 180+128 }, {  "75", 184+128 }, {  "75", 184+128 }, {  "75", 192+128 } } },
    2211             :     { { { "100", 235+128 }, { "100", 240+128 }, { "100", 240+128 }, { "100", 256+128 } } },
    2212             :     { { { "125", 290+128 }, { "125", 296+128 }, { "125", 296+128 }, { "125", 320+128 } } },
    2213             : };
    2214             : 
    2215             : static const GraticuleLines aflat_ire9[] = {
    2216             :     { { { "-25", -78+256 }, { "-25", -80+256 }, { "-25", -80+256 }, { "-25",-128+256 } } },
    2217             :     { { {   "0",  32+256 }, {   "0",  32+256 }, {   "0",  32+256 }, {   "0",   0+256 } } },
    2218             :     { { {  "25", 142+256 }, {  "25", 144+256 }, {  "25", 144+256 }, {  "25", 128+256 } } },
    2219             :     { { {  "50", 251+256 }, {  "50", 256+256 }, {  "50", 256+256 }, {  "50", 256+256 } } },
    2220             :     { { {  "75", 361+256 }, {  "75", 368+256 }, {  "75", 368+256 }, {  "75", 384+256 } } },
    2221             :     { { { "100", 470+256 }, { "100", 480+256 }, { "100", 480+256 }, { "100", 512+256 } } },
    2222             :     { { { "125", 580+256 }, { "125", 592+256 }, { "125", 592+256 }, { "125", 640+256 } } },
    2223             : };
    2224             : 
    2225             : static const GraticuleLines aflat_ire10[] = {
    2226             :     { { { "-25",-156+512 }, { "-25",-160+512 }, { "-25",-160+512 }, { "-25", -256+512 } } },
    2227             :     { { {   "0",  64+512 }, {   "0",  64+512 }, {  "0",   64+512 }, {   "0",    0+512 } } },
    2228             :     { { {  "25", 283+512 }, {  "25", 288+512 }, {  "25", 288+512 }, {  "25",  256+512 } } },
    2229             :     { { {  "50", 502+512 }, {  "50", 512+512 }, {  "50", 512+512 }, {  "50",  512+512 } } },
    2230             :     { { {  "75", 721+512 }, {  "75", 736+512 }, {  "75", 736+512 }, {  "75",  768+512 } } },
    2231             :     { { { "100", 940+512 }, { "100", 960+512 }, { "100", 960+512 }, { "100", 1024+512 } } },
    2232             :     { { { "125",1160+512 }, { "125",1184+512 }, { "125",1184+512 }, { "125", 1280+512 } } },
    2233             : };
    2234             : 
    2235             : static const GraticuleLines aflat_ire12[] = {
    2236             :     { { { "-25", -624+2048 }, { "-25", -640+2048 }, { "-25", -640+2048 }, { "-25",-1024+2048 } } },
    2237             :     { { {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",    0+2048 } } },
    2238             :     { { {  "25", 1132+2048 }, {  "25", 1152+2048 }, {  "25", 1152+2048 }, {  "25", 1024+2048 } } },
    2239             :     { { {  "50", 2008+2048 }, {  "50", 2048+2048 }, {  "50", 2048+2048 }, {  "50", 2048+2048 } } },
    2240             :     { { {  "75", 2884+2048 }, {  "75", 2944+2048 }, {  "75", 2944+2048 }, {  "75", 3072+2048 } } },
    2241             :     { { { "100", 3760+2048 }, { "100", 3840+2048 }, { "100", 3840+2048 }, { "100", 4096+2048 } } },
    2242             :     { { { "125", 4640+2048 }, { "125", 4736+2048 }, { "125", 4736+2048 }, { "125", 5120+2048 } } },
    2243             : };
    2244             : 
    2245             : static const GraticuleLines flat_digital8[] = {
    2246             :     { { {  "16",  16+256 }, {  "16",  16+256 }, {  "16",  16+256 }, {   "0",   0+256 } } },
    2247             :     { { { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 } } },
    2248             :     { { { "235", 235+256 }, { "240", 240+256 }, { "240", 240+256 }, { "255", 255+256 } } },
    2249             : };
    2250             : 
    2251             : static const GraticuleLines flat_digital9[] = {
    2252             :     { { {  "32",  32+512 }, {  "32",  32+512 }, {  "32",  32+512 }, {   "0",   0+512 } } },
    2253             :     { { { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 } } },
    2254             :     { { { "470", 470+512 }, { "480", 480+512 }, { "480", 480+512 }, { "511", 511+512 } } },
    2255             : };
    2256             : 
    2257             : static const GraticuleLines flat_digital10[] = {
    2258             :     { { {  "64",  64+1024 }, {  "64",  64+1024 }, {  "64",  64+1024 }, {    "0",    0+1024 } } },
    2259             :     { { { "512", 512+1024 }, { "512", 512+1024 }, { "512", 512+1024 }, {  "512",  512+1024 } } },
    2260             :     { { { "940", 940+1024 }, { "960", 960+1024 }, { "960", 960+1024 }, { "1023", 1023+1024 } } },
    2261             : };
    2262             : 
    2263             : static const GraticuleLines flat_digital12[] = {
    2264             :     { { {  "256",  256+4096 }, {  "256",  256+4096 }, {  "256",  256+4096 }, {    "0",    0+4096 } } },
    2265             :     { { { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 } } },
    2266             :     { { { "3760", 3760+4096 }, { "3840", 3840+4096 }, { "3840", 3840+4096 }, { "4095", 4095+4096 } } },
    2267             : };
    2268             : 
    2269             : static const GraticuleLines flat_millivolts8[] = {
    2270             :     { { {   "0",  16+256 }, {   "0",  16+256 }, {   "0",  16+256 }, {   "0",   0+256 } } },
    2271             :     { { { "175",  71+256 }, { "175",  72+256 }, { "175",  72+256 }, { "175",  64+256 } } },
    2272             :     { { { "350", 126+256 }, { "350", 128+256 }, { "350", 128+256 }, { "350", 128+256 } } },
    2273             :     { { { "525", 180+256 }, { "525", 184+256 }, { "525", 184+256 }, { "525", 192+256 } } },
    2274             :     { { { "700", 235+256 }, { "700", 240+256 }, { "700", 240+256 }, { "700", 255+256 } } },
    2275             : };
    2276             : 
    2277             : static const GraticuleLines flat_millivolts9[] = {
    2278             :     { { {   "0",  32+512 }, {   "0",  32+512 }, {   "0",  32+512 }, {   "0",   0+512 } } },
    2279             :     { { { "175", 142+512 }, { "175", 144+512 }, { "175", 144+512 }, { "175", 128+512 } } },
    2280             :     { { { "350", 251+512 }, { "350", 256+512 }, { "350", 256+512 }, { "350", 256+512 } } },
    2281             :     { { { "525", 361+512 }, { "525", 368+512 }, { "525", 368+512 }, { "525", 384+512 } } },
    2282             :     { { { "700", 470+512 }, { "700", 480+512 }, { "700", 480+512 }, { "700", 511+512 } } },
    2283             : };
    2284             : 
    2285             : static const GraticuleLines flat_millivolts10[] = {
    2286             :     { { {   "0",  64+1024 }, {   "0",  64+1024 }, {   "0",  64+1024 }, {   "0",    0+1024 } } },
    2287             :     { { { "175", 283+1024 }, { "175", 288+1024 }, { "175", 288+1024 }, { "175",  256+1024 } } },
    2288             :     { { { "350", 502+1024 }, { "350", 512+1024 }, { "350", 512+1024 }, { "350",  512+1024 } } },
    2289             :     { { { "525", 721+1024 }, { "525", 736+1024 }, { "525", 736+1024 }, { "525",  768+1024 } } },
    2290             :     { { { "700", 940+1024 }, { "700", 960+1024 }, { "700", 960+1024 }, { "700", 1023+1024 } } },
    2291             : };
    2292             : 
    2293             : static const GraticuleLines flat_millivolts12[] = {
    2294             :     { { {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",    0+4096 } } },
    2295             :     { { { "175", 1132+4096 }, { "175", 1152+4096 }, { "175", 1152+4096 }, { "175", 1024+4096 } } },
    2296             :     { { { "350", 2008+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 } } },
    2297             :     { { { "525", 2884+4096 }, { "525", 2944+4096 }, { "525", 2944+4096 }, { "525", 3072+4096 } } },
    2298             :     { { { "700", 3760+4096 }, { "700", 3840+4096 }, { "700", 3840+4096 }, { "700", 4095+4096 } } },
    2299             : };
    2300             : 
    2301             : static const GraticuleLines flat_ire8[] = {
    2302             :     { { { "-25", -39+256 }, { "-25", -40+256 }, { "-25", -40+256 }, { "-25", -64+256 } } },
    2303             :     { { {   "0",  16+256 }, {   "0",  16+256 }, {   "0",  16+256 }, {   "0",   0+256 } } },
    2304             :     { { {  "25",  71+256 }, {  "25",  72+256 }, {  "25",  72+256 }, {  "25",  64+256 } } },
    2305             :     { { {  "50", 126+256 }, {  "50", 128+256 }, {  "50", 128+256 }, {  "50", 128+256 } } },
    2306             :     { { {  "75", 180+256 }, {  "75", 184+256 }, {  "75", 184+256 }, {  "75", 192+256 } } },
    2307             :     { { { "100", 235+256 }, { "100", 240+256 }, { "100", 240+256 }, { "100", 256+256 } } },
    2308             :     { { { "125", 290+256 }, { "125", 296+256 }, { "125", 296+256 }, { "125", 320+256 } } },
    2309             : };
    2310             : 
    2311             : static const GraticuleLines flat_ire9[] = {
    2312             :     { { { "-25", -78+512 }, { "-25", -80+512 }, { "-25", -80+512 }, { "-25",-128+512 } } },
    2313             :     { { {   "0",  32+512 }, {   "0",  32+512 }, {   "0",  32+512 }, {   "0",   0+512 } } },
    2314             :     { { {  "25", 142+512 }, {  "25", 144+512 }, {  "25", 144+512 }, {  "25", 128+512 } } },
    2315             :     { { {  "50", 251+512 }, {  "50", 256+512 }, {  "50", 256+512 }, {  "50", 256+512 } } },
    2316             :     { { {  "75", 361+512 }, {  "75", 368+512 }, {  "75", 368+512 }, {  "75", 384+512 } } },
    2317             :     { { { "100", 470+512 }, { "100", 480+512 }, { "100", 480+512 }, { "100", 512+512 } } },
    2318             :     { { { "125", 580+512 }, { "125", 592+512 }, { "125", 592+512 }, { "125", 640+512 } } },
    2319             : };
    2320             : 
    2321             : static const GraticuleLines flat_ire10[] = {
    2322             :     { { { "-25",-156+1024 }, { "-25",-160+1024 }, { "-25",-160+1024 }, { "-25", -256+1024 } } },
    2323             :     { { {   "0",  64+1024 }, {   "0",  64+1024 }, {  "0",   64+1024 }, {   "0",    0+1024 } } },
    2324             :     { { {  "25", 283+1024 }, {  "25", 288+1024 }, {  "25", 288+1024 }, {  "25",  256+1024 } } },
    2325             :     { { {  "50", 502+1024 }, {  "50", 512+1024 }, {  "50", 512+1024 }, {  "50",  512+1024 } } },
    2326             :     { { {  "75", 721+1024 }, {  "75", 736+1024 }, {  "75", 736+1024 }, {  "75",  768+1024 } } },
    2327             :     { { { "100", 940+1024 }, { "100", 960+1024 }, { "100", 960+1024 }, { "100", 1024+1024 } } },
    2328             :     { { { "125",1160+1024 }, { "125",1184+1024 }, { "125",1184+1024 }, { "125", 1280+1024 } } },
    2329             : };
    2330             : 
    2331             : static const GraticuleLines flat_ire12[] = {
    2332             :     { { { "-25", -624+4096 }, { "-25", -640+4096 }, { "-25", -640+4096 }, { "-25",-1024+4096 } } },
    2333             :     { { {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",    0+4096 } } },
    2334             :     { { {  "25", 1132+4096 }, {  "25", 1152+4096 }, {  "25", 1152+4096 }, {  "25", 1024+4096 } } },
    2335             :     { { {  "50", 2008+4096 }, {  "50", 2048+4096 }, {  "50", 2048+4096 }, {  "50", 2048+4096 } } },
    2336             :     { { {  "75", 2884+4096 }, {  "75", 2944+4096 }, {  "75", 2944+4096 }, {  "75", 3072+4096 } } },
    2337             :     { { { "100", 3760+4096 }, { "100", 3840+4096 }, { "100", 3840+4096 }, { "100", 4096+4096 } } },
    2338             :     { { { "125", 4640+4096 }, { "125", 4736+4096 }, { "125", 4736+4096 }, { "125", 5120+4096 } } },
    2339             : };
    2340             : 
    2341             : static const GraticuleLines digital8[] = {
    2342             :     { { {  "16",  16 }, {  "16",  16 }, {  "16",  16 }, {   "0",   0 } } },
    2343             :     { { { "128", 128 }, { "128", 128 }, { "128", 128 }, { "128", 128 } } },
    2344             :     { { { "235", 235 }, { "240", 240 }, { "240", 240 }, { "255", 255 } } },
    2345             : };
    2346             : 
    2347             : static const GraticuleLines digital9[] = {
    2348             :     { { {  "32",  32 }, {  "32",  32 }, {  "32",  32 }, {   "0",   0 } } },
    2349             :     { { { "256", 256 }, { "256", 256 }, { "256", 256 }, { "256", 256 } } },
    2350             :     { { { "470", 470 }, { "480", 480 }, { "480", 480 }, { "511", 511 } } },
    2351             : };
    2352             : 
    2353             : static const GraticuleLines digital10[] = {
    2354             :     { { {  "64",  64 }, {  "64",  64 }, {  "64",  64 }, {    "0",    0 } } },
    2355             :     { { { "512", 512 }, { "512", 512 }, { "512", 512 }, {  "512",  512 } } },
    2356             :     { { { "940", 940 }, { "960", 960 }, { "960", 960 }, { "1023", 1023 } } },
    2357             : };
    2358             : 
    2359             : static const GraticuleLines digital12[] = {
    2360             :     { { {  "256",  256 }, {  "256",  256 }, {  "256",  256 }, {    "0",    0 } } },
    2361             :     { { { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 } } },
    2362             :     { { { "3760", 3760 }, { "3840", 3840 }, { "3840", 3840 }, { "4095", 4095 } } },
    2363             : };
    2364             : 
    2365             : static const GraticuleLines millivolts8[] = {
    2366             :     { { {   "0",  16 }, {   "0",  16 }, {   "0",  16 }, {   "0",   0 } } },
    2367             :     { { { "175",  71 }, { "175",  72 }, { "175",  72 }, { "175",  64 } } },
    2368             :     { { { "350", 126 }, { "350", 128 }, { "350", 128 }, { "350", 128 } } },
    2369             :     { { { "525", 180 }, { "525", 184 }, { "525", 184 }, { "525", 192 } } },
    2370             :     { { { "700", 235 }, { "700", 240 }, { "700", 240 }, { "700", 255 } } },
    2371             : };
    2372             : 
    2373             : static const GraticuleLines millivolts9[] = {
    2374             :     { { {   "0",  32 }, {   "0",  32 }, {   "0",  32 }, {   "0",   0 } } },
    2375             :     { { { "175", 142 }, { "175", 144 }, { "175", 144 }, { "175", 128 } } },
    2376             :     { { { "350", 251 }, { "350", 256 }, { "350", 256 }, { "350", 256 } } },
    2377             :     { { { "525", 361 }, { "525", 368 }, { "525", 368 }, { "525", 384 } } },
    2378             :     { { { "700", 470 }, { "700", 480 }, { "700", 480 }, { "700", 511 } } },
    2379             : };
    2380             : 
    2381             : static const GraticuleLines millivolts10[] = {
    2382             :     { { {   "0",  64 }, {   "0",  64 }, {   "0",  64 }, {   "0",    0 } } },
    2383             :     { { { "175", 283 }, { "175", 288 }, { "175", 288 }, { "175",  256 } } },
    2384             :     { { { "350", 502 }, { "350", 512 }, { "350", 512 }, { "350",  512 } } },
    2385             :     { { { "525", 721 }, { "525", 736 }, { "525", 736 }, { "525",  768 } } },
    2386             :     { { { "700", 940 }, { "700", 960 }, { "700", 960 }, { "700", 1023 } } },
    2387             : };
    2388             : 
    2389             : static const GraticuleLines millivolts12[] = {
    2390             :     { { {   "0",  256 }, {   "0",  256 }, {   "0",  256 }, {   "0",    0 } } },
    2391             :     { { { "175", 1132 }, { "175", 1152 }, { "175", 1152 }, { "175", 1024 } } },
    2392             :     { { { "350", 2008 }, { "350", 2048 }, { "350", 2048 }, { "350", 2048 } } },
    2393             :     { { { "525", 2884 }, { "525", 2944 }, { "525", 2944 }, { "525", 3072 } } },
    2394             :     { { { "700", 3760 }, { "700", 3840 }, { "700", 3840 }, { "700", 4095 } } },
    2395             : };
    2396             : 
    2397             : static const GraticuleLines ire8[] = {
    2398             :     { { {   "0",  16 }, {   "0",  16 }, {   "0",  16 }, {   "0",   0 } } },
    2399             :     { { {  "25",  71 }, {  "25",  72 }, {  "25",  72 }, {  "25",  64 } } },
    2400             :     { { {  "50", 126 }, {  "50", 128 }, {  "50", 128 }, {  "50", 128 } } },
    2401             :     { { {  "75", 180 }, {  "75", 184 }, {  "75", 184 }, {  "75", 192 } } },
    2402             :     { { { "100", 235 }, { "100", 240 }, { "100", 240 }, { "100", 255 } } },
    2403             : };
    2404             : 
    2405             : static const GraticuleLines ire9[] = {
    2406             :     { { {   "0",  32 }, {   "0",  32 }, {   "0",  32 }, {   "0",   0 } } },
    2407             :     { { {  "25", 142 }, {  "25", 144 }, {  "25", 144 }, {  "25", 128 } } },
    2408             :     { { {  "50", 251 }, {  "50", 256 }, {  "50", 256 }, {  "50", 256 } } },
    2409             :     { { {  "75", 361 }, {  "75", 368 }, {  "75", 368 }, {  "75", 384 } } },
    2410             :     { { { "100", 470 }, { "100", 480 }, { "100", 480 }, { "100", 511 } } },
    2411             : };
    2412             : 
    2413             : static const GraticuleLines ire10[] = {
    2414             :     { { {   "0",  64 }, {   "0",  64 }, {  "0",   64 }, {   "0",    0 } } },
    2415             :     { { {  "25", 283 }, {  "25", 288 }, {  "25", 288 }, {  "25",  256 } } },
    2416             :     { { {  "50", 502 }, {  "50", 512 }, {  "50", 512 }, {  "50",  512 } } },
    2417             :     { { {  "75", 721 }, {  "75", 736 }, {  "75", 736 }, {  "75",  768 } } },
    2418             :     { { { "100", 940 }, { "100", 960 }, { "100", 960 }, { "100", 1023 } } },
    2419             : };
    2420             : 
    2421             : static const GraticuleLines ire12[] = {
    2422             :     { { {   "0",  256 }, {   "0",  256 }, {   "0",  256 }, {   "0",    0 } } },
    2423             :     { { {  "25", 1132 }, {  "25", 1152 }, {  "25", 1152 }, {  "25", 1024 } } },
    2424             :     { { {  "50", 2008 }, {  "50", 2048 }, {  "50", 2048 }, {  "50", 2048 } } },
    2425             :     { { {  "75", 2884 }, {  "75", 2944 }, {  "75", 2944 }, {  "75", 3072 } } },
    2426             :     { { { "100", 3760 }, { "100", 3840 }, { "100", 3840 }, { "100", 4095 } } },
    2427             : };
    2428             : 
    2429             : static const GraticuleLines chroma_digital8[] = {
    2430             :     { { {  "50",  50 }, {  "50",  50 }, {  "50",  50 }, {  "50",  50 } } },
    2431             :     { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
    2432             :     { { { "150", 150 }, { "150", 150 }, { "150", 150 }, { "150", 150 } } },
    2433             :     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
    2434             :     { { { "255", 255 }, { "255", 255 }, { "255", 255 }, { "255", 255 } } },
    2435             : };
    2436             : 
    2437             : static const GraticuleLines chroma_digital9[] = {
    2438             :     { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
    2439             :     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
    2440             :     { { { "300", 300 }, { "300", 300 }, { "300", 300 }, { "300", 300 } } },
    2441             :     { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
    2442             :     { { { "500", 500 }, { "500", 500 }, { "500", 500 }, { "500", 500 } } },
    2443             : };
    2444             : 
    2445             : static const GraticuleLines chroma_digital10[] = {
    2446             :     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
    2447             :     { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
    2448             :     { { { "600", 600 }, { "600", 600 }, { "600", 600 }, { "600", 600 } } },
    2449             :     { { { "800", 800 }, { "800", 800 }, { "800", 800 }, { "800", 800 } } },
    2450             :     { { {"1000",1000 }, {"1000",1000 }, {"1000",1000 }, {"1000",1000 } } },
    2451             : };
    2452             : 
    2453             : static const GraticuleLines chroma_digital12[] = {
    2454             :     { { {  "800",  800 }, {  "800",  800 }, {  "800",  800 }, {  "800",  800 } } },
    2455             :     { { { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 } } },
    2456             :     { { { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 } } },
    2457             :     { { { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 } } },
    2458             :     { { { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 } } },
    2459             : };
    2460             : 
    2461           0 : static void blend_vline(uint8_t *dst, int height, int linesize, float o1, float o2, int v, int step)
    2462             : {
    2463             :     int y;
    2464             : 
    2465           0 :     for (y = 0; y < height; y += step) {
    2466           0 :         dst[0] = v * o1 + dst[0] * o2;
    2467             : 
    2468           0 :         dst += linesize * step;
    2469             :     }
    2470           0 : }
    2471             : 
    2472           0 : static void blend_vline16(uint16_t *dst, int height, int linesize, float o1, float o2, int v, int step)
    2473             : {
    2474             :     int y;
    2475             : 
    2476           0 :     for (y = 0; y < height; y += step) {
    2477           0 :         dst[0] = v * o1 + dst[0] * o2;
    2478             : 
    2479           0 :         dst += (linesize / 2) * step;
    2480             :     }
    2481           0 : }
    2482             : 
    2483           0 : static void blend_hline(uint8_t *dst, int width, float o1, float o2, int v, int step)
    2484             : {
    2485             :     int x;
    2486             : 
    2487           0 :     for (x = 0; x < width; x += step) {
    2488           0 :         dst[x] = v * o1 + dst[x] * o2;
    2489             :     }
    2490           0 : }
    2491             : 
    2492           0 : static void blend_hline16(uint16_t *dst, int width, float o1, float o2, int v, int step)
    2493             : {
    2494             :     int x;
    2495             : 
    2496           0 :     for (x = 0; x < width; x += step) {
    2497           0 :         dst[x] = v * o1 + dst[x] * o2;
    2498             :     }
    2499           0 : }
    2500             : 
    2501           0 : static void draw_htext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
    2502             : {
    2503             :     const uint8_t *font;
    2504             :     int font_height;
    2505             :     int i, plane;
    2506             : 
    2507           0 :     font = avpriv_cga_font,   font_height =  8;
    2508             : 
    2509           0 :     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
    2510           0 :         for (i = 0; txt[i]; i++) {
    2511             :             int char_y, mask;
    2512           0 :             int v = color[plane];
    2513             : 
    2514           0 :             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
    2515           0 :             for (char_y = 0; char_y < font_height; char_y++) {
    2516           0 :                 for (mask = 0x80; mask; mask >>= 1) {
    2517           0 :                     if (font[txt[i] * font_height + char_y] & mask)
    2518           0 :                         p[0] = p[0] * o2 + v * o1;
    2519           0 :                     p++;
    2520             :                 }
    2521           0 :                 p += out->linesize[plane] - 8;
    2522             :             }
    2523             :         }
    2524             :     }
    2525           0 : }
    2526             : 
    2527           0 : static void draw_htext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
    2528             : {
    2529             :     const uint8_t *font;
    2530             :     int font_height;
    2531             :     int i, plane;
    2532             : 
    2533           0 :     font = avpriv_cga_font,   font_height =  8;
    2534             : 
    2535           0 :     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
    2536           0 :         for (i = 0; txt[i]; i++) {
    2537             :             int char_y, mask;
    2538           0 :             int v = color[plane] * mult;
    2539             : 
    2540           0 :             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
    2541           0 :             for (char_y = 0; char_y < font_height; char_y++) {
    2542           0 :                 for (mask = 0x80; mask; mask >>= 1) {
    2543           0 :                     if (font[txt[i] * font_height + char_y] & mask)
    2544           0 :                         p[0] = p[0] * o2 + v * o1;
    2545           0 :                     p++;
    2546             :                 }
    2547           0 :                 p += out->linesize[plane] / 2 - 8;
    2548             :             }
    2549             :         }
    2550             :     }
    2551           0 : }
    2552             : 
    2553           0 : static void draw_vtext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
    2554             : {
    2555             :     const uint8_t *font;
    2556             :     int font_height;
    2557             :     int i, plane;
    2558             : 
    2559           0 :     font = avpriv_cga_font,   font_height =  8;
    2560             : 
    2561           0 :     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
    2562           0 :         for (i = 0; txt[i]; i++) {
    2563             :             int char_y, mask;
    2564           0 :             int v = color[plane];
    2565             : 
    2566           0 :             for (char_y = font_height - 1; char_y >= 0; char_y--) {
    2567           0 :                 uint8_t *p = out->data[plane] + (y + i * 10) * out->linesize[plane] + x;
    2568           0 :                 for (mask = 0x80; mask; mask >>= 1) {
    2569           0 :                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
    2570           0 :                         p[char_y] = p[char_y] * o2 + v * o1;
    2571           0 :                     p += out->linesize[plane];
    2572             :                 }
    2573             :             }
    2574             :         }
    2575             :     }
    2576           0 : }
    2577             : 
    2578           0 : static void draw_vtext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
    2579             : {
    2580             :     const uint8_t *font;
    2581             :     int font_height;
    2582             :     int i, plane;
    2583             : 
    2584           0 :     font = avpriv_cga_font,   font_height =  8;
    2585             : 
    2586           0 :     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
    2587           0 :         for (i = 0; txt[i]; i++) {
    2588             :             int char_y, mask;
    2589           0 :             int v = color[plane] * mult;
    2590             : 
    2591           0 :             for (char_y = 0; char_y < font_height; char_y++) {
    2592           0 :                 uint16_t *p = (uint16_t *)(out->data[plane] + (y + i * 10) * out->linesize[plane]) + x;
    2593           0 :                 for (mask = 0x80; mask; mask >>= 1) {
    2594           0 :                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
    2595           0 :                         p[char_y] = p[char_y] * o2 + v * o1;
    2596           0 :                     p += out->linesize[plane] / 2;
    2597             :                 }
    2598             :             }
    2599             :         }
    2600             :     }
    2601           0 : }
    2602             : 
    2603         200 : static void graticule_none(WaveformContext *s, AVFrame *out)
    2604             : {
    2605         200 : }
    2606             : 
    2607           0 : static void graticule_row(WaveformContext *s, AVFrame *out)
    2608             : {
    2609           0 :     const int step = (s->flags & 2) + 1;
    2610           0 :     const float o1 = s->opacity;
    2611           0 :     const float o2 = 1. - o1;
    2612           0 :     const int height = s->display == PARADE ? out->height / s->acomp : out->height;
    2613           0 :     int k = 0, c, p, l, offset_x = 0, offset_y = 0;
    2614             : 
    2615           0 :     for (c = 0; c < s->ncomp; c++) {
    2616           0 :         if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
    2617           0 :             continue;
    2618             : 
    2619           0 :         k++;
    2620           0 :         for (p = 0; p < s->ncomp; p++) {
    2621           0 :             const int v = s->grat_yuva_color[p];
    2622           0 :             for (l = 0; l < s->nb_glines; l++) {
    2623           0 :                 const uint16_t pos = s->glines[l].line[c].pos;
    2624           0 :                 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
    2625           0 :                 uint8_t *dst = out->data[p] + offset_y * out->linesize[p] + x;
    2626             : 
    2627           0 :                 blend_vline(dst, height, out->linesize[p], o1, o2, v, step);
    2628             :             }
    2629             :         }
    2630             : 
    2631           0 :         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
    2632           0 :             const char *name = s->glines[l].line[c].name;
    2633           0 :             const uint16_t pos = s->glines[l].line[c].pos;
    2634           0 :             int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
    2635             : 
    2636           0 :             if (x < 0)
    2637           0 :                 x = 4;
    2638             : 
    2639           0 :             draw_vtext(out, x, offset_y + 2, o1, o2, name, s->grat_yuva_color);
    2640             :         }
    2641             : 
    2642           0 :         offset_x += s->size * (s->display == STACK);
    2643           0 :         offset_y += height * (s->display == PARADE);
    2644             :     }
    2645           0 : }
    2646             : 
    2647           0 : static void graticule16_row(WaveformContext *s, AVFrame *out)
    2648             : {
    2649           0 :     const int step = (s->flags & 2) + 1;
    2650           0 :     const float o1 = s->opacity;
    2651           0 :     const float o2 = 1. - o1;
    2652           0 :     const int mult = s->max / 256;
    2653           0 :     const int height = s->display == PARADE ? out->height / s->acomp : out->height;
    2654           0 :     int k = 0, c, p, l, offset_x = 0, offset_y = 0;
    2655             : 
    2656           0 :     for (c = 0; c < s->ncomp; c++) {
    2657           0 :         if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
    2658           0 :             continue;
    2659             : 
    2660           0 :         k++;
    2661           0 :         for (p = 0; p < s->ncomp; p++) {
    2662           0 :             const int v = s->grat_yuva_color[p] * mult;
    2663           0 :             for (l = 0; l < s->nb_glines ; l++) {
    2664           0 :                 const uint16_t pos = s->glines[l].line[c].pos;
    2665           0 :                 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
    2666           0 :                 uint16_t *dst = (uint16_t *)(out->data[p] + offset_y * out->linesize[p]) + x;
    2667             : 
    2668           0 :                 blend_vline16(dst, height, out->linesize[p], o1, o2, v, step);
    2669             :             }
    2670             :         }
    2671             : 
    2672           0 :         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
    2673           0 :             const char *name = s->glines[l].line[c].name;
    2674           0 :             const uint16_t pos = s->glines[l].line[c].pos;
    2675           0 :             int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
    2676             : 
    2677           0 :             if (x < 0)
    2678           0 :                 x = 4;
    2679             : 
    2680           0 :             draw_vtext16(out, x, offset_y + 2, mult, o1, o2, name, s->grat_yuva_color);
    2681             :         }
    2682             : 
    2683           0 :         offset_x += s->size * (s->display == STACK);
    2684           0 :         offset_y += height * (s->display == PARADE);
    2685             :     }
    2686           0 : }
    2687             : 
    2688           0 : static void graticule_column(WaveformContext *s, AVFrame *out)
    2689             : {
    2690           0 :     const int step = (s->flags & 2) + 1;
    2691           0 :     const float o1 = s->opacity;
    2692           0 :     const float o2 = 1. - o1;
    2693           0 :     const int width = s->display == PARADE ? out->width / s->acomp : out->width;
    2694           0 :     int k = 0, c, p, l, offset_y = 0, offset_x = 0;
    2695             : 
    2696           0 :     for (c = 0; c < s->ncomp; c++) {
    2697           0 :         if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
    2698           0 :             continue;
    2699             : 
    2700           0 :         k++;
    2701           0 :         for (p = 0; p < s->ncomp; p++) {
    2702           0 :             const int v = s->grat_yuva_color[p];
    2703           0 :             for (l = 0; l < s->nb_glines ; l++) {
    2704           0 :                 const uint16_t pos = s->glines[l].line[c].pos;
    2705           0 :                 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
    2706           0 :                 uint8_t *dst = out->data[p] + y * out->linesize[p] + offset_x;
    2707             : 
    2708           0 :                 blend_hline(dst, width, o1, o2, v, step);
    2709             :             }
    2710             :         }
    2711             : 
    2712           0 :         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
    2713           0 :             const char *name = s->glines[l].line[c].name;
    2714           0 :             const uint16_t pos = s->glines[l].line[c].pos;
    2715           0 :             int y = offset_y + (s->mirror ? s->size - 1 - pos : pos) - 10;
    2716             : 
    2717           0 :             if (y < 0)
    2718           0 :                 y = 4;
    2719             : 
    2720           0 :             draw_htext(out, 2 + offset_x, y, o1, o2, name, s->grat_yuva_color);
    2721             :         }
    2722             : 
    2723           0 :         offset_y += s->size * (s->display == STACK);
    2724           0 :         offset_x += width * (s->display == PARADE);
    2725             :     }
    2726           0 : }
    2727             : 
    2728           0 : static void graticule16_column(WaveformContext *s, AVFrame *out)
    2729             : {
    2730           0 :     const int step = (s->flags & 2) + 1;
    2731           0 :     const float o1 = s->opacity;
    2732           0 :     const float o2 = 1. - o1;
    2733           0 :     const int mult = s->max / 256;
    2734           0 :     const int width = s->display == PARADE ? out->width / s->acomp : out->width;
    2735           0 :     int k = 0, c, p, l, offset_x = 0, offset_y = 0;
    2736             : 
    2737           0 :     for (c = 0; c < s->ncomp; c++) {
    2738           0 :         if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
    2739           0 :             continue;
    2740             : 
    2741           0 :         k++;
    2742           0 :         for (p = 0; p < s->ncomp; p++) {
    2743           0 :             const int v = s->grat_yuva_color[p] * mult;
    2744           0 :             for (l = 0; l < s->nb_glines ; l++) {
    2745           0 :                 const uint16_t pos = s->glines[l].line[c].pos;
    2746           0 :                 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
    2747           0 :                 uint16_t *dst = (uint16_t *)(out->data[p] + y * out->linesize[p]) + offset_x;
    2748             : 
    2749           0 :                 blend_hline16(dst, width, o1, o2, v, step);
    2750             :             }
    2751             :         }
    2752             : 
    2753           0 :         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
    2754           0 :             const char *name = s->glines[l].line[c].name;
    2755           0 :             const uint16_t pos = s->glines[l].line[c].pos;
    2756           0 :             int y = offset_y + (s->mirror ? s->size - 1 - pos: pos) - 10;
    2757             : 
    2758           0 :             if (y < 0)
    2759           0 :                 y = 4;
    2760             : 
    2761           0 :             draw_htext16(out, 2 + offset_x, y, mult, o1, o2, name, s->grat_yuva_color);
    2762             :         }
    2763             : 
    2764           0 :         offset_y += s->size * (s->display == STACK);
    2765           0 :         offset_x += width * (s->display == PARADE);
    2766             :     }
    2767           0 : }
    2768             : 
    2769           4 : static int config_input(AVFilterLink *inlink)
    2770             : {
    2771           4 :     AVFilterContext *ctx = inlink->dst;
    2772           4 :     WaveformContext *s = ctx->priv;
    2773             : 
    2774           4 :     s->desc  = av_pix_fmt_desc_get(inlink->format);
    2775           4 :     s->ncomp = s->desc->nb_components;
    2776           4 :     s->bits = s->desc->comp[0].depth;
    2777           4 :     s->max = 1 << s->bits;
    2778           4 :     s->intensity = s->fintensity * (s->max - 1);
    2779             : 
    2780           4 :     s->shift_w[0] = s->shift_w[3] = 0;
    2781           4 :     s->shift_h[0] = s->shift_h[3] = 0;
    2782           4 :     s->shift_w[1] = s->shift_w[2] = s->desc->log2_chroma_w;
    2783           4 :     s->shift_h[1] = s->shift_h[2] = s->desc->log2_chroma_h;
    2784             : 
    2785           4 :     s->graticulef = graticule_none;
    2786             : 
    2787           4 :     switch (s->filter) {
    2788           0 :     case XFLAT:
    2789           0 :     case AFLAT: s->size = 256 * 2; break;
    2790           0 :     case FLAT:  s->size = 256 * 3; break;
    2791           4 :     default:    s->size = 256;     break;
    2792             :     }
    2793             : 
    2794          12 :     switch (s->filter | ((s->bits > 8) << 4) |
    2795           8 :             (s->mode << 8) | (s->mirror << 12)) {
    2796           3 :     case 0x1100: s->waveform_slice = lowpass_column_mirror; break;
    2797           1 :     case 0x1000: s->waveform_slice = lowpass_row_mirror;    break;
    2798           0 :     case 0x0100: s->waveform_slice = lowpass_column;        break;
    2799           0 :     case 0x0000: s->waveform_slice = lowpass_row;           break;
    2800           0 :     case 0x1110: s->waveform_slice = lowpass16_column_mirror; break;
    2801           0 :     case 0x1010: s->waveform_slice = lowpass16_row_mirror;    break;
    2802           0 :     case 0x0110: s->waveform_slice = lowpass16_column;        break;
    2803           0 :     case 0x0010: s->waveform_slice = lowpass16_row;           break;
    2804           0 :     case 0x1101: s->waveform_slice = flat_column_mirror; break;
    2805           0 :     case 0x1001: s->waveform_slice = flat_row_mirror;    break;
    2806           0 :     case 0x0101: s->waveform_slice = flat_column;        break;
    2807           0 :     case 0x0001: s->waveform_slice = flat_row;           break;
    2808           0 :     case 0x1111: s->waveform_slice = flat16_column_mirror; break;
    2809           0 :     case 0x1011: s->waveform_slice = flat16_row_mirror;    break;
    2810           0 :     case 0x0111: s->waveform_slice = flat16_column;        break;
    2811           0 :     case 0x0011: s->waveform_slice = flat16_row;           break;
    2812           0 :     case 0x1102: s->waveform_slice = aflat_column_mirror; break;
    2813           0 :     case 0x1002: s->waveform_slice = aflat_row_mirror;    break;
    2814           0 :     case 0x0102: s->waveform_slice = aflat_column;        break;
    2815           0 :     case 0x0002: s->waveform_slice = aflat_row;           break;
    2816           0 :     case 0x1112: s->waveform_slice = aflat16_column_mirror; break;
    2817           0 :     case 0x1012: s->waveform_slice = aflat16_row_mirror;    break;
    2818           0 :     case 0x0112: s->waveform_slice = aflat16_column;        break;
    2819           0 :     case 0x0012: s->waveform_slice = aflat16_row;           break;
    2820           0 :     case 0x1103: s->waveform_slice = chroma_column_mirror; break;
    2821           0 :     case 0x1003: s->waveform_slice = chroma_row_mirror;    break;
    2822           0 :     case 0x0103: s->waveform_slice = chroma_column;        break;
    2823           0 :     case 0x0003: s->waveform_slice = chroma_row;           break;
    2824           0 :     case 0x1113: s->waveform_slice = chroma16_column_mirror; break;
    2825           0 :     case 0x1013: s->waveform_slice = chroma16_row_mirror;    break;
    2826           0 :     case 0x0113: s->waveform_slice = chroma16_column;        break;
    2827           0 :     case 0x0013: s->waveform_slice = chroma16_row;           break;
    2828           0 :     case 0x1104: s->waveform_slice = color_column_mirror; break;
    2829           0 :     case 0x1004: s->waveform_slice = color_row_mirror;    break;
    2830           0 :     case 0x0104: s->waveform_slice = color_column;        break;
    2831           0 :     case 0x0004: s->waveform_slice = color_row;           break;
    2832           0 :     case 0x1114: s->waveform_slice = color16_column_mirror; break;
    2833           0 :     case 0x1014: s->waveform_slice = color16_row_mirror;    break;
    2834           0 :     case 0x0114: s->waveform_slice = color16_column;        break;
    2835           0 :     case 0x0014: s->waveform_slice = color16_row;           break;
    2836           0 :     case 0x1105: s->waveform_slice = acolor_column_mirror; break;
    2837           0 :     case 0x1005: s->waveform_slice = acolor_row_mirror;    break;
    2838           0 :     case 0x0105: s->waveform_slice = acolor_column;        break;
    2839           0 :     case 0x0005: s->waveform_slice = acolor_row;           break;
    2840           0 :     case 0x1115: s->waveform_slice = acolor16_column_mirror; break;
    2841           0 :     case 0x1015: s->waveform_slice = acolor16_row_mirror;    break;
    2842           0 :     case 0x0115: s->waveform_slice = acolor16_column;        break;
    2843           0 :     case 0x0015: s->waveform_slice = acolor16_row;           break;
    2844           0 :     case 0x1106: s->waveform_slice = xflat_column_mirror; break;
    2845           0 :     case 0x1006: s->waveform_slice = xflat_row_mirror;    break;
    2846           0 :     case 0x0106: s->waveform_slice = xflat_column;        break;
    2847           0 :     case 0x0006: s->waveform_slice = xflat_row;           break;
    2848           0 :     case 0x1116: s->waveform_slice = xflat16_column_mirror; break;
    2849           0 :     case 0x1016: s->waveform_slice = xflat16_row_mirror;    break;
    2850           0 :     case 0x0116: s->waveform_slice = xflat16_column;        break;
    2851           0 :     case 0x0016: s->waveform_slice = xflat16_row;           break;
    2852             :     }
    2853             : 
    2854           4 :     s->grat_yuva_color[0] = 255;
    2855           4 :     s->grat_yuva_color[2] = s->graticule == 2 ? 255 : 0;
    2856           4 :     s->grat_yuva_color[3] = 255;
    2857             : 
    2858           4 :     switch (s->filter) {
    2859           4 :     case LOWPASS:
    2860             :     case COLOR:
    2861             :     case ACOLOR:
    2862             :     case CHROMA:
    2863             :     case AFLAT:
    2864             :     case XFLAT:
    2865             :     case FLAT:
    2866           4 :         if (s->graticule && s->mode == 1)
    2867           0 :             s->graticulef = s->bits > 8 ? graticule16_column : graticule_column;
    2868           4 :         else if (s->graticule && s->mode == 0)
    2869           0 :             s->graticulef = s->bits > 8 ? graticule16_row : graticule_row;
    2870           4 :         break;
    2871             :     }
    2872             : 
    2873           4 :     switch (s->filter) {
    2874           4 :     case COLOR:
    2875             :     case ACOLOR:
    2876             :     case LOWPASS:
    2877           4 :         switch (s->scale) {
    2878           4 :         case DIGITAL:
    2879           4 :             switch (s->bits) {
    2880           4 :             case  8: s->glines = (GraticuleLines *)digital8;  s->nb_glines = FF_ARRAY_ELEMS(digital8);  break;
    2881           0 :             case  9: s->glines = (GraticuleLines *)digital9;  s->nb_glines = FF_ARRAY_ELEMS(digital9);  break;
    2882           0 :             case 10: s->glines = (GraticuleLines *)digital10; s->nb_glines = FF_ARRAY_ELEMS(digital10); break;
    2883           0 :             case 12: s->glines = (GraticuleLines *)digital12; s->nb_glines = FF_ARRAY_ELEMS(digital12); break;
    2884             :             }
    2885           4 :             break;
    2886           0 :         case MILLIVOLTS:
    2887           0 :             switch (s->bits) {
    2888           0 :             case  8: s->glines = (GraticuleLines *)millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(millivolts8);  break;
    2889           0 :             case  9: s->glines = (GraticuleLines *)millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(millivolts9);  break;
    2890           0 :             case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
    2891           0 :             case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
    2892             :             }
    2893           0 :             break;
    2894           0 :         case IRE:
    2895           0 :             switch (s->bits) {
    2896           0 :             case  8: s->glines = (GraticuleLines *)ire8;  s->nb_glines = FF_ARRAY_ELEMS(ire8);  break;
    2897           0 :             case  9: s->glines = (GraticuleLines *)ire9;  s->nb_glines = FF_ARRAY_ELEMS(ire9);  break;
    2898           0 :             case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
    2899           0 :             case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
    2900             :             }
    2901           0 :             break;
    2902             :         }
    2903           4 :         break;
    2904           0 :     case CHROMA:
    2905           0 :         switch (s->scale) {
    2906           0 :         case DIGITAL:
    2907           0 :             switch (s->bits) {
    2908           0 :             case  8: s->glines = (GraticuleLines *)chroma_digital8;  s->nb_glines = FF_ARRAY_ELEMS(chroma_digital8);  break;
    2909           0 :             case  9: s->glines = (GraticuleLines *)chroma_digital9;  s->nb_glines = FF_ARRAY_ELEMS(chroma_digital9);  break;
    2910           0 :             case 10: s->glines = (GraticuleLines *)chroma_digital10; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital10); break;
    2911           0 :             case 12: s->glines = (GraticuleLines *)chroma_digital12; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital12); break;
    2912             :             }
    2913           0 :             break;
    2914           0 :         case MILLIVOLTS:
    2915           0 :             switch (s->bits) {
    2916           0 :             case  8: s->glines = (GraticuleLines *)millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(millivolts8);  break;
    2917           0 :             case  9: s->glines = (GraticuleLines *)millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(millivolts9);  break;
    2918           0 :             case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
    2919           0 :             case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
    2920             :             }
    2921           0 :             break;
    2922           0 :         case IRE:
    2923           0 :             switch (s->bits) {
    2924           0 :             case  8: s->glines = (GraticuleLines *)ire8;  s->nb_glines = FF_ARRAY_ELEMS(ire8);  break;
    2925           0 :             case  9: s->glines = (GraticuleLines *)ire9;  s->nb_glines = FF_ARRAY_ELEMS(ire9);  break;
    2926           0 :             case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
    2927           0 :             case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
    2928             :             }
    2929           0 :             break;
    2930             :         }
    2931           0 :         break;
    2932           0 :     case XFLAT:
    2933             :     case AFLAT:
    2934           0 :         switch (s->scale) {
    2935           0 :         case DIGITAL:
    2936           0 :             switch (s->bits) {
    2937           0 :             case  8: s->glines = (GraticuleLines *)aflat_digital8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_digital8);  break;
    2938           0 :             case  9: s->glines = (GraticuleLines *)aflat_digital9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_digital9);  break;
    2939           0 :             case 10: s->glines = (GraticuleLines *)aflat_digital10; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital10); break;
    2940           0 :             case 12: s->glines = (GraticuleLines *)aflat_digital12; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital12); break;
    2941             :             }
    2942           0 :             break;
    2943           0 :         case MILLIVOLTS:
    2944           0 :             switch (s->bits) {
    2945           0 :             case  8: s->glines = (GraticuleLines *)aflat_millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts8);  break;
    2946           0 :             case  9: s->glines = (GraticuleLines *)aflat_millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts9);  break;
    2947           0 :             case 10: s->glines = (GraticuleLines *)aflat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts10); break;
    2948           0 :             case 12: s->glines = (GraticuleLines *)aflat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts12); break;
    2949             :             }
    2950           0 :             break;
    2951           0 :         case IRE:
    2952           0 :             switch (s->bits) {
    2953           0 :             case  8: s->glines = (GraticuleLines *)aflat_ire8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_ire8);  break;
    2954           0 :             case  9: s->glines = (GraticuleLines *)aflat_ire9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_ire9);  break;
    2955           0 :             case 10: s->glines = (GraticuleLines *)aflat_ire10; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire10); break;
    2956           0 :             case 12: s->glines = (GraticuleLines *)aflat_ire12; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire12); break;
    2957             :             }
    2958           0 :             break;
    2959             :         }
    2960           0 :         break;
    2961           0 :     case FLAT:
    2962           0 :         switch (s->scale) {
    2963           0 :         case DIGITAL:
    2964           0 :             switch (s->bits) {
    2965           0 :             case  8: s->glines = (GraticuleLines *)flat_digital8;  s->nb_glines = FF_ARRAY_ELEMS(flat_digital8);  break;
    2966           0 :             case  9: s->glines = (GraticuleLines *)flat_digital9;  s->nb_glines = FF_ARRAY_ELEMS(flat_digital9);  break;
    2967           0 :             case 10: s->glines = (GraticuleLines *)flat_digital10; s->nb_glines = FF_ARRAY_ELEMS(flat_digital10); break;
    2968           0 :             case 12: s->glines = (GraticuleLines *)flat_digital12; s->nb_glines = FF_ARRAY_ELEMS(flat_digital12); break;
    2969             :             }
    2970           0 :             break;
    2971           0 :         case MILLIVOLTS:
    2972           0 :             switch (s->bits) {
    2973           0 :             case  8: s->glines = (GraticuleLines *)flat_millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts8);  break;
    2974           0 :             case  9: s->glines = (GraticuleLines *)flat_millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts9);  break;
    2975           0 :             case 10: s->glines = (GraticuleLines *)flat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts10); break;
    2976           0 :             case 12: s->glines = (GraticuleLines *)flat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts12); break;
    2977             :             }
    2978           0 :             break;
    2979           0 :         case IRE:
    2980           0 :             switch (s->bits) {
    2981           0 :             case  8: s->glines = (GraticuleLines *)flat_ire8;  s->nb_glines = FF_ARRAY_ELEMS(flat_ire8);  break;
    2982           0 :             case  9: s->glines = (GraticuleLines *)flat_ire9;  s->nb_glines = FF_ARRAY_ELEMS(flat_ire9);  break;
    2983           0 :             case 10: s->glines = (GraticuleLines *)flat_ire10; s->nb_glines = FF_ARRAY_ELEMS(flat_ire10); break;
    2984           0 :             case 12: s->glines = (GraticuleLines *)flat_ire12; s->nb_glines = FF_ARRAY_ELEMS(flat_ire12); break;
    2985             :             }
    2986           0 :             break;
    2987             :         }
    2988           0 :         break;
    2989             :     }
    2990             : 
    2991           4 :     s->size = s->size << (s->bits - 8);
    2992             : 
    2993           4 :     switch (inlink->format) {
    2994           0 :     case AV_PIX_FMT_GBRAP:
    2995             :     case AV_PIX_FMT_GBRP:
    2996             :     case AV_PIX_FMT_GBRP9:
    2997             :     case AV_PIX_FMT_GBRP10:
    2998             :     case AV_PIX_FMT_GBRP12:
    2999           0 :         memcpy(s->bg_color, black_gbrp_color, sizeof(s->bg_color));
    3000           0 :         s->graticulef = graticule_none;
    3001           0 :         break;
    3002           4 :     default:
    3003           4 :         memcpy(s->bg_color, black_yuva_color, sizeof(s->bg_color));
    3004             :     }
    3005             : 
    3006           4 :     s->bg_color[3] *= s->bgopacity;
    3007             : 
    3008           4 :     return 0;
    3009             : }
    3010             : 
    3011           4 : static int config_output(AVFilterLink *outlink)
    3012             : {
    3013           4 :     AVFilterContext *ctx = outlink->src;
    3014           4 :     AVFilterLink *inlink = ctx->inputs[0];
    3015           4 :     WaveformContext *s = ctx->priv;
    3016           4 :     int comp = 0, i, j = 0, k, p, size;
    3017             : 
    3018          16 :     for (i = 0; i < s->ncomp; i++) {
    3019          12 :         if ((1 << i) & s->pcomp)
    3020           5 :             comp++;
    3021             :     }
    3022           4 :     s->acomp = comp;
    3023           4 :     s->odesc = av_pix_fmt_desc_get(outlink->format);
    3024           4 :     s->dcomp = s->odesc->nb_components;
    3025             : 
    3026           4 :     av_freep(&s->peak);
    3027             : 
    3028           4 :     if (s->mode) {
    3029           3 :         outlink->h = s->size * FFMAX(comp * (s->display == STACK), 1);
    3030           3 :         outlink->w = inlink->w * FFMAX(comp * (s->display == PARADE), 1);
    3031           3 :         size = inlink->w;
    3032             :     } else {
    3033           1 :         outlink->w = s->size * FFMAX(comp * (s->display == STACK), 1);
    3034           1 :         outlink->h = inlink->h * FFMAX(comp * (s->display == PARADE), 1);
    3035           1 :         size = inlink->h;
    3036             :     }
    3037             : 
    3038           4 :     s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
    3039           4 :     if (!s->peak)
    3040           0 :         return AVERROR(ENOMEM);
    3041             : 
    3042          16 :     for (p = 0; p < s->ncomp; p++) {
    3043          12 :         const int plane = s->desc->comp[p].plane;
    3044             :         int offset;
    3045             : 
    3046          12 :         if (!((1 << p) & s->pcomp))
    3047           7 :             continue;
    3048             : 
    3049          25 :         for (k = 0; k < 4; k++) {
    3050          20 :             s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
    3051          20 :             s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
    3052             :         }
    3053             : 
    3054           5 :         offset = j++ * s->size * (s->display == STACK);
    3055           5 :         s->estart[plane] = offset;
    3056           5 :         s->eend[plane]   = (offset + s->size - 1);
    3057        1701 :         for (i = 0; i < size; i++) {
    3058        8480 :             for (k = 0; k < 4; k++) {
    3059        6784 :                 s->emax[plane][k][i] = s->estart[plane];
    3060        6784 :                 s->emin[plane][k][i] = s->eend[plane];
    3061             :             }
    3062             :         }
    3063             :     }
    3064             : 
    3065           4 :     outlink->sample_aspect_ratio = (AVRational){1,1};
    3066             : 
    3067           4 :     return 0;
    3068             : }
    3069             : 
    3070         200 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
    3071             : {
    3072         200 :     AVFilterContext *ctx  = inlink->dst;
    3073         200 :     WaveformContext *s    = ctx->priv;
    3074         200 :     AVFilterLink *outlink = ctx->outputs[0];
    3075             :     AVFrame *out;
    3076             :     int i, j, k;
    3077             : 
    3078         200 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
    3079         200 :     if (!out) {
    3080           0 :         av_frame_free(&in);
    3081           0 :         return AVERROR(ENOMEM);
    3082             :     }
    3083         200 :     out->pts = in->pts;
    3084         200 :     out->color_range = AVCOL_RANGE_JPEG;
    3085             : 
    3086         800 :     for (k = 0; k < s->dcomp; k++) {
    3087         600 :         if (s->bits <= 8) {
    3088      197400 :             for (i = 0; i < outlink->h ; i++)
    3089      590400 :                 memset(out->data[s->odesc->comp[k].plane] +
    3090      196800 :                        i * out->linesize[s->odesc->comp[k].plane],
    3091      393600 :                        s->bg_color[k], outlink->w);
    3092             :         } else {
    3093           0 :             const int mult = s->max / 256;
    3094           0 :             uint16_t *dst = (uint16_t *)out->data[s->odesc->comp[k].plane];
    3095             : 
    3096           0 :             for (i = 0; i < outlink->h ; i++) {
    3097           0 :                 for (j = 0; j < outlink->w; j++)
    3098           0 :                     dst[j] = s->bg_color[k] * mult;
    3099           0 :                 dst += out->linesize[s->odesc->comp[k].plane] / 2;
    3100             :             }
    3101             :         }
    3102             :     }
    3103             : 
    3104         800 :     for (k = 0, i = 0; k < s->ncomp; k++) {
    3105         600 :         if ((1 << k) & s->pcomp) {
    3106         250 :             const int plane = s->desc->comp[k].plane;
    3107             :             ThreadData td;
    3108             :             int offset_y;
    3109             :             int offset_x;
    3110             : 
    3111         250 :             if (s->display == PARADE) {
    3112           0 :                 offset_x = s->mode ? i++ * inlink->w : 0;
    3113           0 :                 offset_y = s->mode ? 0 : i++ * inlink->h;
    3114             :             } else {
    3115         250 :                 offset_y = s->mode ? i++ * s->size * !!s->display : 0;
    3116         250 :                 offset_x = s->mode ? 0 : i++ * s->size * !!s->display;
    3117             :             }
    3118             : 
    3119         250 :             td.in = in;
    3120         250 :             td.out = out;
    3121         250 :             td.component = k;
    3122         250 :             td.offset_y = offset_y;
    3123         250 :             td.offset_x = offset_x;
    3124         250 :             ctx->internal->execute(ctx, s->waveform_slice, &td, NULL, ff_filter_get_nb_threads(ctx));
    3125         250 :             switch (s->filter) {
    3126         250 :             case ACOLOR:
    3127             :             case CHROMA:
    3128             :             case COLOR:
    3129             :             case LOWPASS:
    3130         250 :                 if (s->bits <= 8)
    3131         250 :                     envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
    3132             :                 else
    3133           0 :                     envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
    3134         250 :                 break;
    3135           0 :             case FLAT:
    3136           0 :                 if (s->bits <= 8) {
    3137           0 :                     envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
    3138           0 :                     envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
    3139             :                 } else {
    3140           0 :                     envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
    3141           0 :                     envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
    3142             :                 }
    3143           0 :                 break;
    3144           0 :             case AFLAT:
    3145             :             case XFLAT:
    3146           0 :                 if (s->bits <= 8) {
    3147           0 :                     envelope(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
    3148           0 :                     envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
    3149           0 :                     envelope(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
    3150             :                 } else {
    3151           0 :                     envelope16(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
    3152           0 :                     envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
    3153           0 :                     envelope16(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
    3154             :                 }
    3155           0 :                 break;
    3156             :             }
    3157             :         }
    3158             :     }
    3159         200 :     s->graticulef(s, out);
    3160             : 
    3161         200 :     av_frame_free(&in);
    3162         200 :     return ff_filter_frame(outlink, out);
    3163             : }
    3164             : 
    3165           4 : static av_cold void uninit(AVFilterContext *ctx)
    3166             : {
    3167           4 :     WaveformContext *s = ctx->priv;
    3168             : 
    3169           4 :     av_freep(&s->peak);
    3170           4 : }
    3171             : 
    3172             : static const AVFilterPad inputs[] = {
    3173             :     {
    3174             :         .name         = "default",
    3175             :         .type         = AVMEDIA_TYPE_VIDEO,
    3176             :         .filter_frame = filter_frame,
    3177             :         .config_props = config_input,
    3178             :     },
    3179             :     { NULL }
    3180             : };
    3181             : 
    3182             : static const AVFilterPad outputs[] = {
    3183             :     {
    3184             :         .name         = "default",
    3185             :         .type         = AVMEDIA_TYPE_VIDEO,
    3186             :         .config_props = config_output,
    3187             :     },
    3188             :     { NULL }
    3189             : };
    3190             : 
    3191             : AVFilter ff_vf_waveform = {
    3192             :     .name          = "waveform",
    3193             :     .description   = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
    3194             :     .priv_size     = sizeof(WaveformContext),
    3195             :     .priv_class    = &waveform_class,
    3196             :     .query_formats = query_formats,
    3197             :     .uninit        = uninit,
    3198             :     .inputs        = inputs,
    3199             :     .outputs       = outputs,
    3200             :     .flags         = AVFILTER_FLAG_SLICE_THREADS,
    3201             : };

Generated by: LCOV version 1.13