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