]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_vectorscope.c
avfilter/vf_vectorscope: add invert graticule
[ffmpeg] / libavfilter / vf_vectorscope.c
1 /*
2  * Copyright (c) 2015 Paul B Mahol
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "libavutil/avassert.h"
22 #include "libavutil/intreadwrite.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 enum GraticuleType {
33     GRAT_NONE,
34     GRAT_GREEN,
35     GRAT_COLOR,
36     GRAT_INVERT,
37     NB_GRATICULES
38 };
39
40 enum VectorscopeMode {
41     GRAY,
42     COLOR,
43     COLOR2,
44     COLOR3,
45     COLOR4,
46     COLOR5,
47     MODE_NB
48 };
49
50 typedef struct VectorscopeContext {
51     const AVClass *class;
52     int mode;
53     int intensity;
54     float fintensity;
55     uint16_t bg_color[4];
56     int planewidth[4];
57     int planeheight[4];
58     int hsub, vsub;
59     int x, y, pd;
60     int is_yuv;
61     int size;
62     int depth;
63     int mult;
64     int envelope;
65     int graticule;
66     float opacity;
67     float bgopacity;
68     float lthreshold;
69     float hthreshold;
70     int tmin;
71     int tmax;
72     int flags;
73     int colorspace;
74     int cs;
75     uint8_t *peak_memory;
76     uint8_t **peak;
77
78     void (*vectorscope)(struct VectorscopeContext *s,
79                         AVFrame *in, AVFrame *out, int pd);
80     void (*graticulef)(struct VectorscopeContext *s, AVFrame *out,
81                        int X, int Y, int D, int P);
82 } VectorscopeContext;
83
84 #define OFFSET(x) offsetof(VectorscopeContext, x)
85 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
86
87 static const AVOption vectorscope_options[] = {
88     { "mode", "set vectorscope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, MODE_NB-1, FLAGS, "mode"},
89     { "m",    "set vectorscope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, MODE_NB-1, FLAGS, "mode"},
90     {   "gray",   0, 0, AV_OPT_TYPE_CONST, {.i64=GRAY},   0, 0, FLAGS, "mode" },
91     {   "color",  0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR},  0, 0, FLAGS, "mode" },
92     {   "color2", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR2}, 0, 0, FLAGS, "mode" },
93     {   "color3", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR3}, 0, 0, FLAGS, "mode" },
94     {   "color4", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR4}, 0, 0, FLAGS, "mode" },
95     {   "color5", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR5}, 0, 0, FLAGS, "mode" },
96     { "x", "set color component on X axis", OFFSET(x), AV_OPT_TYPE_INT, {.i64=1}, 0, 2, FLAGS},
97     { "y", "set color component on Y axis", OFFSET(y), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, FLAGS},
98     { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.004}, 0, 1, FLAGS},
99     { "i",         "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.004}, 0, 1, FLAGS},
100     { "envelope",  "set envelope", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope"},
101     { "e",         "set envelope", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope"},
102     {   "none",         0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
103     {   "instant",      0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
104     {   "peak",         0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
105     {   "peak+instant", 0, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
106     { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=GRAT_NONE}, 0, NB_GRATICULES-1, FLAGS, "graticule"},
107     { "g",         "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=GRAT_NONE}, 0, NB_GRATICULES-1, FLAGS, "graticule"},
108     {   "none",         0, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_NONE},  0, 0, FLAGS, "graticule" },
109     {   "green",        0, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_GREEN}, 0, 0, FLAGS, "graticule" },
110     {   "color",        0, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_COLOR}, 0, 0, FLAGS, "graticule" },
111     {   "invert",       0, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_INVERT},0, 0, FLAGS, "graticule" },
112     { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS},
113     { "o",       "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS},
114     { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=4}, 0, 7, FLAGS, "flags"},
115     { "f",     "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=4}, 0, 7, FLAGS, "flags"},
116     {   "white", "draw white point", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "flags" },
117     {   "black", "draw black point", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
118     {   "name",  "draw point name",  0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, FLAGS, "flags" },
119     { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS},
120     { "b",         "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS},
121     { "lthreshold", "set low threshold",  OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS},
122     { "l",          "set low threshold",  OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS},
123     { "hthreshold", "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS},
124     { "h",          "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS},
125     { "colorspace", "set colorspace", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "colorspace"},
126     { "c",          "set colorspace", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "colorspace"},
127     {   "auto",       0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "colorspace" },
128     {   "601",        0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "colorspace" },
129     {   "709",        0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "colorspace" },
130     { NULL }
131 };
132
133 AVFILTER_DEFINE_CLASS(vectorscope);
134
135 static const enum AVPixelFormat out_yuv8_pix_fmts[] = {
136     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P,
137     AV_PIX_FMT_NONE
138 };
139
140 static const enum AVPixelFormat out_yuv9_pix_fmts[] = {
141     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUV444P9,
142     AV_PIX_FMT_NONE
143 };
144
145 static const enum AVPixelFormat out_yuv10_pix_fmts[] = {
146     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUV444P10,
147     AV_PIX_FMT_NONE
148 };
149
150 static const enum AVPixelFormat out_yuv12_pix_fmts[] = {
151     AV_PIX_FMT_YUV444P12,
152     AV_PIX_FMT_NONE
153 };
154
155 static const enum AVPixelFormat out_rgb8_pix_fmts[] = {
156     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
157     AV_PIX_FMT_NONE
158 };
159
160 static const enum AVPixelFormat out_rgb9_pix_fmts[] = {
161     AV_PIX_FMT_GBRP9,
162     AV_PIX_FMT_NONE
163 };
164
165 static const enum AVPixelFormat out_rgb10_pix_fmts[] = {
166     AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
167     AV_PIX_FMT_NONE
168 };
169
170 static const enum AVPixelFormat out_rgb12_pix_fmts[] = {
171     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
172     AV_PIX_FMT_NONE
173 };
174
175 static const enum AVPixelFormat in1_pix_fmts[] = {
176     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
177     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
178     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10,
179     AV_PIX_FMT_YUV444P12,
180     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
181     AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
182     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
183     AV_PIX_FMT_NONE
184 };
185
186 static const enum AVPixelFormat in2_pix_fmts[] = {
187     AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
188     AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
189     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
190     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUVJ411P,
191     AV_PIX_FMT_YUV440P,  AV_PIX_FMT_YUV410P,
192     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
193     AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
194     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
195     AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
196     AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
197     AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
198     AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
199     AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
200     AV_PIX_FMT_NONE
201 };
202
203 static int query_formats(AVFilterContext *ctx)
204 {
205     VectorscopeContext *s = ctx->priv;
206     const enum AVPixelFormat *out_pix_fmts;
207     const AVPixFmtDescriptor *desc;
208     AVFilterFormats *avff;
209     int depth, rgb, i, ret;
210
211     if (!ctx->inputs[0]->in_formats ||
212         !ctx->inputs[0]->in_formats->nb_formats) {
213         return AVERROR(EAGAIN);
214     }
215
216     if (!ctx->inputs[0]->out_formats) {
217         const enum AVPixelFormat *in_pix_fmts;
218
219         if ((s->x == 1 && s->y == 2) || (s->x == 2 && s->y == 1))
220             in_pix_fmts = in2_pix_fmts;
221         else
222             in_pix_fmts = in1_pix_fmts;
223         if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->out_formats)) < 0)
224             return ret;
225     }
226
227     avff = ctx->inputs[0]->in_formats;
228     desc = av_pix_fmt_desc_get(avff->formats[0]);
229     rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
230     depth = desc->comp[0].depth;
231     for (i = 1; i < avff->nb_formats; i++) {
232         desc = av_pix_fmt_desc_get(avff->formats[i]);
233         if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
234             depth != desc->comp[0].depth)
235             return AVERROR(EAGAIN);
236     }
237
238     if (rgb && depth == 8)
239         out_pix_fmts = out_rgb8_pix_fmts;
240     else if (rgb && depth == 9)
241         out_pix_fmts = out_rgb9_pix_fmts;
242     else if (rgb && depth == 10)
243         out_pix_fmts = out_rgb10_pix_fmts;
244     else if (rgb && depth == 12)
245         out_pix_fmts = out_rgb12_pix_fmts;
246     else if (depth == 8)
247         out_pix_fmts = out_yuv8_pix_fmts;
248     else if (depth == 9)
249         out_pix_fmts = out_yuv9_pix_fmts;
250     else if (depth == 10)
251         out_pix_fmts = out_yuv10_pix_fmts;
252     else if (depth == 12)
253         out_pix_fmts = out_yuv12_pix_fmts;
254     else
255         return AVERROR(EAGAIN);
256     if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats)) < 0)
257         return ret;
258
259     return 0;
260 }
261
262 static int config_output(AVFilterLink *outlink)
263 {
264     VectorscopeContext *s = outlink->src->priv;
265     int i;
266
267     s->intensity = s->fintensity * (s->size - 1);
268     outlink->h = outlink->w = s->size;
269     outlink->sample_aspect_ratio = (AVRational){1,1};
270
271     s->peak_memory = av_calloc(s->size, s->size);
272     if (!s->peak_memory)
273         return AVERROR(ENOMEM);
274
275     s->peak = av_calloc(s->size, sizeof(*s->peak));
276     if (!s->peak)
277         return AVERROR(ENOMEM);
278
279     for (i = 0; i < s->size; i++)
280         s->peak[i] = s->peak_memory + s->size * i;
281
282     return 0;
283 }
284
285 static void envelope_instant16(VectorscopeContext *s, AVFrame *out)
286 {
287     const int dlinesize = out->linesize[0] / 2;
288     uint16_t *dpd = s->mode == COLOR || !s->is_yuv ? (uint16_t *)out->data[s->pd] : (uint16_t *)out->data[0];
289     const int max = s->size - 1;
290     int i, j;
291
292     for (i = 0; i < out->height; i++) {
293         for (j = 0; j < out->width; j++) {
294             const int pos = i * dlinesize + j;
295             const int poa = (i - 1) * dlinesize + j;
296             const int pob = (i + 1) * dlinesize + j;
297
298             if (dpd[pos] && (((!j || !dpd[pos - 1]) || ((j == (out->width - 1)) || !dpd[pos + 1]))
299                          || ((!i || !dpd[poa]) || ((i == (out->height - 1)) || !dpd[pob])))) {
300                 dpd[pos] = max;
301             }
302         }
303     }
304 }
305
306 static void envelope_peak16(VectorscopeContext *s, AVFrame *out)
307 {
308     const int dlinesize = out->linesize[0] / 2;
309     uint16_t *dpd = s->mode == COLOR || !s->is_yuv ? (uint16_t *)out->data[s->pd] : (uint16_t *)out->data[0];
310     const int max = s->size - 1;
311     int i, j;
312
313     for (i = 0; i < out->height; i++) {
314         for (j = 0; j < out->width; j++) {
315             const int pos = i * dlinesize + j;
316
317             if (dpd[pos])
318                 s->peak[i][j] = 1;
319         }
320     }
321
322     if (s->envelope == 3)
323         envelope_instant16(s, out);
324
325     for (i = 0; i < out->height; i++) {
326         for (j = 0; j < out->width; j++) {
327             const int pos = i * dlinesize + j;
328
329             if (s->peak[i][j] && (((!j || !s->peak[i][j-1]) || ((j == (out->width - 1)) || !s->peak[i][j + 1]))
330                               || ((!i || !s->peak[i-1][j]) || ((i == (out->height - 1)) || !s->peak[i + 1][j])))) {
331                 dpd[pos] = max;
332             }
333         }
334     }
335 }
336
337 static void envelope_instant(VectorscopeContext *s, AVFrame *out)
338 {
339     const int dlinesize = out->linesize[0];
340     uint8_t *dpd = s->mode == COLOR || !s->is_yuv ? out->data[s->pd] : out->data[0];
341     int i, j;
342
343     for (i = 0; i < out->height; i++) {
344         for (j = 0; j < out->width; j++) {
345             const int pos = i * dlinesize + j;
346             const int poa = (i - 1) * dlinesize + j;
347             const int pob = (i + 1) * dlinesize + j;
348
349             if (dpd[pos] && (((!j || !dpd[pos - 1]) || ((j == (out->width - 1)) || !dpd[pos + 1]))
350                          || ((!i || !dpd[poa]) || ((i == (out->height - 1)) || !dpd[pob])))) {
351                 dpd[pos] = 255;
352             }
353         }
354     }
355 }
356
357 static void envelope_peak(VectorscopeContext *s, AVFrame *out)
358 {
359     const int dlinesize = out->linesize[0];
360     uint8_t *dpd = s->mode == COLOR || !s->is_yuv ? out->data[s->pd] : out->data[0];
361     int i, j;
362
363     for (i = 0; i < out->height; i++) {
364         for (j = 0; j < out->width; j++) {
365             const int pos = i * dlinesize + j;
366
367             if (dpd[pos])
368                 s->peak[i][j] = 1;
369         }
370     }
371
372     if (s->envelope == 3)
373         envelope_instant(s, out);
374
375     for (i = 0; i < out->height; i++) {
376         for (j = 0; j < out->width; j++) {
377             const int pos = i * dlinesize + j;
378
379             if (s->peak[i][j] && (((!j || !s->peak[i][j-1]) || ((j == (out->width - 1)) || !s->peak[i][j + 1]))
380                               || ((!i || !s->peak[i-1][j]) || ((i == (out->height - 1)) || !s->peak[i + 1][j])))) {
381                 dpd[pos] = 255;
382             }
383         }
384     }
385 }
386
387 static void envelope16(VectorscopeContext *s, AVFrame *out)
388 {
389     if (!s->envelope) {
390         return;
391     } else if (s->envelope == 1) {
392         envelope_instant16(s, out);
393     } else {
394         envelope_peak16(s, out);
395     }
396 }
397
398 static void envelope(VectorscopeContext *s, AVFrame *out)
399 {
400     if (!s->envelope) {
401         return;
402     } else if (s->envelope == 1) {
403         envelope_instant(s, out);
404     } else {
405         envelope_peak(s, out);
406     }
407 }
408
409 static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int pd)
410 {
411     const uint16_t * const *src = (const uint16_t * const *)in->data;
412     const int slinesizex = in->linesize[s->x] / 2;
413     const int slinesizey = in->linesize[s->y] / 2;
414     const int slinesized = in->linesize[pd] / 2;
415     const int dlinesize = out->linesize[0] / 2;
416     const int intensity = s->intensity;
417     const int px = s->x, py = s->y;
418     const int h = s->planeheight[py];
419     const int w = s->planewidth[px];
420     const uint16_t *spx = src[px];
421     const uint16_t *spy = src[py];
422     const uint16_t *spd = src[pd];
423     const int hsub = s->hsub;
424     const int vsub = s->vsub;
425     uint16_t **dst = (uint16_t **)out->data;
426     uint16_t *dpx = dst[px];
427     uint16_t *dpy = dst[py];
428     uint16_t *dpd = dst[pd];
429     const int max = s->size - 1;
430     const int mid = s->size / 2;
431     const int tmin = s->tmin;
432     const int tmax = s->tmax;
433     int i, j, k;
434
435     for (k = 0; k < 4 && dst[k]; k++) {
436         for (i = 0; i < out->height ; i++)
437             for (j = 0; j < out->width; j++)
438                 AV_WN16(out->data[k] + i * out->linesize[k] + j * 2,
439                         (s->mode == COLOR || s->mode == COLOR5) && k == s->pd ? 0 : s->bg_color[k]);
440     }
441
442     switch (s->mode) {
443     case COLOR:
444     case COLOR5:
445     case GRAY:
446         if (s->is_yuv) {
447             for (i = 0; i < h; i++) {
448                 const int iwx = i * slinesizex;
449                 const int iwy = i * slinesizey;
450                 const int iwd = i * slinesized;
451                 for (j = 0; j < w; j++) {
452                     const int x = FFMIN(spx[iwx + j], max);
453                     const int y = FFMIN(spy[iwy + j], max);
454                     const int z = spd[iwd + j];
455                     const int pos = y * dlinesize + x;
456
457                     if (z < tmin || z > tmax)
458                         continue;
459
460                     dpd[pos] = FFMIN(dpd[pos] + intensity, max);
461                 }
462             }
463         } else {
464             for (i = 0; i < h; i++) {
465                 const int iwx = i * slinesizex;
466                 const int iwy = i * slinesizey;
467                 const int iwd = i * slinesized;
468                 for (j = 0; j < w; j++) {
469                     const int x = FFMIN(spx[iwx + j], max);
470                     const int y = FFMIN(spy[iwy + j], max);
471                     const int z = spd[iwd + j];
472                     const int pos = y * dlinesize + x;
473
474                     if (z < tmin || z > tmax)
475                         continue;
476
477                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, max);
478                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, max);
479                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, max);
480                 }
481             }
482         }
483         break;
484     case COLOR2:
485         if (s->is_yuv) {
486             for (i = 0; i < h; i++) {
487                 const int iw1 = i * slinesizex;
488                 const int iw2 = i * slinesizey;
489                 const int iwd = i * slinesized;
490                 for (j = 0; j < w; j++) {
491                     const int x = FFMIN(spx[iw1 + j], max);
492                     const int y = FFMIN(spy[iw2 + j], max);
493                     const int z = spd[iwd + j];
494                     const int pos = y * dlinesize + x;
495
496                     if (z < tmin || z > tmax)
497                         continue;
498
499                     if (!dpd[pos])
500                         dpd[pos] = FFABS(mid - x) + FFABS(mid - y);
501                     dpx[pos] = x;
502                     dpy[pos] = y;
503                 }
504             }
505         } else {
506             for (i = 0; i < h; i++) {
507                 const int iw1 = i * slinesizex;
508                 const int iw2 = i * slinesizey;
509                 const int iwd = i * slinesized;
510                 for (j = 0; j < w; j++) {
511                     const int x = FFMIN(spx[iw1 + j], max);
512                     const int y = FFMIN(spy[iw2 + j], max);
513                     const int z = spd[iwd + j];
514                     const int pos = y * dlinesize + x;
515
516                     if (z < tmin || z > tmax)
517                         continue;
518
519                     if (!dpd[pos])
520                         dpd[pos] = FFMIN(x + y, max);
521                     dpx[pos] = x;
522                     dpy[pos] = y;
523                 }
524             }
525         }
526         break;
527     case COLOR3:
528         for (i = 0; i < h; i++) {
529             const int iw1 = i * slinesizex;
530             const int iw2 = i * slinesizey;
531             const int iwd = i * slinesized;
532             for (j = 0; j < w; j++) {
533                 const int x = FFMIN(spx[iw1 + j], max);
534                 const int y = FFMIN(spy[iw2 + j], max);
535                 const int z = spd[iwd + j];
536                 const int pos = y * dlinesize + x;
537
538                 if (z < tmin || z > tmax)
539                     continue;
540
541                 dpd[pos] = FFMIN(max, dpd[pos] + intensity);
542                 dpx[pos] = x;
543                 dpy[pos] = y;
544             }
545         }
546         break;
547     case COLOR4:
548         for (i = 0; i < in->height; i++) {
549             const int iwx = (i >> vsub) * slinesizex;
550             const int iwy = (i >> vsub) * slinesizey;
551             const int iwd = i * slinesized;
552             for (j = 0; j < in->width; j++) {
553                 const int x = FFMIN(spx[iwx + (j >> hsub)], max);
554                 const int y = FFMIN(spy[iwy + (j >> hsub)], max);
555                 const int z = spd[iwd + j];
556                 const int pos = y * dlinesize + x;
557
558                 if (z < tmin || z > tmax)
559                     continue;
560
561                 dpd[pos] = FFMAX(z, dpd[pos]);
562                 dpx[pos] = x;
563                 dpy[pos] = y;
564             }
565         }
566         break;
567     default:
568         av_assert0(0);
569     }
570
571     envelope16(s, out);
572
573     if (dst[3]) {
574         for (i = 0; i < out->height; i++) {
575             for (j = 0; j < out->width; j++) {
576                 int pos = i * dlinesize + j;
577
578                 if (dpd[pos])
579                     dst[3][pos] = max;
580             }
581         }
582     }
583
584     if (s->mode == COLOR) {
585         for (i = 0; i < out->height; i++) {
586             for (j = 0; j < out->width; j++) {
587                 if (!dpd[i * dlinesize + j]) {
588                     dpx[i * dlinesize + j] = j;
589                     dpy[i * dlinesize + j] = i;
590                     dpd[i * dlinesize + j] = mid;
591                 }
592             }
593         }
594     } else if (s->mode == COLOR5) {
595         for (i = 0; i < out->height; i++) {
596             for (j = 0; j < out->width; j++) {
597                 if (!dpd[i * dlinesize + j]) {
598                     dpx[i * dlinesize + j] = j;
599                     dpy[i * dlinesize + j] = i;
600                     dpd[i * dlinesize + j] = mid * M_SQRT2 - hypot(i - mid, j - mid);
601                 }
602             }
603         }
604     }
605 }
606
607 static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int pd)
608 {
609     const uint8_t * const *src = (const uint8_t * const *)in->data;
610     const int slinesizex = in->linesize[s->x];
611     const int slinesizey = in->linesize[s->y];
612     const int slinesized = in->linesize[pd];
613     const int dlinesize = out->linesize[0];
614     const int intensity = s->intensity;
615     const int px = s->x, py = s->y;
616     const int h = s->planeheight[py];
617     const int w = s->planewidth[px];
618     const uint8_t *spx = src[px];
619     const uint8_t *spy = src[py];
620     const uint8_t *spd = src[pd];
621     const int hsub = s->hsub;
622     const int vsub = s->vsub;
623     uint8_t **dst = out->data;
624     uint8_t *dpx = dst[px];
625     uint8_t *dpy = dst[py];
626     uint8_t *dpd = dst[pd];
627     const int tmin = s->tmin;
628     const int tmax = s->tmax;
629     int i, j, k;
630
631     for (k = 0; k < 4 && dst[k]; k++)
632         for (i = 0; i < out->height ; i++)
633             memset(dst[k] + i * out->linesize[k],
634                    (s->mode == COLOR || s->mode == COLOR5) && k == s->pd ? 0 : s->bg_color[k], out->width);
635
636     switch (s->mode) {
637     case COLOR5:
638     case COLOR:
639     case GRAY:
640         if (s->is_yuv) {
641             for (i = 0; i < h; i++) {
642                 const int iwx = i * slinesizex;
643                 const int iwy = i * slinesizey;
644                 const int iwd = i * slinesized;
645                 for (j = 0; j < w; j++) {
646                     const int x = spx[iwx + j];
647                     const int y = spy[iwy + j];
648                     const int z = spd[iwd + j];
649                     const int pos = y * dlinesize + x;
650
651                     if (z < tmin || z > tmax)
652                         continue;
653
654                     dpd[pos] = FFMIN(dpd[pos] + intensity, 255);
655                 }
656             }
657         } else {
658             for (i = 0; i < h; i++) {
659                 const int iwx = i * slinesizex;
660                 const int iwy = i * slinesizey;
661                 const int iwd = i * slinesized;
662                 for (j = 0; j < w; j++) {
663                     const int x = spx[iwx + j];
664                     const int y = spy[iwy + j];
665                     const int z = spd[iwd + j];
666                     const int pos = y * dlinesize + x;
667
668                     if (z < tmin || z > tmax)
669                         continue;
670
671                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, 255);
672                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, 255);
673                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, 255);
674                 }
675             }
676         }
677         break;
678     case COLOR2:
679         if (s->is_yuv) {
680             for (i = 0; i < h; i++) {
681                 const int iw1 = i * slinesizex;
682                 const int iw2 = i * slinesizey;
683                 const int iwd = i * slinesized;
684                 for (j = 0; j < w; j++) {
685                     const int x = spx[iw1 + j];
686                     const int y = spy[iw2 + j];
687                     const int z = spd[iwd + j];
688                     const int pos = y * dlinesize + x;
689
690                     if (z < tmin || z > tmax)
691                         continue;
692
693                     if (!dpd[pos])
694                         dpd[pos] = FFABS(128 - x) + FFABS(128 - y);
695                     dpx[pos] = x;
696                     dpy[pos] = y;
697                 }
698             }
699         } else {
700             for (i = 0; i < h; i++) {
701                 const int iw1 = i * slinesizex;
702                 const int iw2 = i * slinesizey;
703                 const int iwd = i * slinesized;
704                 for (j = 0; j < w; j++) {
705                     const int x = spx[iw1 + j];
706                     const int y = spy[iw2 + j];
707                     const int z = spd[iwd + j];
708                     const int pos = y * dlinesize + x;
709
710                     if (z < tmin || z > tmax)
711                         continue;
712
713                     if (!dpd[pos])
714                         dpd[pos] = FFMIN(x + y, 255);
715                     dpx[pos] = x;
716                     dpy[pos] = y;
717                 }
718             }
719         }
720         break;
721     case COLOR3:
722         for (i = 0; i < h; i++) {
723             const int iw1 = i * slinesizex;
724             const int iw2 = i * slinesizey;
725             const int iwd = i * slinesized;
726             for (j = 0; j < w; j++) {
727                 const int x = spx[iw1 + j];
728                 const int y = spy[iw2 + j];
729                 const int z = spd[iwd + j];
730                 const int pos = y * dlinesize + x;
731
732                 if (z < tmin || z > tmax)
733                     continue;
734
735                 dpd[pos] = FFMIN(255, dpd[pos] + intensity);
736                 dpx[pos] = x;
737                 dpy[pos] = y;
738             }
739         }
740         break;
741     case COLOR4:
742         for (i = 0; i < in->height; i++) {
743             const int iwx = (i >> vsub) * slinesizex;
744             const int iwy = (i >> vsub) * slinesizey;
745             const int iwd = i * slinesized;
746             for (j = 0; j < in->width; j++) {
747                 const int x = spx[iwx + (j >> hsub)];
748                 const int y = spy[iwy + (j >> hsub)];
749                 const int z = spd[iwd + j];
750                 const int pos = y * dlinesize + x;
751
752                 if (z < tmin || z > tmax)
753                     continue;
754
755                 dpd[pos] = FFMAX(z, dpd[pos]);
756                 dpx[pos] = x;
757                 dpy[pos] = y;
758             }
759         }
760         break;
761     default:
762         av_assert0(0);
763     }
764
765     envelope(s, out);
766
767     if (dst[3]) {
768         for (i = 0; i < out->height; i++) {
769             for (j = 0; j < out->width; j++) {
770                 int pos = i * dlinesize + j;
771
772                 if (dpd[pos])
773                     dst[3][pos] = 255;
774             }
775         }
776     }
777
778     if (s->mode == COLOR) {
779         for (i = 0; i < out->height; i++) {
780             for (j = 0; j < out->width; j++) {
781                 if (!dpd[i * out->linesize[pd] + j]) {
782                     dpx[i * out->linesize[px] + j] = j;
783                     dpy[i * out->linesize[py] + j] = i;
784                     dpd[i * out->linesize[pd] + j] = 128;
785                 }
786             }
787         }
788     } else if (s->mode == COLOR5) {
789         for (i = 0; i < out->height; i++) {
790             for (j = 0; j < out->width; j++) {
791                 if (!dpd[i * out->linesize[pd] + j]) {
792                     dpx[i * out->linesize[px] + j] = j;
793                     dpy[i * out->linesize[py] + j] = i;
794                     dpd[i * out->linesize[pd] + j] = 128 * M_SQRT2 - hypot(i - 128, j - 128);
795                 }
796             }
797         }
798     }
799 }
800
801 const static char *positions_name[] = {
802     "R", "B", "Cy", "Yl", "G", "Mg",
803 };
804
805 const static uint16_t positions[][14][3] = {
806   {
807     {  81,  90, 240 }, {  41, 240, 110 }, { 170, 166,  16 },
808     { 210,  16, 146 }, { 145,  54,  34 }, { 106, 202, 222 },
809     { 162,  44, 142 }, { 131, 156,  44 }, { 112,  72,  58 },
810     {  84, 184, 198 }, {  65, 100, 212 }, {  35, 212, 114 },
811     { 235, 128, 128 }, { 16, 128, 128 } },
812   { {  63, 102, 240 }, {  32, 240, 118 }, { 188, 154,  16 },
813     { 219,  16, 138 }, { 173,  42,  26 }, {  78, 214, 230 },
814     {  28, 212, 120 }, {  51, 109, 212 }, {  63, 193, 204 },
815     { 133,  63,  52 }, { 145, 147,  44 }, { 168,  44, 136 },
816     { 235, 128, 128 }, { 16, 128, 128 } },
817   { {  81*2,  90*2, 240*2 }, {  41*2, 240*2, 110*2 }, { 170*2, 166*2,  16*2 },
818     { 210*2,  16*2, 146*2 }, { 145*2,  54*2,  34*2 }, { 106*2, 202*2, 222*2 },
819     { 162*2,  44*2, 142*2 }, { 131*2, 156*2,  44*2 }, { 112*2,  72*2,  58*2 },
820     {  84*2, 184*2, 198*2 }, {  65*2, 100*2, 212*2 }, {  35*2, 212*2, 114*2 },
821     { 470, 256, 256 }, { 32, 256, 256 } },
822   { {  63*2, 102*2, 240*2 }, {  32*2, 240*2, 118*2 }, { 188*2, 154*2,  16*2 },
823     { 219*2,  16*2, 138*2 }, { 173*2,  42*2,  26*2 }, {  78*2, 214*2, 230*2 },
824     {  28*2, 212*2, 120*2 }, {  51*2, 109*2, 212*2 }, {  63*2, 193*2, 204*2 },
825     { 133*2,  63*2,  52*2 }, { 145*2, 147*2,  44*2 }, { 168*2,  44*2, 136*2 },
826     { 470, 256, 256 }, { 32, 256, 256 } },
827   { {  81*4,  90*4, 240*4 }, {  41*4, 240*4, 110*4 }, { 170*4, 166*4,  16*4 },
828     { 210*4,  16*4, 146*4 }, { 145*4,  54*4,  34*4 }, { 106*4, 202*4, 222*4 },
829     { 162*4,  44*4, 142*4 }, { 131*4, 156*4,  44*4 }, { 112*4,  72*4,  58*4 },
830     {  84*4, 184*4, 198*4 }, {  65*4, 100*4, 212*4 }, {  35*4, 212*4, 114*4 },
831     { 940, 512, 512 }, { 64, 512, 512 } },
832   { {  63*4, 102*4, 240*4 }, {  32*4, 240*4, 118*4 }, { 188*4, 154*4,  16*4 },
833     { 219*4,  16*4, 138*4 }, { 173*4,  42*4,  26*4 }, {  78*4, 214*4, 230*4 },
834     {  28*4, 212*4, 120*4 }, {  51*4, 109*4, 212*4 }, {  63*4, 193*4, 204*4 },
835     { 133*4,  63*4,  52*4 }, { 145*4, 147*4,  44*4 }, { 168*4,  44*4, 136*4 },
836     { 940, 512, 512 }, { 64, 512, 512 } },
837   { {  81*8,  90*4, 240*8 }, {  41*8, 240*8, 110*8 }, { 170*8, 166*8,  16*8 },
838     { 210*8,  16*4, 146*8 }, { 145*8,  54*8,  34*8 }, { 106*8, 202*8, 222*8 },
839     { 162*8,  44*4, 142*8 }, { 131*8, 156*8,  44*8 }, { 112*8,  72*8,  58*8 },
840     {  84*8, 184*4, 198*8 }, {  65*8, 100*8, 212*8 }, {  35*8, 212*8, 114*8 },
841     { 1880, 1024, 1024 }, { 128, 1024, 1024 } },
842   { {  63*8, 102*8, 240*8 }, {  32*8, 240*8, 118*8 }, { 188*8, 154*8,  16*8 },
843     { 219*8,  16*8, 138*8 }, { 173*8,  42*8,  26*8 }, {  78*8, 214*8, 230*8 },
844     {  28*8, 212*8, 120*8 }, {  51*8, 109*8, 212*8 }, {  63*8, 193*8, 204*8 },
845     { 133*8,  63*8,  52*8 }, { 145*8, 147*8,  44*8 }, { 168*8,  44*8, 136*8 },
846     { 1880, 1024, 1024 }, { 128, 1024, 1024 } },
847   { {  81*16,  90*16, 240*16 }, {  41*16, 240*16, 110*16 }, { 170*16, 166*16,  16*16 },
848     { 210*16,  16*16, 146*16 }, { 145*16,  54*16,  34*16 }, { 106*16, 202*16, 222*16 },
849     { 162*16,  44*16, 142*16 }, { 131*16, 156*16,  44*16 }, { 112*16,  72*16,  58*16 },
850     {  84*16, 184*16, 198*16 }, {  65*16, 100*16, 212*16 }, {  35*16, 212*16, 114*16 },
851     { 3760, 2048, 2048 }, { 256, 2048, 2048 } },
852   { {  63*16, 102*16, 240*16 }, {  32*16, 240*16, 118*16 }, { 188*16, 154*16,  16*16 },
853     { 219*16,  16*16, 138*16 }, { 173*16,  42*16,  26*16 }, {  78*16, 214*16, 230*16 },
854     {  28*16, 212*16, 120*16 }, {  51*16, 109*16, 212*16 }, {  63*16, 193*16, 204*16 },
855     { 133*16,  63*16,  52*16 }, { 145*16, 147*16,  44*16 }, { 168*16,  44*16, 136*16 },
856     { 3760, 2048, 2048 }, { 256, 2048, 2048 } },
857 };
858
859 static void draw_dots(uint8_t *dst, int L, int v, float o)
860 {
861     const float f = 1. - o;
862     const float V = o * v;
863     int l = L * 2;
864
865     dst[ l - 3] = dst[ l - 3] * f + V;
866     dst[ l + 3] = dst[ l + 3] * f + V;
867     dst[-l - 3] = dst[-l - 3] * f + V;
868     dst[-l + 3] = dst[-l + 3] * f + V;
869
870     l += L;
871
872     dst[ l - 3] = dst[ l - 3] * f + V;
873     dst[ l + 3] = dst[ l + 3] * f + V;
874     dst[ l - 2] = dst[ l - 2] * f + V;
875     dst[ l + 2] = dst[ l + 2] * f + V;
876     dst[-l - 3] = dst[-l - 3] * f + V;
877     dst[-l + 3] = dst[-l + 3] * f + V;
878     dst[-l - 2] = dst[-l - 2] * f + V;
879     dst[-l + 2] = dst[-l + 2] * f + V;
880 }
881
882 static void draw_idots(uint8_t *dst, int L, float o)
883 {
884     const float f = 1. - o;
885     int l = L * 2;
886
887     dst[ l - 3] = dst[ l - 3] * f + (255 - dst[ l - 3]) * o;
888     dst[ l + 3] = dst[ l + 3] * f + (255 - dst[ l + 3]) * o;
889     dst[-l - 3] = dst[-l - 3] * f + (255 - dst[-l - 3]) * o;
890     dst[-l + 3] = dst[-l + 3] * f + (255 - dst[-l + 3]) * o;
891
892     l += L;
893
894     dst[ l - 3] = dst[ l - 3] * f + (255 - dst[ l - 3]) * o;
895     dst[ l + 3] = dst[ l + 3] * f + (255 - dst[ l + 3]) * o;
896     dst[ l - 2] = dst[ l - 2] * f + (255 - dst[ l - 2]) * o;
897     dst[ l + 2] = dst[ l + 2] * f + (255 - dst[ l + 2]) * o;
898     dst[-l - 3] = dst[-l - 3] * f + (255 - dst[-l - 3]) * o;
899     dst[-l + 3] = dst[-l + 3] * f + (255 - dst[-l + 3]) * o;
900     dst[-l - 2] = dst[-l - 2] * f + (255 - dst[-l - 2]) * o;
901     dst[-l + 2] = dst[-l + 2] * f + (255 - dst[-l + 2]) * o;
902 }
903
904 static void draw_dots16(uint16_t *dst, int L, int v, float o)
905 {
906     const float f = 1. - o;
907     const float V = o * v;
908     int l = L * 2;
909
910     dst[ l - 3] = dst[ l - 3] * f + V;
911     dst[ l + 3] = dst[ l + 3] * f + V;
912     dst[-l - 3] = dst[-l - 3] * f + V;
913     dst[-l + 3] = dst[-l + 3] * f + V;
914
915     l += L;
916
917     dst[ l - 3] = dst[ l - 3] * f + V;
918     dst[ l + 3] = dst[ l + 3] * f + V;
919     dst[ l - 2] = dst[ l - 2] * f + V;
920     dst[ l + 2] = dst[ l + 2] * f + V;
921     dst[-l - 3] = dst[-l - 3] * f + V;
922     dst[-l + 3] = dst[-l + 3] * f + V;
923     dst[-l - 2] = dst[-l - 2] * f + V;
924     dst[-l + 2] = dst[-l + 2] * f + V;
925 }
926
927 static void draw_idots16(uint16_t *dst, int L, int v, float o)
928 {
929     const float f = 1. - o;
930     int l = L * 2;
931
932     dst[ l - 3] = dst[ l - 3] * f + (v - dst[ l - 3]) * o;
933     dst[ l + 3] = dst[ l + 3] * f + (v - dst[ l + 3]) * o;
934     dst[-l - 3] = dst[-l - 3] * f + (v - dst[-l - 3]) * o;
935     dst[-l + 3] = dst[-l + 3] * f + (v - dst[-l + 3]) * o;
936
937     l += L;
938
939     dst[ l - 3] = dst[ l - 3] * f + (v - dst[ l - 3]) * o;
940     dst[ l + 3] = dst[ l + 3] * f + (v - dst[ l + 3]) * o;
941     dst[ l - 2] = dst[ l - 2] * f + (v - dst[ l - 2]) * o;
942     dst[ l + 2] = dst[ l + 2] * f + (v - dst[ l + 2]) * o;
943     dst[-l - 3] = dst[-l - 3] * f + (v - dst[-l - 3]) * o;
944     dst[-l + 3] = dst[-l + 3] * f + (v - dst[-l + 3]) * o;
945     dst[-l - 2] = dst[-l - 2] * f + (v - dst[-l - 2]) * o;
946     dst[-l + 2] = dst[-l + 2] * f + (v - dst[-l + 2]) * o;
947 }
948
949 static void none_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
950 {
951 }
952
953 static void draw_ihtext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
954 {
955     const uint8_t *font;
956     int font_height;
957     int i, plane;
958
959     font = avpriv_cga_font,   font_height =  8;
960
961     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
962         for (i = 0; txt[i]; i++) {
963             int char_y, mask;
964
965             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
966             for (char_y = font_height - 1; char_y >= 0; char_y--) {
967                 for (mask = 0x80; mask; mask >>= 1) {
968                     if (font[txt[i] * font_height + char_y] & mask)
969                         p[0] = p[0] * o2 + (255 - p[0]) * o1;
970                     p++;
971                 }
972                 p += out->linesize[plane] - 8;
973             }
974         }
975     }
976 }
977
978 static void draw_ihtext16(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint16_t color[4])
979 {
980     const uint8_t *font;
981     int font_height;
982     int i, plane;
983
984     font = avpriv_cga_font,   font_height =  8;
985
986     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
987         for (i = 0; txt[i]; i++) {
988             int char_y, mask;
989             int v = color[plane];
990
991             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
992             for (char_y = font_height - 1; char_y >= 0; char_y--) {
993                 for (mask = 0x80; mask; mask >>= 1) {
994                     if (font[txt[i] * font_height + char_y] & mask)
995                         p[0] = p[0] * o2 + (v - p[0]) * o1;
996                     p++;
997                 }
998                 p += out->linesize[plane] / 2 - 8;
999             }
1000         }
1001     }
1002 }
1003
1004 static void draw_htext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
1005 {
1006     const uint8_t *font;
1007     int font_height;
1008     int i, plane;
1009
1010     font = avpriv_cga_font,   font_height =  8;
1011
1012     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
1013         for (i = 0; txt[i]; i++) {
1014             int char_y, mask;
1015             int v = color[plane];
1016
1017             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
1018             for (char_y = font_height - 1; char_y >= 0; char_y--) {
1019                 for (mask = 0x80; mask; mask >>= 1) {
1020                     if (font[txt[i] * font_height + char_y] & mask)
1021                         p[0] = p[0] * o2 + v * o1;
1022                     p++;
1023                 }
1024                 p += out->linesize[plane] - 8;
1025             }
1026         }
1027     }
1028 }
1029
1030 static void draw_htext16(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint16_t color[4])
1031 {
1032     const uint8_t *font;
1033     int font_height;
1034     int i, plane;
1035
1036     font = avpriv_cga_font,   font_height =  8;
1037
1038     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
1039         for (i = 0; txt[i]; i++) {
1040             int char_y, mask;
1041             int v = color[plane];
1042
1043             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
1044             for (char_y = font_height - 1; char_y >= 0; char_y--) {
1045                 for (mask = 0x80; mask; mask >>= 1) {
1046                     if (font[txt[i] * font_height + char_y] & mask)
1047                         p[0] = p[0] * o2 + v * o1;
1048                     p++;
1049                 }
1050                 p += out->linesize[plane] / 2 - 8;
1051             }
1052         }
1053     }
1054 }
1055
1056 static void color_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1057 {
1058     const int max = s->size - 1;
1059     const float o = s->opacity;
1060     int i;
1061
1062     for (i = 0; i < 12; i++) {
1063         int x = positions[P][i][X];
1064         int y = positions[P][i][Y];
1065         int d = positions[P][i][D];
1066
1067         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1068         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1069         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1070         if (out->data[3])
1071             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1072     }
1073
1074     if (s->flags & 1) {
1075         int x = positions[P][12][X];
1076         int y = positions[P][12][Y];
1077         int d = positions[P][12][D];
1078
1079         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1080         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1081         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1082         if (out->data[3])
1083             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1084     }
1085
1086     if (s->flags & 2) {
1087         int x = positions[P][13][X];
1088         int y = positions[P][13][Y];
1089         int d = positions[P][13][D];
1090
1091         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1092         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1093         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1094         if (out->data[3])
1095             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1096     }
1097
1098     for (i = 0; i < 6 && s->flags & 4; i++) {
1099         uint16_t color[4] = { 0, 0, 0, 0 };
1100         int x = positions[P][i][X];
1101         int y = positions[P][i][Y];
1102         int d = positions[P][i][D];
1103
1104         color[D] = d;
1105         color[X] = x;
1106         color[Y] = y;
1107         color[3] = max;
1108
1109         if (x > max / 2)
1110             x += 8;
1111         else
1112             x -= 14;
1113         if (y > max / 2)
1114             y += 8;
1115         else
1116             y -= 14;
1117
1118         x = av_clip(x, 0, out->width - 9);
1119         y = av_clip(y, 0, out->height - 9);
1120         draw_htext16(out, x, y, o, 1. - o, positions_name[i], color);
1121     }
1122 }
1123
1124 static void color_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1125 {
1126     const float o = s->opacity;
1127     int i;
1128
1129     for (i = 0; i < 12; i++) {
1130         int x = positions[P][i][X];
1131         int y = positions[P][i][Y];
1132         int d = positions[P][i][D];
1133
1134         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1135         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1136         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1137         if (out->data[3])
1138             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1139     }
1140
1141     if (s->flags & 1) {
1142         int x = positions[P][12][X];
1143         int y = positions[P][12][Y];
1144         int d = positions[P][12][D];
1145
1146         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1147         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1148         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1149         if (out->data[3])
1150             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1151     }
1152
1153     if (s->flags & 2) {
1154         int x = positions[P][13][X];
1155         int y = positions[P][13][Y];
1156         int d = positions[P][12][D];
1157
1158         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1159         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1160         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1161         if (out->data[3])
1162             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1163     }
1164
1165     for (i = 0; i < 6 && s->flags & 4; i++) {
1166         uint8_t color[4] = { 0, 0, 0, 255 };
1167         int x = positions[P][i][X];
1168         int y = positions[P][i][Y];
1169         int d = positions[P][i][D];
1170
1171         color[D] = d;
1172         color[X] = x;
1173         color[Y] = y;
1174
1175         if (x > 128)
1176             x += 8;
1177         else
1178             x -= 14;
1179         if (y > 128)
1180             y += 8;
1181         else
1182             y -= 14;
1183
1184         x = av_clip(x, 0, out->width - 9);
1185         y = av_clip(y, 0, out->height - 9);
1186         draw_htext(out, x, y, o, 1. - o, positions_name[i], color);
1187     }
1188 }
1189
1190 static void green_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1191 {
1192     const int max = s->size - 1;
1193     const float o = s->opacity;
1194     const int m = s->mult;
1195     int i;
1196
1197     for (i = 0; i < 12; i++) {
1198         int x = positions[P][i][X];
1199         int y = positions[P][i][Y];
1200
1201         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1202         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1203         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1204         if (out->data[3])
1205             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1206     }
1207
1208     if (s->flags & 1) {
1209         int x = positions[P][12][X];
1210         int y = positions[P][12][Y];
1211
1212         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1213         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1214         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1215         if (out->data[3])
1216             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1217     }
1218
1219     if (s->flags & 2) {
1220         int x = positions[P][13][X];
1221         int y = positions[P][13][Y];
1222
1223         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1224         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1225         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1226         if (out->data[3])
1227             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1228     }
1229
1230     for (i = 0; i < 6 && s->flags & 4; i++) {
1231         const uint16_t color[4] = { 128 * m, 0, 0, max };
1232         int x = positions[P][i][X];
1233         int y = positions[P][i][Y];
1234
1235         if (x > max / 2)
1236             x += 8;
1237         else
1238             x -= 14;
1239         if (y > max / 2)
1240             y += 8;
1241         else
1242             y -= 14;
1243
1244         x = av_clip(x, 0, out->width - 9);
1245         y = av_clip(y, 0, out->height - 9);
1246         draw_htext16(out, x, y, o, 1. - o, positions_name[i], color);
1247     }
1248 }
1249
1250 static void green_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1251 {
1252     const float o = s->opacity;
1253     int i;
1254
1255     for (i = 0; i < 12; i++) {
1256         int x = positions[P][i][X];
1257         int y = positions[P][i][Y];
1258
1259         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1260         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1261         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1262         if (out->data[3])
1263             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1264     }
1265
1266     if (s->flags & 1) {
1267         int x = positions[P][12][X];
1268         int y = positions[P][12][Y];
1269
1270         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1271         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1272         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1273         if (out->data[3])
1274             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1275     }
1276
1277     if (s->flags & 2) {
1278         int x = positions[P][13][X];
1279         int y = positions[P][13][Y];
1280
1281         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1282         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1283         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1284         if (out->data[3])
1285             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1286     }
1287
1288     for (i = 0; i < 6 && s->flags & 4; i++) {
1289         const uint8_t color[4] = { 128, 0, 0, 255 };
1290         int x = positions[P][i][X];
1291         int y = positions[P][i][Y];
1292
1293         if (x > 128)
1294             x += 8;
1295         else
1296             x -= 14;
1297         if (y > 128)
1298             y += 8;
1299         else
1300             y -= 14;
1301
1302         x = av_clip(x, 0, out->width - 9);
1303         y = av_clip(y, 0, out->height - 9);
1304         draw_htext(out, x, y, o, 1. - o, positions_name[i], color);
1305     }
1306 }
1307
1308 static void invert_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1309 {
1310     const int max = s->size - 1;
1311     const float o = s->opacity;
1312     int i;
1313
1314     for (i = 0; i < 12; i++) {
1315         int x = positions[P][i][X];
1316         int y = positions[P][i][Y];
1317
1318         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1319         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1320         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1321         if (out->data[3])
1322             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1323     }
1324
1325     if (s->flags & 1) {
1326         int x = positions[P][12][X];
1327         int y = positions[P][12][Y];
1328
1329         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1330         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1331         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1332         if (out->data[3])
1333             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1334     }
1335
1336     if (s->flags & 2) {
1337         int x = positions[P][13][X];
1338         int y = positions[P][13][Y];
1339
1340         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1341         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1342         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1343         if (out->data[3])
1344             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1345     }
1346
1347     for (i = 0; i < 6 && s->flags & 4; i++) {
1348         uint16_t color[4] = { max, max, max, max };
1349         int x = positions[P][i][X];
1350         int y = positions[P][i][Y];
1351
1352         if (x > max / 2)
1353             x += 8;
1354         else
1355             x -= 14;
1356         if (y > max / 2)
1357             y += 8;
1358         else
1359             y -= 14;
1360
1361         x = av_clip(x, 0, out->width - 9);
1362         y = av_clip(y, 0, out->height - 9);
1363         draw_ihtext16(out, x, y, o, 1. - o, positions_name[i], color);
1364     }
1365 }
1366
1367 static void invert_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1368 {
1369     const float o = s->opacity;
1370     int i;
1371
1372     for (i = 0; i < 12; i++) {
1373         int x = positions[P][i][X];
1374         int y = positions[P][i][Y];
1375
1376         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1377         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1378         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1379         if (out->data[3])
1380             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1381     }
1382
1383     if (s->flags & 1) {
1384         int x = positions[P][12][X];
1385         int y = positions[P][12][Y];
1386
1387         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1388         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1389         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1390         if (out->data[3])
1391             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1392     }
1393
1394     if (s->flags & 2) {
1395         int x = positions[P][13][X];
1396         int y = positions[P][13][Y];
1397
1398         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1399         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1400         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1401         if (out->data[3])
1402             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1403     }
1404
1405     for (i = 0; i < 6 && s->flags & 4; i++) {
1406         uint8_t color[4] = { 255, 255, 255, 255 };
1407         int x = positions[P][i][X];
1408         int y = positions[P][i][Y];
1409
1410         if (x > 128)
1411             x += 8;
1412         else
1413             x -= 14;
1414         if (y > 128)
1415             y += 8;
1416         else
1417             y -= 14;
1418
1419         x = av_clip(x, 0, out->width - 9);
1420         y = av_clip(y, 0, out->height - 9);
1421         draw_ihtext(out, x, y, o, 1. - o, positions_name[i], color);
1422     }
1423 }
1424
1425 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1426 {
1427     AVFilterContext *ctx  = inlink->dst;
1428     VectorscopeContext *s = ctx->priv;
1429     AVFilterLink *outlink = ctx->outputs[0];
1430     AVFrame *out;
1431     int plane;
1432
1433     if (s->colorspace) {
1434         s->cs = (s->depth - 8) * 2 + s->colorspace - 1;
1435     } else {
1436         switch (in->colorspace) {
1437         case AVCOL_SPC_SMPTE170M:
1438         case AVCOL_SPC_BT470BG:
1439             s->cs = (s->depth - 8) * 2 + 0;
1440             break;
1441         case AVCOL_SPC_BT709:
1442         default:
1443             s->cs = (s->depth - 8) * 2 + 1;
1444         }
1445     }
1446
1447     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1448     if (!out) {
1449         av_frame_free(&in);
1450         return AVERROR(ENOMEM);
1451     }
1452     av_frame_copy_props(out, in);
1453
1454     s->vectorscope(s, in, out, s->pd);
1455     s->graticulef(s, out, s->x, s->y, s->pd, s->cs);
1456
1457     for (plane = 0; plane < 4; plane++) {
1458         if (out->data[plane]) {
1459             out->data[plane]    += (s->size - 1) * out->linesize[plane];
1460             out->linesize[plane] = -out->linesize[plane];
1461         }
1462     }
1463
1464     av_frame_free(&in);
1465     return ff_filter_frame(outlink, out);
1466 }
1467
1468 static int config_input(AVFilterLink *inlink)
1469 {
1470     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
1471     AVFilterContext *ctx = inlink->dst;
1472     VectorscopeContext *s = ctx->priv;
1473
1474     s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB);
1475     s->size = 1 << desc->comp[0].depth;
1476     s->mult = s->size / 256;
1477     s->depth = desc->comp[0].depth;
1478     s->tmin = s->lthreshold * (s->size - 1);
1479     s->tmax = s->hthreshold * (s->size - 1);
1480
1481     if (s->tmin > s->tmax) {
1482         av_log(ctx, AV_LOG_ERROR, "low threshold should be less than high threshold\n");
1483         return AVERROR(EINVAL);
1484     }
1485
1486     if (s->mode == GRAY && s->is_yuv)
1487         s->pd = 0;
1488     else {
1489         if ((s->x == 1 && s->y == 2) || (s->x == 2 && s->y == 1))
1490             s->pd = 0;
1491         else if ((s->x == 0 && s->y == 2) || (s->x == 2 && s->y == 0))
1492             s->pd = 1;
1493         else if ((s->x == 0 && s->y == 1) || (s->x == 1 && s->y == 0))
1494             s->pd = 2;
1495     }
1496
1497     if (s->size == 256)
1498         s->vectorscope = vectorscope8;
1499     else
1500         s->vectorscope = vectorscope16;
1501
1502     s->graticulef = none_graticule;
1503
1504     if (s->is_yuv && s->size == 256) {
1505         if (s->graticule == GRAT_GREEN)
1506             s->graticulef = green_graticule;
1507         else if (s->graticule == GRAT_COLOR)
1508             s->graticulef = color_graticule;
1509         else if (s->graticule == GRAT_INVERT)
1510             s->graticulef = invert_graticule;
1511     } else if (s->is_yuv) {
1512         if (s->graticule == GRAT_GREEN)
1513             s->graticulef = green_graticule16;
1514         else if (s->graticule == GRAT_COLOR)
1515             s->graticulef = color_graticule16;
1516         else if (s->graticule == GRAT_INVERT)
1517             s->graticulef = invert_graticule16;
1518     }
1519
1520     s->bg_color[3] = s->bgopacity * (s->size - 1);
1521
1522     switch (inlink->format) {
1523     case AV_PIX_FMT_GBRP12:
1524     case AV_PIX_FMT_GBRP10:
1525     case AV_PIX_FMT_GBRP9:
1526     case AV_PIX_FMT_GBRAP:
1527     case AV_PIX_FMT_GBRP:
1528         s->bg_color[0] = 0;
1529         s->bg_color[1] = 0;
1530         s->bg_color[2] = 0;
1531         break;
1532     default:
1533         s->bg_color[0] = 0;
1534         s->bg_color[1] = s->size / 2 - 1;
1535         s->bg_color[2] = s->size / 2 - 1;
1536     }
1537
1538     s->hsub = desc->log2_chroma_w;
1539     s->vsub = desc->log2_chroma_h;
1540     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
1541     s->planeheight[0] = s->planeheight[3] = inlink->h;
1542     s->planewidth[1]  = s->planewidth[2]  = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
1543     s->planewidth[0]  = s->planewidth[3]  = inlink->w;
1544
1545     return 0;
1546 }
1547
1548 static av_cold void uninit(AVFilterContext *ctx)
1549 {
1550     VectorscopeContext *s = ctx->priv;
1551
1552     av_freep(&s->peak);
1553     av_freep(&s->peak_memory);
1554 }
1555
1556 static const AVFilterPad inputs[] = {
1557     {
1558         .name         = "default",
1559         .type         = AVMEDIA_TYPE_VIDEO,
1560         .filter_frame = filter_frame,
1561         .config_props = config_input,
1562     },
1563     { NULL }
1564 };
1565
1566 static const AVFilterPad outputs[] = {
1567     {
1568         .name         = "default",
1569         .type         = AVMEDIA_TYPE_VIDEO,
1570         .config_props = config_output,
1571     },
1572     { NULL }
1573 };
1574
1575 AVFilter ff_vf_vectorscope = {
1576     .name          = "vectorscope",
1577     .description   = NULL_IF_CONFIG_SMALL("Video vectorscope."),
1578     .priv_size     = sizeof(VectorscopeContext),
1579     .priv_class    = &vectorscope_class,
1580     .query_formats = query_formats,
1581     .uninit        = uninit,
1582     .inputs        = inputs,
1583     .outputs       = outputs,
1584 };