]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_vectorscope.c
avfilter/vf_vectorscope: rename gray mode to tint mode
[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     const int max = s->size - 1;
437     const int mid = s->size / 2;
438     const int tmin = s->tmin;
439     const int tmax = s->tmax;
440     int i, j, k;
441
442     for (k = 0; k < 4 && dst[k]; k++) {
443         for (i = 0; i < out->height ; i++)
444             for (j = 0; j < out->width; j++)
445                 AV_WN16(out->data[k] + i * out->linesize[k] + j * 2,
446                         (s->mode == COLOR || s->mode == COLOR5) && k == s->pd ? 0 : s->bg_color[k]);
447     }
448
449     switch (s->mode) {
450     case COLOR:
451     case COLOR5:
452     case TINT:
453         if (s->is_yuv) {
454             for (i = 0; i < h; i++) {
455                 const int iwx = i * slinesizex;
456                 const int iwy = i * slinesizey;
457                 const int iwd = i * slinesized;
458                 for (j = 0; j < w; j++) {
459                     const int x = FFMIN(spx[iwx + j], max);
460                     const int y = FFMIN(spy[iwy + j], max);
461                     const int z = spd[iwd + j];
462                     const int pos = y * dlinesize + x;
463
464                     if (z < tmin || z > tmax)
465                         continue;
466
467                     dpd[pos] = FFMIN(dpd[pos] + intensity, max);
468                 }
469             }
470         } else {
471             for (i = 0; i < h; i++) {
472                 const int iwx = i * slinesizex;
473                 const int iwy = i * slinesizey;
474                 const int iwd = i * slinesized;
475                 for (j = 0; j < w; j++) {
476                     const int x = FFMIN(spx[iwx + j], max);
477                     const int y = FFMIN(spy[iwy + j], max);
478                     const int z = spd[iwd + j];
479                     const int pos = y * dlinesize + x;
480
481                     if (z < tmin || z > tmax)
482                         continue;
483
484                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, max);
485                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, max);
486                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, max);
487                 }
488             }
489         }
490         break;
491     case COLOR2:
492         if (s->is_yuv) {
493             for (i = 0; i < h; i++) {
494                 const int iw1 = i * slinesizex;
495                 const int iw2 = i * slinesizey;
496                 const int iwd = i * slinesized;
497                 for (j = 0; j < w; j++) {
498                     const int x = FFMIN(spx[iw1 + j], max);
499                     const int y = FFMIN(spy[iw2 + j], max);
500                     const int z = spd[iwd + j];
501                     const int pos = y * dlinesize + x;
502
503                     if (z < tmin || z > tmax)
504                         continue;
505
506                     if (!dpd[pos])
507                         dpd[pos] = FFABS(mid - x) + FFABS(mid - y);
508                     dpx[pos] = x;
509                     dpy[pos] = y;
510                 }
511             }
512         } else {
513             for (i = 0; i < h; i++) {
514                 const int iw1 = i * slinesizex;
515                 const int iw2 = i * slinesizey;
516                 const int iwd = i * slinesized;
517                 for (j = 0; j < w; j++) {
518                     const int x = FFMIN(spx[iw1 + j], max);
519                     const int y = FFMIN(spy[iw2 + j], max);
520                     const int z = spd[iwd + j];
521                     const int pos = y * dlinesize + x;
522
523                     if (z < tmin || z > tmax)
524                         continue;
525
526                     if (!dpd[pos])
527                         dpd[pos] = FFMIN(x + y, max);
528                     dpx[pos] = x;
529                     dpy[pos] = y;
530                 }
531             }
532         }
533         break;
534     case COLOR3:
535         for (i = 0; i < h; i++) {
536             const int iw1 = i * slinesizex;
537             const int iw2 = i * slinesizey;
538             const int iwd = i * slinesized;
539             for (j = 0; j < w; j++) {
540                 const int x = FFMIN(spx[iw1 + j], max);
541                 const int y = FFMIN(spy[iw2 + j], max);
542                 const int z = spd[iwd + j];
543                 const int pos = y * dlinesize + x;
544
545                 if (z < tmin || z > tmax)
546                     continue;
547
548                 dpd[pos] = FFMIN(max, dpd[pos] + intensity);
549                 dpx[pos] = x;
550                 dpy[pos] = y;
551             }
552         }
553         break;
554     case COLOR4:
555         for (i = 0; i < in->height; i++) {
556             const int iwx = (i >> vsub) * slinesizex;
557             const int iwy = (i >> vsub) * slinesizey;
558             const int iwd = i * slinesized;
559             for (j = 0; j < in->width; j++) {
560                 const int x = FFMIN(spx[iwx + (j >> hsub)], max);
561                 const int y = FFMIN(spy[iwy + (j >> hsub)], max);
562                 const int z = spd[iwd + j];
563                 const int pos = y * dlinesize + x;
564
565                 if (z < tmin || z > tmax)
566                     continue;
567
568                 dpd[pos] = FFMAX(z, dpd[pos]);
569                 dpx[pos] = x;
570                 dpy[pos] = y;
571             }
572         }
573         break;
574     default:
575         av_assert0(0);
576     }
577
578     envelope16(s, out);
579
580     if (dst[3]) {
581         for (i = 0; i < out->height; i++) {
582             for (j = 0; j < out->width; j++) {
583                 int pos = i * dlinesize + j;
584
585                 if (dpd[pos])
586                     dst[3][pos] = max;
587             }
588         }
589     }
590
591     if (s->mode == TINT && (s->tint[0] != mid ||
592                             s->tint[1] != mid)) {
593         for (i = 0; i < out->height; i++) {
594             for (j = 0; j < out->width; j++) {
595                 if (dpd[i * dlinesize + j]) {
596                     dst[1][i * dlinesize + j] = s->tint[0];
597                     dst[2][i * dlinesize + j] = s->tint[1];
598                 }
599             }
600         }
601     } else if (s->mode == COLOR) {
602         for (i = 0; i < out->height; i++) {
603             for (j = 0; j < out->width; j++) {
604                 if (!dpd[i * dlinesize + j]) {
605                     dpx[i * dlinesize + j] = j;
606                     dpy[i * dlinesize + j] = i;
607                     dpd[i * dlinesize + j] = mid;
608                 }
609             }
610         }
611     } else if (s->mode == COLOR5) {
612         for (i = 0; i < out->height; i++) {
613             for (j = 0; j < out->width; j++) {
614                 if (!dpd[i * dlinesize + j]) {
615                     dpx[i * dlinesize + j] = j;
616                     dpy[i * dlinesize + j] = i;
617                     dpd[i * dlinesize + j] = mid * M_SQRT2 - hypot(i - mid, j - mid);
618                 }
619             }
620         }
621     }
622 }
623
624 static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int pd)
625 {
626     const uint8_t * const *src = (const uint8_t * const *)in->data;
627     const int slinesizex = in->linesize[s->x];
628     const int slinesizey = in->linesize[s->y];
629     const int slinesized = in->linesize[pd];
630     const int dlinesize = out->linesize[0];
631     const int intensity = s->intensity;
632     const int px = s->x, py = s->y;
633     const int h = s->planeheight[py];
634     const int w = s->planewidth[px];
635     const uint8_t *spx = src[px];
636     const uint8_t *spy = src[py];
637     const uint8_t *spd = src[pd];
638     const int hsub = s->hsub;
639     const int vsub = s->vsub;
640     uint8_t **dst = out->data;
641     uint8_t *dpx = dst[px];
642     uint8_t *dpy = dst[py];
643     uint8_t *dpd = dst[pd];
644     const int tmin = s->tmin;
645     const int tmax = s->tmax;
646     int i, j, k;
647
648     for (k = 0; k < 4 && dst[k]; k++)
649         for (i = 0; i < out->height ; i++)
650             memset(dst[k] + i * out->linesize[k],
651                    (s->mode == COLOR || s->mode == COLOR5) && k == s->pd ? 0 : s->bg_color[k], out->width);
652
653     switch (s->mode) {
654     case COLOR5:
655     case COLOR:
656     case TINT:
657         if (s->is_yuv) {
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                     dpd[pos] = FFMIN(dpd[pos] + intensity, 255);
672                 }
673             }
674         } else {
675             for (i = 0; i < h; i++) {
676                 const int iwx = i * slinesizex;
677                 const int iwy = i * slinesizey;
678                 const int iwd = i * slinesized;
679                 for (j = 0; j < w; j++) {
680                     const int x = spx[iwx + j];
681                     const int y = spy[iwy + j];
682                     const int z = spd[iwd + j];
683                     const int pos = y * dlinesize + x;
684
685                     if (z < tmin || z > tmax)
686                         continue;
687
688                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, 255);
689                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, 255);
690                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, 255);
691                 }
692             }
693         }
694         break;
695     case COLOR2:
696         if (s->is_yuv) {
697             for (i = 0; i < h; i++) {
698                 const int iw1 = i * slinesizex;
699                 const int iw2 = i * slinesizey;
700                 const int iwd = i * slinesized;
701                 for (j = 0; j < w; j++) {
702                     const int x = spx[iw1 + j];
703                     const int y = spy[iw2 + j];
704                     const int z = spd[iwd + j];
705                     const int pos = y * dlinesize + x;
706
707                     if (z < tmin || z > tmax)
708                         continue;
709
710                     if (!dpd[pos])
711                         dpd[pos] = FFABS(128 - x) + FFABS(128 - y);
712                     dpx[pos] = x;
713                     dpy[pos] = y;
714                 }
715             }
716         } else {
717             for (i = 0; i < h; i++) {
718                 const int iw1 = i * slinesizex;
719                 const int iw2 = i * slinesizey;
720                 const int iwd = i * slinesized;
721                 for (j = 0; j < w; j++) {
722                     const int x = spx[iw1 + j];
723                     const int y = spy[iw2 + j];
724                     const int z = spd[iwd + j];
725                     const int pos = y * dlinesize + x;
726
727                     if (z < tmin || z > tmax)
728                         continue;
729
730                     if (!dpd[pos])
731                         dpd[pos] = FFMIN(x + y, 255);
732                     dpx[pos] = x;
733                     dpy[pos] = y;
734                 }
735             }
736         }
737         break;
738     case COLOR3:
739         for (i = 0; i < h; i++) {
740             const int iw1 = i * slinesizex;
741             const int iw2 = i * slinesizey;
742             const int iwd = i * slinesized;
743             for (j = 0; j < w; j++) {
744                 const int x = spx[iw1 + j];
745                 const int y = spy[iw2 + j];
746                 const int z = spd[iwd + j];
747                 const int pos = y * dlinesize + x;
748
749                 if (z < tmin || z > tmax)
750                     continue;
751
752                 dpd[pos] = FFMIN(255, dpd[pos] + intensity);
753                 dpx[pos] = x;
754                 dpy[pos] = y;
755             }
756         }
757         break;
758     case COLOR4:
759         for (i = 0; i < in->height; i++) {
760             const int iwx = (i >> vsub) * slinesizex;
761             const int iwy = (i >> vsub) * slinesizey;
762             const int iwd = i * slinesized;
763             for (j = 0; j < in->width; j++) {
764                 const int x = spx[iwx + (j >> hsub)];
765                 const int y = spy[iwy + (j >> hsub)];
766                 const int z = spd[iwd + j];
767                 const int pos = y * dlinesize + x;
768
769                 if (z < tmin || z > tmax)
770                     continue;
771
772                 dpd[pos] = FFMAX(z, dpd[pos]);
773                 dpx[pos] = x;
774                 dpy[pos] = y;
775             }
776         }
777         break;
778     default:
779         av_assert0(0);
780     }
781
782     envelope(s, out);
783
784     if (dst[3]) {
785         for (i = 0; i < out->height; i++) {
786             for (j = 0; j < out->width; j++) {
787                 int pos = i * dlinesize + j;
788
789                 if (dpd[pos])
790                     dst[3][pos] = 255;
791             }
792         }
793     }
794
795     if (s->mode == TINT && (s->tint[0] != 128 ||
796                             s->tint[1] != 128)) {
797         for (i = 0; i < out->height; i++) {
798             for (j = 0; j < out->width; j++) {
799                 if (dpd[i * dlinesize + j]) {
800                     dst[1][i * dlinesize + j] = s->tint[0];
801                     dst[2][i * dlinesize + j] = s->tint[1];
802                 }
803             }
804         }
805     } else if (s->mode == COLOR) {
806         for (i = 0; i < out->height; i++) {
807             for (j = 0; j < out->width; j++) {
808                 if (!dpd[i * out->linesize[pd] + j]) {
809                     dpx[i * out->linesize[px] + j] = j;
810                     dpy[i * out->linesize[py] + j] = i;
811                     dpd[i * out->linesize[pd] + j] = 128;
812                 }
813             }
814         }
815     } else if (s->mode == COLOR5) {
816         for (i = 0; i < out->height; i++) {
817             for (j = 0; j < out->width; j++) {
818                 if (!dpd[i * out->linesize[pd] + j]) {
819                     dpx[i * out->linesize[px] + j] = j;
820                     dpy[i * out->linesize[py] + j] = i;
821                     dpd[i * out->linesize[pd] + j] = 128 * M_SQRT2 - hypot(i - 128, j - 128);
822                 }
823             }
824         }
825     }
826 }
827
828 const static char *positions_name[] = {
829     "R", "B", "Cy", "Yl", "G", "Mg",
830 };
831
832 const static uint16_t positions[][14][3] = {
833   {
834     {  81,  90, 240 }, {  41, 240, 110 }, { 170, 166,  16 },
835     { 210,  16, 146 }, { 145,  54,  34 }, { 106, 202, 222 },
836     { 162,  44, 142 }, { 131, 156,  44 }, { 112,  72,  58 },
837     {  84, 184, 198 }, {  65, 100, 212 }, {  35, 212, 114 },
838     { 235, 128, 128 }, { 16, 128, 128 } },
839   { {  63, 102, 240 }, {  32, 240, 118 }, { 188, 154,  16 },
840     { 219,  16, 138 }, { 173,  42,  26 }, {  78, 214, 230 },
841     {  28, 212, 120 }, {  51, 109, 212 }, {  63, 193, 204 },
842     { 133,  63,  52 }, { 145, 147,  44 }, { 168,  44, 136 },
843     { 235, 128, 128 }, { 16, 128, 128 } },
844   { {  81*2,  90*2, 240*2 }, {  41*2, 240*2, 110*2 }, { 170*2, 166*2,  16*2 },
845     { 210*2,  16*2, 146*2 }, { 145*2,  54*2,  34*2 }, { 106*2, 202*2, 222*2 },
846     { 162*2,  44*2, 142*2 }, { 131*2, 156*2,  44*2 }, { 112*2,  72*2,  58*2 },
847     {  84*2, 184*2, 198*2 }, {  65*2, 100*2, 212*2 }, {  35*2, 212*2, 114*2 },
848     { 470, 256, 256 }, { 32, 256, 256 } },
849   { {  63*2, 102*2, 240*2 }, {  32*2, 240*2, 118*2 }, { 188*2, 154*2,  16*2 },
850     { 219*2,  16*2, 138*2 }, { 173*2,  42*2,  26*2 }, {  78*2, 214*2, 230*2 },
851     {  28*2, 212*2, 120*2 }, {  51*2, 109*2, 212*2 }, {  63*2, 193*2, 204*2 },
852     { 133*2,  63*2,  52*2 }, { 145*2, 147*2,  44*2 }, { 168*2,  44*2, 136*2 },
853     { 470, 256, 256 }, { 32, 256, 256 } },
854   { {  81*4,  90*4, 240*4 }, {  41*4, 240*4, 110*4 }, { 170*4, 166*4,  16*4 },
855     { 210*4,  16*4, 146*4 }, { 145*4,  54*4,  34*4 }, { 106*4, 202*4, 222*4 },
856     { 162*4,  44*4, 142*4 }, { 131*4, 156*4,  44*4 }, { 112*4,  72*4,  58*4 },
857     {  84*4, 184*4, 198*4 }, {  65*4, 100*4, 212*4 }, {  35*4, 212*4, 114*4 },
858     { 940, 512, 512 }, { 64, 512, 512 } },
859   { {  63*4, 102*4, 240*4 }, {  32*4, 240*4, 118*4 }, { 188*4, 154*4,  16*4 },
860     { 219*4,  16*4, 138*4 }, { 173*4,  42*4,  26*4 }, {  78*4, 214*4, 230*4 },
861     {  28*4, 212*4, 120*4 }, {  51*4, 109*4, 212*4 }, {  63*4, 193*4, 204*4 },
862     { 133*4,  63*4,  52*4 }, { 145*4, 147*4,  44*4 }, { 168*4,  44*4, 136*4 },
863     { 940, 512, 512 }, { 64, 512, 512 } },
864   { {  81*8,  90*4, 240*8 }, {  41*8, 240*8, 110*8 }, { 170*8, 166*8,  16*8 },
865     { 210*8,  16*4, 146*8 }, { 145*8,  54*8,  34*8 }, { 106*8, 202*8, 222*8 },
866     { 162*8,  44*4, 142*8 }, { 131*8, 156*8,  44*8 }, { 112*8,  72*8,  58*8 },
867     {  84*8, 184*4, 198*8 }, {  65*8, 100*8, 212*8 }, {  35*8, 212*8, 114*8 },
868     { 1880, 1024, 1024 }, { 128, 1024, 1024 } },
869   { {  63*8, 102*8, 240*8 }, {  32*8, 240*8, 118*8 }, { 188*8, 154*8,  16*8 },
870     { 219*8,  16*8, 138*8 }, { 173*8,  42*8,  26*8 }, {  78*8, 214*8, 230*8 },
871     {  28*8, 212*8, 120*8 }, {  51*8, 109*8, 212*8 }, {  63*8, 193*8, 204*8 },
872     { 133*8,  63*8,  52*8 }, { 145*8, 147*8,  44*8 }, { 168*8,  44*8, 136*8 },
873     { 1880, 1024, 1024 }, { 128, 1024, 1024 } },
874   { {  81*16,  90*16, 240*16 }, {  41*16, 240*16, 110*16 }, { 170*16, 166*16,  16*16 },
875     { 210*16,  16*16, 146*16 }, { 145*16,  54*16,  34*16 }, { 106*16, 202*16, 222*16 },
876     { 162*16,  44*16, 142*16 }, { 131*16, 156*16,  44*16 }, { 112*16,  72*16,  58*16 },
877     {  84*16, 184*16, 198*16 }, {  65*16, 100*16, 212*16 }, {  35*16, 212*16, 114*16 },
878     { 3760, 2048, 2048 }, { 256, 2048, 2048 } },
879   { {  63*16, 102*16, 240*16 }, {  32*16, 240*16, 118*16 }, { 188*16, 154*16,  16*16 },
880     { 219*16,  16*16, 138*16 }, { 173*16,  42*16,  26*16 }, {  78*16, 214*16, 230*16 },
881     {  28*16, 212*16, 120*16 }, {  51*16, 109*16, 212*16 }, {  63*16, 193*16, 204*16 },
882     { 133*16,  63*16,  52*16 }, { 145*16, 147*16,  44*16 }, { 168*16,  44*16, 136*16 },
883     { 3760, 2048, 2048 }, { 256, 2048, 2048 } },
884 };
885
886 static void draw_dots(uint8_t *dst, int L, int v, float o)
887 {
888     const float f = 1. - o;
889     const float V = o * v;
890     int l = L * 2;
891
892     dst[ l - 3] = dst[ l - 3] * f + V;
893     dst[ l + 3] = dst[ l + 3] * f + V;
894     dst[-l - 3] = dst[-l - 3] * f + V;
895     dst[-l + 3] = dst[-l + 3] * f + V;
896
897     l += L;
898
899     dst[ l - 3] = dst[ l - 3] * f + V;
900     dst[ l + 3] = dst[ l + 3] * f + V;
901     dst[ l - 2] = dst[ l - 2] * f + V;
902     dst[ l + 2] = dst[ l + 2] * f + V;
903     dst[-l - 3] = dst[-l - 3] * f + V;
904     dst[-l + 3] = dst[-l + 3] * f + V;
905     dst[-l - 2] = dst[-l - 2] * f + V;
906     dst[-l + 2] = dst[-l + 2] * f + V;
907 }
908
909 static void draw_idots(uint8_t *dst, int L, float o)
910 {
911     const float f = 1. - o;
912     int l = L * 2;
913
914     dst[ l - 3] = dst[ l - 3] * f + (255 - dst[ l - 3]) * o;
915     dst[ l + 3] = dst[ l + 3] * f + (255 - dst[ l + 3]) * o;
916     dst[-l - 3] = dst[-l - 3] * f + (255 - dst[-l - 3]) * o;
917     dst[-l + 3] = dst[-l + 3] * f + (255 - dst[-l + 3]) * o;
918
919     l += L;
920
921     dst[ l - 3] = dst[ l - 3] * f + (255 - dst[ l - 3]) * o;
922     dst[ l + 3] = dst[ l + 3] * f + (255 - dst[ l + 3]) * o;
923     dst[ l - 2] = dst[ l - 2] * f + (255 - dst[ l - 2]) * o;
924     dst[ l + 2] = dst[ l + 2] * f + (255 - dst[ l + 2]) * o;
925     dst[-l - 3] = dst[-l - 3] * f + (255 - dst[-l - 3]) * o;
926     dst[-l + 3] = dst[-l + 3] * f + (255 - dst[-l + 3]) * o;
927     dst[-l - 2] = dst[-l - 2] * f + (255 - dst[-l - 2]) * o;
928     dst[-l + 2] = dst[-l + 2] * f + (255 - dst[-l + 2]) * o;
929 }
930
931 static void draw_dots16(uint16_t *dst, int L, int v, float o)
932 {
933     const float f = 1. - o;
934     const float V = o * v;
935     int l = L * 2;
936
937     dst[ l - 3] = dst[ l - 3] * f + V;
938     dst[ l + 3] = dst[ l + 3] * f + V;
939     dst[-l - 3] = dst[-l - 3] * f + V;
940     dst[-l + 3] = dst[-l + 3] * f + V;
941
942     l += L;
943
944     dst[ l - 3] = dst[ l - 3] * f + V;
945     dst[ l + 3] = dst[ l + 3] * f + V;
946     dst[ l - 2] = dst[ l - 2] * f + V;
947     dst[ l + 2] = dst[ l + 2] * f + V;
948     dst[-l - 3] = dst[-l - 3] * f + V;
949     dst[-l + 3] = dst[-l + 3] * f + V;
950     dst[-l - 2] = dst[-l - 2] * f + V;
951     dst[-l + 2] = dst[-l + 2] * f + V;
952 }
953
954 static void draw_idots16(uint16_t *dst, int L, int v, float o)
955 {
956     const float f = 1. - o;
957     int l = L * 2;
958
959     dst[ l - 3] = dst[ l - 3] * f + (v - dst[ l - 3]) * o;
960     dst[ l + 3] = dst[ l + 3] * f + (v - dst[ l + 3]) * o;
961     dst[-l - 3] = dst[-l - 3] * f + (v - dst[-l - 3]) * o;
962     dst[-l + 3] = dst[-l + 3] * f + (v - dst[-l + 3]) * o;
963
964     l += L;
965
966     dst[ l - 3] = dst[ l - 3] * f + (v - dst[ l - 3]) * o;
967     dst[ l + 3] = dst[ l + 3] * f + (v - dst[ l + 3]) * o;
968     dst[ l - 2] = dst[ l - 2] * f + (v - dst[ l - 2]) * o;
969     dst[ l + 2] = dst[ l + 2] * f + (v - dst[ l + 2]) * o;
970     dst[-l - 3] = dst[-l - 3] * f + (v - dst[-l - 3]) * o;
971     dst[-l + 3] = dst[-l + 3] * f + (v - dst[-l + 3]) * o;
972     dst[-l - 2] = dst[-l - 2] * f + (v - dst[-l - 2]) * o;
973     dst[-l + 2] = dst[-l + 2] * f + (v - dst[-l + 2]) * o;
974 }
975
976 static void none_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
977 {
978 }
979
980 static void draw_ihtext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
981 {
982     const uint8_t *font;
983     int font_height;
984     int i, plane;
985
986     font = avpriv_cga_font,   font_height =  8;
987
988     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
989         for (i = 0; txt[i]; i++) {
990             int char_y, mask;
991
992             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
993             for (char_y = font_height - 1; char_y >= 0; char_y--) {
994                 for (mask = 0x80; mask; mask >>= 1) {
995                     if (font[txt[i] * font_height + char_y] & mask)
996                         p[0] = p[0] * o2 + (255 - p[0]) * o1;
997                     p++;
998                 }
999                 p += out->linesize[plane] - 8;
1000             }
1001         }
1002     }
1003 }
1004
1005 static void draw_ihtext16(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint16_t color[4])
1006 {
1007     const uint8_t *font;
1008     int font_height;
1009     int i, plane;
1010
1011     font = avpriv_cga_font,   font_height =  8;
1012
1013     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
1014         for (i = 0; txt[i]; i++) {
1015             int char_y, mask;
1016             int v = color[plane];
1017
1018             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
1019             for (char_y = font_height - 1; char_y >= 0; char_y--) {
1020                 for (mask = 0x80; mask; mask >>= 1) {
1021                     if (font[txt[i] * font_height + char_y] & mask)
1022                         p[0] = p[0] * o2 + (v - p[0]) * o1;
1023                     p++;
1024                 }
1025                 p += out->linesize[plane] / 2 - 8;
1026             }
1027         }
1028     }
1029 }
1030
1031 static void draw_htext(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint8_t color[4])
1032 {
1033     const uint8_t *font;
1034     int font_height;
1035     int i, plane;
1036
1037     font = avpriv_cga_font,   font_height =  8;
1038
1039     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
1040         for (i = 0; txt[i]; i++) {
1041             int char_y, mask;
1042             int v = color[plane];
1043
1044             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
1045             for (char_y = font_height - 1; char_y >= 0; char_y--) {
1046                 for (mask = 0x80; mask; mask >>= 1) {
1047                     if (font[txt[i] * font_height + char_y] & mask)
1048                         p[0] = p[0] * o2 + v * o1;
1049                     p++;
1050                 }
1051                 p += out->linesize[plane] - 8;
1052             }
1053         }
1054     }
1055 }
1056
1057 static void draw_htext16(AVFrame *out, int x, int y, float o1, float o2, const char *txt, const uint16_t color[4])
1058 {
1059     const uint8_t *font;
1060     int font_height;
1061     int i, plane;
1062
1063     font = avpriv_cga_font,   font_height =  8;
1064
1065     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
1066         for (i = 0; txt[i]; i++) {
1067             int char_y, mask;
1068             int v = color[plane];
1069
1070             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
1071             for (char_y = font_height - 1; char_y >= 0; char_y--) {
1072                 for (mask = 0x80; mask; mask >>= 1) {
1073                     if (font[txt[i] * font_height + char_y] & mask)
1074                         p[0] = p[0] * o2 + v * o1;
1075                     p++;
1076                 }
1077                 p += out->linesize[plane] / 2 - 8;
1078             }
1079         }
1080     }
1081 }
1082
1083 static void color_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1084 {
1085     const int max = s->size - 1;
1086     const float o = s->opacity;
1087     int i;
1088
1089     for (i = 0; i < 12; i++) {
1090         int x = positions[P][i][X];
1091         int y = positions[P][i][Y];
1092         int d = positions[P][i][D];
1093
1094         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1095         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1096         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1097         if (out->data[3])
1098             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1099     }
1100
1101     if (s->flags & 1) {
1102         int x = positions[P][12][X];
1103         int y = positions[P][12][Y];
1104         int d = positions[P][12][D];
1105
1106         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1107         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1108         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1109         if (out->data[3])
1110             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1111     }
1112
1113     if (s->flags & 2) {
1114         int x = positions[P][13][X];
1115         int y = positions[P][13][Y];
1116         int d = positions[P][13][D];
1117
1118         draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
1119         draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
1120         draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
1121         if (out->data[3])
1122             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1123     }
1124
1125     for (i = 0; i < 6 && s->flags & 4; i++) {
1126         uint16_t color[4] = { 0, 0, 0, 0 };
1127         int x = positions[P][i][X];
1128         int y = positions[P][i][Y];
1129         int d = positions[P][i][D];
1130
1131         color[D] = d;
1132         color[X] = x;
1133         color[Y] = y;
1134         color[3] = max;
1135
1136         if (x > max / 2)
1137             x += 8;
1138         else
1139             x -= 14;
1140         if (y > max / 2)
1141             y += 8;
1142         else
1143             y -= 14;
1144
1145         x = av_clip(x, 0, out->width - 9);
1146         y = av_clip(y, 0, out->height - 9);
1147         draw_htext16(out, x, y, o, 1. - o, positions_name[i], color);
1148     }
1149 }
1150
1151 static void color_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1152 {
1153     const float o = s->opacity;
1154     int i;
1155
1156     for (i = 0; i < 12; i++) {
1157         int x = positions[P][i][X];
1158         int y = positions[P][i][Y];
1159         int d = positions[P][i][D];
1160
1161         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1162         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1163         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1164         if (out->data[3])
1165             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1166     }
1167
1168     if (s->flags & 1) {
1169         int x = positions[P][12][X];
1170         int y = positions[P][12][Y];
1171         int d = positions[P][12][D];
1172
1173         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1174         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1175         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1176         if (out->data[3])
1177             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1178     }
1179
1180     if (s->flags & 2) {
1181         int x = positions[P][13][X];
1182         int y = positions[P][13][Y];
1183         int d = positions[P][12][D];
1184
1185         draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
1186         draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
1187         draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
1188         if (out->data[3])
1189             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1190     }
1191
1192     for (i = 0; i < 6 && s->flags & 4; i++) {
1193         uint8_t color[4] = { 0, 0, 0, 255 };
1194         int x = positions[P][i][X];
1195         int y = positions[P][i][Y];
1196         int d = positions[P][i][D];
1197
1198         color[D] = d;
1199         color[X] = x;
1200         color[Y] = y;
1201
1202         if (x > 128)
1203             x += 8;
1204         else
1205             x -= 14;
1206         if (y > 128)
1207             y += 8;
1208         else
1209             y -= 14;
1210
1211         x = av_clip(x, 0, out->width - 9);
1212         y = av_clip(y, 0, out->height - 9);
1213         draw_htext(out, x, y, o, 1. - o, positions_name[i], color);
1214     }
1215 }
1216
1217 static void green_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1218 {
1219     const int max = s->size - 1;
1220     const float o = s->opacity;
1221     const int m = s->mult;
1222     int i;
1223
1224     for (i = 0; i < 12; i++) {
1225         int x = positions[P][i][X];
1226         int y = positions[P][i][Y];
1227
1228         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1229         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1230         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1231         if (out->data[3])
1232             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1233     }
1234
1235     if (s->flags & 1) {
1236         int x = positions[P][12][X];
1237         int y = positions[P][12][Y];
1238
1239         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1240         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1241         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1242         if (out->data[3])
1243             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1244     }
1245
1246     if (s->flags & 2) {
1247         int x = positions[P][13][X];
1248         int y = positions[P][13][Y];
1249
1250         draw_dots16((uint16_t *)(out->data[0] + y * out->linesize[0] + x * 2), out->linesize[0] / 2, 128 * m, o);
1251         draw_dots16((uint16_t *)(out->data[1] + y * out->linesize[1] + x * 2), out->linesize[1] / 2, 0, o);
1252         draw_dots16((uint16_t *)(out->data[2] + y * out->linesize[2] + x * 2), out->linesize[2] / 2, 0, o);
1253         if (out->data[3])
1254             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1255     }
1256
1257     for (i = 0; i < 6 && s->flags & 4; i++) {
1258         const uint16_t color[4] = { 128 * m, 0, 0, max };
1259         int x = positions[P][i][X];
1260         int y = positions[P][i][Y];
1261
1262         if (x > max / 2)
1263             x += 8;
1264         else
1265             x -= 14;
1266         if (y > max / 2)
1267             y += 8;
1268         else
1269             y -= 14;
1270
1271         x = av_clip(x, 0, out->width - 9);
1272         y = av_clip(y, 0, out->height - 9);
1273         draw_htext16(out, x, y, o, 1. - o, positions_name[i], color);
1274     }
1275 }
1276
1277 static void green_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1278 {
1279     const float o = s->opacity;
1280     int i;
1281
1282     for (i = 0; i < 12; i++) {
1283         int x = positions[P][i][X];
1284         int y = positions[P][i][Y];
1285
1286         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1287         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1288         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1289         if (out->data[3])
1290             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1291     }
1292
1293     if (s->flags & 1) {
1294         int x = positions[P][12][X];
1295         int y = positions[P][12][Y];
1296
1297         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1298         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1299         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1300         if (out->data[3])
1301             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1302     }
1303
1304     if (s->flags & 2) {
1305         int x = positions[P][13][X];
1306         int y = positions[P][13][Y];
1307
1308         draw_dots(out->data[0] + y * out->linesize[0] + x, out->linesize[0], 128, o);
1309         draw_dots(out->data[1] + y * out->linesize[1] + x, out->linesize[1], 0, o);
1310         draw_dots(out->data[2] + y * out->linesize[2] + x, out->linesize[2], 0, o);
1311         if (out->data[3])
1312             draw_dots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], 255, o);
1313     }
1314
1315     for (i = 0; i < 6 && s->flags & 4; i++) {
1316         const uint8_t color[4] = { 128, 0, 0, 255 };
1317         int x = positions[P][i][X];
1318         int y = positions[P][i][Y];
1319
1320         if (x > 128)
1321             x += 8;
1322         else
1323             x -= 14;
1324         if (y > 128)
1325             y += 8;
1326         else
1327             y -= 14;
1328
1329         x = av_clip(x, 0, out->width - 9);
1330         y = av_clip(y, 0, out->height - 9);
1331         draw_htext(out, x, y, o, 1. - o, positions_name[i], color);
1332     }
1333 }
1334
1335 static void invert_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1336 {
1337     const int max = s->size - 1;
1338     const float o = s->opacity;
1339     int i;
1340
1341     for (i = 0; i < 12; i++) {
1342         int x = positions[P][i][X];
1343         int y = positions[P][i][Y];
1344
1345         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1346         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1347         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1348         if (out->data[3])
1349             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1350     }
1351
1352     if (s->flags & 1) {
1353         int x = positions[P][12][X];
1354         int y = positions[P][12][Y];
1355
1356         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1357         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1358         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1359         if (out->data[3])
1360             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1361     }
1362
1363     if (s->flags & 2) {
1364         int x = positions[P][13][X];
1365         int y = positions[P][13][Y];
1366
1367         draw_idots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, max, o);
1368         draw_idots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, max, o);
1369         draw_idots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, max, o);
1370         if (out->data[3])
1371             draw_dots16((uint16_t *)(out->data[3] + y * out->linesize[3] + x * 2), out->linesize[3] / 2, max, o);
1372     }
1373
1374     for (i = 0; i < 6 && s->flags & 4; i++) {
1375         uint16_t color[4] = { max, max, max, max };
1376         int x = positions[P][i][X];
1377         int y = positions[P][i][Y];
1378
1379         if (x > max / 2)
1380             x += 8;
1381         else
1382             x -= 14;
1383         if (y > max / 2)
1384             y += 8;
1385         else
1386             y -= 14;
1387
1388         x = av_clip(x, 0, out->width - 9);
1389         y = av_clip(y, 0, out->height - 9);
1390         draw_ihtext16(out, x, y, o, 1. - o, positions_name[i], color);
1391     }
1392 }
1393
1394 static void invert_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
1395 {
1396     const float o = s->opacity;
1397     int i;
1398
1399     for (i = 0; i < 12; i++) {
1400         int x = positions[P][i][X];
1401         int y = positions[P][i][Y];
1402
1403         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1404         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1405         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1406         if (out->data[3])
1407             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1408     }
1409
1410     if (s->flags & 1) {
1411         int x = positions[P][12][X];
1412         int y = positions[P][12][Y];
1413
1414         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1415         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1416         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1417         if (out->data[3])
1418             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1419     }
1420
1421     if (s->flags & 2) {
1422         int x = positions[P][13][X];
1423         int y = positions[P][13][Y];
1424
1425         draw_idots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], o);
1426         draw_idots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], o);
1427         draw_idots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], o);
1428         if (out->data[3])
1429             draw_idots(out->data[3] + y * out->linesize[3] + x, out->linesize[3], o);
1430     }
1431
1432     for (i = 0; i < 6 && s->flags & 4; i++) {
1433         uint8_t color[4] = { 255, 255, 255, 255 };
1434         int x = positions[P][i][X];
1435         int y = positions[P][i][Y];
1436
1437         if (x > 128)
1438             x += 8;
1439         else
1440             x -= 14;
1441         if (y > 128)
1442             y += 8;
1443         else
1444             y -= 14;
1445
1446         x = av_clip(x, 0, out->width - 9);
1447         y = av_clip(y, 0, out->height - 9);
1448         draw_ihtext(out, x, y, o, 1. - o, positions_name[i], color);
1449     }
1450 }
1451
1452 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1453 {
1454     AVFilterContext *ctx  = inlink->dst;
1455     VectorscopeContext *s = ctx->priv;
1456     AVFilterLink *outlink = ctx->outputs[0];
1457     AVFrame *out;
1458     int plane;
1459
1460     if (s->colorspace) {
1461         s->cs = (s->depth - 8) * 2 + s->colorspace - 1;
1462     } else {
1463         switch (in->colorspace) {
1464         case AVCOL_SPC_SMPTE170M:
1465         case AVCOL_SPC_BT470BG:
1466             s->cs = (s->depth - 8) * 2 + 0;
1467             break;
1468         case AVCOL_SPC_BT709:
1469         default:
1470             s->cs = (s->depth - 8) * 2 + 1;
1471         }
1472     }
1473
1474     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1475     if (!out) {
1476         av_frame_free(&in);
1477         return AVERROR(ENOMEM);
1478     }
1479     av_frame_copy_props(out, in);
1480
1481     s->vectorscope(s, in, out, s->pd);
1482     s->graticulef(s, out, s->x, s->y, s->pd, s->cs);
1483
1484     for (plane = 0; plane < 4; plane++) {
1485         if (out->data[plane]) {
1486             out->data[plane]    += (s->size - 1) * out->linesize[plane];
1487             out->linesize[plane] = -out->linesize[plane];
1488         }
1489     }
1490
1491     av_frame_free(&in);
1492     return ff_filter_frame(outlink, out);
1493 }
1494
1495 static int config_input(AVFilterLink *inlink)
1496 {
1497     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
1498     AVFilterContext *ctx = inlink->dst;
1499     VectorscopeContext *s = ctx->priv;
1500
1501     s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB);
1502     s->size = 1 << desc->comp[0].depth;
1503     s->mult = s->size / 256;
1504     s->depth = desc->comp[0].depth;
1505     s->tmin = s->lthreshold * (s->size - 1);
1506     s->tmax = s->hthreshold * (s->size - 1);
1507
1508     if (s->tmin > s->tmax) {
1509         av_log(ctx, AV_LOG_ERROR, "low threshold should be less than high threshold\n");
1510         return AVERROR(EINVAL);
1511     }
1512
1513     if (s->mode == TINT && s->is_yuv) {
1514         s->pd = 0;
1515     } else {
1516         if ((s->x == 1 && s->y == 2) || (s->x == 2 && s->y == 1))
1517             s->pd = 0;
1518         else if ((s->x == 0 && s->y == 2) || (s->x == 2 && s->y == 0))
1519             s->pd = 1;
1520         else if ((s->x == 0 && s->y == 1) || (s->x == 1 && s->y == 0))
1521             s->pd = 2;
1522     }
1523
1524     if (s->size == 256)
1525         s->vectorscope = vectorscope8;
1526     else
1527         s->vectorscope = vectorscope16;
1528
1529     s->graticulef = none_graticule;
1530
1531     if (s->is_yuv && s->size == 256) {
1532         if (s->graticule == GRAT_GREEN)
1533             s->graticulef = green_graticule;
1534         else if (s->graticule == GRAT_COLOR)
1535             s->graticulef = color_graticule;
1536         else if (s->graticule == GRAT_INVERT)
1537             s->graticulef = invert_graticule;
1538     } else if (s->is_yuv) {
1539         if (s->graticule == GRAT_GREEN)
1540             s->graticulef = green_graticule16;
1541         else if (s->graticule == GRAT_COLOR)
1542             s->graticulef = color_graticule16;
1543         else if (s->graticule == GRAT_INVERT)
1544             s->graticulef = invert_graticule16;
1545     }
1546
1547     s->bg_color[3] = s->bgopacity * (s->size - 1);
1548
1549     s->tint[0] = .5f * (s->ftint[0] + 1.f) * (s->size - 1);
1550     s->tint[1] = .5f * (s->ftint[1] + 1.f) * (s->size - 1);
1551
1552     switch (inlink->format) {
1553     case AV_PIX_FMT_GBRP12:
1554     case AV_PIX_FMT_GBRP10:
1555     case AV_PIX_FMT_GBRP9:
1556     case AV_PIX_FMT_GBRAP:
1557     case AV_PIX_FMT_GBRP:
1558         s->bg_color[0] = 0;
1559         s->bg_color[1] = 0;
1560         s->bg_color[2] = 0;
1561         break;
1562     default:
1563         s->bg_color[0] = 0;
1564         s->bg_color[1] = s->size / 2;
1565         s->bg_color[2] = s->size / 2;
1566     }
1567
1568     s->hsub = desc->log2_chroma_w;
1569     s->vsub = desc->log2_chroma_h;
1570     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
1571     s->planeheight[0] = s->planeheight[3] = inlink->h;
1572     s->planewidth[1]  = s->planewidth[2]  = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
1573     s->planewidth[0]  = s->planewidth[3]  = inlink->w;
1574
1575     return 0;
1576 }
1577
1578 static av_cold void uninit(AVFilterContext *ctx)
1579 {
1580     VectorscopeContext *s = ctx->priv;
1581
1582     av_freep(&s->peak);
1583     av_freep(&s->peak_memory);
1584 }
1585
1586 static const AVFilterPad inputs[] = {
1587     {
1588         .name         = "default",
1589         .type         = AVMEDIA_TYPE_VIDEO,
1590         .filter_frame = filter_frame,
1591         .config_props = config_input,
1592     },
1593     { NULL }
1594 };
1595
1596 static const AVFilterPad outputs[] = {
1597     {
1598         .name         = "default",
1599         .type         = AVMEDIA_TYPE_VIDEO,
1600         .config_props = config_output,
1601     },
1602     { NULL }
1603 };
1604
1605 AVFilter ff_vf_vectorscope = {
1606     .name          = "vectorscope",
1607     .description   = NULL_IF_CONFIG_SMALL("Video vectorscope."),
1608     .priv_size     = sizeof(VectorscopeContext),
1609     .priv_class    = &vectorscope_class,
1610     .query_formats = query_formats,
1611     .uninit        = uninit,
1612     .inputs        = inputs,
1613     .outputs       = outputs,
1614 };