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