]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_vectorscope.c
Merge commit '883ad2c59ceea1ced5495b5ccc83695ed4bbb94b'
[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 "avfilter.h"
27 #include "formats.h"
28 #include "internal.h"
29 #include "video.h"
30
31 enum VectorscopeMode {
32     GRAY,
33     COLOR,
34     COLOR2,
35     COLOR3,
36     COLOR4,
37     MODE_NB
38 };
39
40 typedef struct VectorscopeContext {
41     const AVClass *class;
42     int mode;
43     int intensity;
44     float fintensity;
45     const uint8_t *bg_color;
46     int planewidth[4];
47     int planeheight[4];
48     int hsub, vsub;
49     int x, y, pd;
50     int is_yuv;
51     int size;
52     int mult;
53     int envelope;
54     uint8_t peak[1024][1024];
55
56     void (*vectorscope)(struct VectorscopeContext *s,
57                         AVFrame *in, AVFrame *out, int pd);
58 } VectorscopeContext;
59
60 #define OFFSET(x) offsetof(VectorscopeContext, x)
61 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
62
63 static const AVOption vectorscope_options[] = {
64     { "mode", "set vectorscope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, MODE_NB-1, FLAGS, "mode"},
65     { "m",    "set vectorscope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, MODE_NB-1, FLAGS, "mode"},
66     {   "gray",   0, 0, AV_OPT_TYPE_CONST, {.i64=GRAY},   0, 0, FLAGS, "mode" },
67     {   "color",  0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR},  0, 0, FLAGS, "mode" },
68     {   "color2", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR2}, 0, 0, FLAGS, "mode" },
69     {   "color3", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR3}, 0, 0, FLAGS, "mode" },
70     {   "color4", 0, 0, AV_OPT_TYPE_CONST, {.i64=COLOR4}, 0, 0, FLAGS, "mode" },
71     { "x", "set color component on X axis", OFFSET(x), AV_OPT_TYPE_INT, {.i64=1}, 0, 2, FLAGS},
72     { "y", "set color component on Y axis", OFFSET(y), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, FLAGS},
73     { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.004}, 0, 1, FLAGS},
74     { "i",         "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.004}, 0, 1, FLAGS},
75     { "envelope",  "set envelope", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope"},
76     { "e",         "set envelope", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope"},
77     {   "none",         0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
78     {   "instant",      0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
79     {   "peak",         0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
80     {   "peak+instant", 0, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
81     { NULL }
82 };
83
84 AVFILTER_DEFINE_CLASS(vectorscope);
85
86 static const enum AVPixelFormat out_yuv8_pix_fmts[] = {
87     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P,
88     AV_PIX_FMT_NONE
89 };
90
91 static const enum AVPixelFormat out_yuv9_pix_fmts[] = {
92     AV_PIX_FMT_YUV444P9,
93     AV_PIX_FMT_NONE
94 };
95
96 static const enum AVPixelFormat out_yuv10_pix_fmts[] = {
97     AV_PIX_FMT_YUV444P10,
98     AV_PIX_FMT_NONE
99 };
100
101 static const enum AVPixelFormat out_rgb8_pix_fmts[] = {
102     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
103     AV_PIX_FMT_NONE
104 };
105
106 static const enum AVPixelFormat out_rgb9_pix_fmts[] = {
107     AV_PIX_FMT_GBRP9,
108     AV_PIX_FMT_NONE
109 };
110
111 static const enum AVPixelFormat out_rgb10_pix_fmts[] = {
112     AV_PIX_FMT_GBRP10,
113     AV_PIX_FMT_NONE
114 };
115
116 static const enum AVPixelFormat in1_pix_fmts[] = {
117     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
118     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
119     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
120     AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
121     AV_PIX_FMT_NONE
122 };
123
124 static const enum AVPixelFormat in2_pix_fmts[] = {
125     AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
126     AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
127     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
128     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUVJ411P,
129     AV_PIX_FMT_YUV440P,  AV_PIX_FMT_YUV410P,
130     AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP,
131     AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
132     AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
133     AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
134     AV_PIX_FMT_NONE
135 };
136
137 static int query_formats(AVFilterContext *ctx)
138 {
139     VectorscopeContext *s = ctx->priv;
140     const enum AVPixelFormat *out_pix_fmts;
141     const AVPixFmtDescriptor *desc;
142     AVFilterFormats *avff;
143     int depth, rgb, i, ret;
144
145     if (!ctx->inputs[0]->in_formats ||
146         !ctx->inputs[0]->in_formats->nb_formats) {
147         return AVERROR(EAGAIN);
148     }
149
150     if (!ctx->inputs[0]->out_formats) {
151         const enum AVPixelFormat *in_pix_fmts;
152
153         if ((s->x == 1 && s->y == 2) || (s->x == 2 && s->y == 1))
154             in_pix_fmts = in2_pix_fmts;
155         else
156             in_pix_fmts = in1_pix_fmts;
157         if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->out_formats)) < 0)
158             return ret;
159     }
160
161     avff = ctx->inputs[0]->in_formats;
162     desc = av_pix_fmt_desc_get(avff->formats[0]);
163     rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
164     depth = desc->comp[0].depth;
165     for (i = 1; i < avff->nb_formats; i++) {
166         desc = av_pix_fmt_desc_get(avff->formats[i]);
167         if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
168             depth != desc->comp[0].depth)
169             return AVERROR(EAGAIN);
170     }
171
172     if (rgb && depth == 8)
173         out_pix_fmts = out_rgb8_pix_fmts;
174     else if (rgb && depth == 9)
175         out_pix_fmts = out_rgb9_pix_fmts;
176     else if (rgb && depth == 10)
177         out_pix_fmts = out_rgb10_pix_fmts;
178     else if (depth == 9)
179         out_pix_fmts = out_yuv9_pix_fmts;
180     else if (depth == 10)
181         out_pix_fmts = out_yuv10_pix_fmts;
182     else
183         out_pix_fmts = out_yuv8_pix_fmts;
184     if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats)) < 0)
185         return ret;
186
187     return 0;
188 }
189
190 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 0 };
191 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 0 };
192
193 static int config_output(AVFilterLink *outlink)
194 {
195     VectorscopeContext *s = outlink->src->priv;
196
197     s->intensity = s->fintensity * (s->size - 1);
198     outlink->h = outlink->w = s->size;
199     outlink->sample_aspect_ratio = (AVRational){1,1};
200     return 0;
201 }
202
203 static void envelope_instant16(VectorscopeContext *s, AVFrame *out)
204 {
205     const int dlinesize = out->linesize[0] / 2;
206     uint16_t *dpd = s->mode == COLOR || !s->is_yuv ? (uint16_t *)out->data[s->pd] : (uint16_t *)out->data[0];
207     const int max = s->size - 1;
208     int i, j;
209
210     for (i = 0; i < out->height; i++) {
211         for (j = 0; j < out->width; j++) {
212             const int pos = i * dlinesize + j;
213             const int poa = (i - 1) * dlinesize + j;
214             const int pob = (i + 1) * dlinesize + j;
215
216             if (dpd[pos] && (((!j || !dpd[pos - 1]) || ((j == (out->width - 1)) || !dpd[pos + 1]))
217                          || ((!i || !dpd[poa]) || ((i == (out->height - 1)) || !dpd[pob])))) {
218                 dpd[pos] = max;
219             }
220         }
221     }
222 }
223
224 static void envelope_peak16(VectorscopeContext *s, AVFrame *out)
225 {
226     const int dlinesize = out->linesize[0] / 2;
227     uint16_t *dpd = s->mode == COLOR || !s->is_yuv ? (uint16_t *)out->data[s->pd] : (uint16_t *)out->data[0];
228     const int max = s->size - 1;
229     int i, j;
230
231     for (i = 0; i < out->height; i++) {
232         for (j = 0; j < out->width; j++) {
233             const int pos = i * dlinesize + j;
234
235             if (dpd[pos])
236                 s->peak[i][j] = 1;
237         }
238     }
239
240     if (s->envelope == 3)
241         envelope_instant16(s, out);
242
243     for (i = 0; i < out->height; i++) {
244         for (j = 0; j < out->width; j++) {
245             const int pos = i * dlinesize + j;
246
247             if (s->peak[i][j] && (((!j || !s->peak[i][j-1]) || ((j == (out->width - 1)) || !s->peak[i][j + 1]))
248                               || ((!i || !s->peak[i-1][j]) || ((i == (out->height - 1)) || !s->peak[i + 1][j])))) {
249                 dpd[pos] = max;
250             }
251         }
252     }
253 }
254
255 static void envelope_instant(VectorscopeContext *s, AVFrame *out)
256 {
257     const int dlinesize = out->linesize[0];
258     uint8_t *dpd = s->mode == COLOR || !s->is_yuv ? out->data[s->pd] : out->data[0];
259     int i, j;
260
261     for (i = 0; i < out->height; i++) {
262         for (j = 0; j < out->width; j++) {
263             const int pos = i * dlinesize + j;
264             const int poa = (i - 1) * dlinesize + j;
265             const int pob = (i + 1) * dlinesize + j;
266
267             if (dpd[pos] && (((!j || !dpd[pos - 1]) || ((j == (out->width - 1)) || !dpd[pos + 1]))
268                          || ((!i || !dpd[poa]) || ((i == (out->height - 1)) || !dpd[pob])))) {
269                 dpd[pos] = 255;
270             }
271         }
272     }
273 }
274
275 static void envelope_peak(VectorscopeContext *s, AVFrame *out)
276 {
277     const int dlinesize = out->linesize[0];
278     uint8_t *dpd = s->mode == COLOR || !s->is_yuv ? out->data[s->pd] : out->data[0];
279     int i, j;
280
281     for (i = 0; i < out->height; i++) {
282         for (j = 0; j < out->width; j++) {
283             const int pos = i * dlinesize + j;
284
285             if (dpd[pos])
286                 s->peak[i][j] = 1;
287         }
288     }
289
290     if (s->envelope == 3)
291         envelope_instant(s, out);
292
293     for (i = 0; i < out->height; i++) {
294         for (j = 0; j < out->width; j++) {
295             const int pos = i * dlinesize + j;
296
297             if (s->peak[i][j] && (((!j || !s->peak[i][j-1]) || ((j == (out->width - 1)) || !s->peak[i][j + 1]))
298                               || ((!i || !s->peak[i-1][j]) || ((i == (out->height - 1)) || !s->peak[i + 1][j])))) {
299                 dpd[pos] = 255;
300             }
301         }
302     }
303 }
304
305 static void envelope16(VectorscopeContext *s, AVFrame *out)
306 {
307     if (!s->envelope) {
308         return;
309     } else if (s->envelope == 1) {
310         envelope_instant16(s, out);
311     } else {
312         envelope_peak16(s, out);
313     }
314 }
315
316 static void envelope(VectorscopeContext *s, AVFrame *out)
317 {
318     if (!s->envelope) {
319         return;
320     } else if (s->envelope == 1) {
321         envelope_instant(s, out);
322     } else {
323         envelope_peak(s, out);
324     }
325 }
326
327 static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int pd)
328 {
329     const uint16_t * const *src = (const uint16_t * const *)in->data;
330     const int slinesizex = in->linesize[s->x] / 2;
331     const int slinesizey = in->linesize[s->y] / 2;
332     const int slinesized = in->linesize[pd] / 2;
333     const int dlinesize = out->linesize[0] / 2;
334     const int intensity = s->intensity;
335     const int px = s->x, py = s->y;
336     const int h = s->planeheight[py];
337     const int w = s->planewidth[px];
338     const uint16_t *spx = src[px];
339     const uint16_t *spy = src[py];
340     const uint16_t *spd = src[pd];
341     const int hsub = s->hsub;
342     const int vsub = s->vsub;
343     uint16_t **dst = (uint16_t **)out->data;
344     uint16_t *dpx = dst[px];
345     uint16_t *dpy = dst[py];
346     uint16_t *dpd = dst[pd];
347     const int max = s->size - 1;
348     const int mid = s->size / 2;
349     int i, j, k;
350
351     for (k = 0; k < 4 && dst[k]; k++) {
352         const int mult = s->mult;
353
354         for (i = 0; i < out->height ; i++)
355             for (j = 0; j < out->width; j++)
356                 AV_WN16(out->data[k] + i * out->linesize[k] + j * 2,
357                         s->mode == COLOR && k == s->pd ? 0 : s->bg_color[k] * mult);
358     }
359
360     switch (s->mode) {
361     case COLOR:
362     case GRAY:
363         if (s->is_yuv) {
364             for (i = 0; i < h; i++) {
365                 const int iwx = i * slinesizex;
366                 const int iwy = i * slinesizey;
367                 for (j = 0; j < w; j++) {
368                     const int x = FFMIN(spx[iwx + j], max);
369                     const int y = FFMIN(spy[iwy + j], max);
370                     const int pos = y * dlinesize + x;
371
372                     dpd[pos] = FFMIN(dpd[pos] + intensity, max);
373                     if (dst[3])
374                         dst[3][pos] = max;
375                 }
376             }
377         } else {
378             for (i = 0; i < h; i++) {
379                 const int iwx = i * slinesizex;
380                 const int iwy = i * slinesizey;
381                 for (j = 0; j < w; j++) {
382                     const int x = FFMIN(spx[iwx + j], max);
383                     const int y = FFMIN(spy[iwy + j], max);
384                     const int pos = y * dlinesize + x;
385
386                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, max);
387                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, max);
388                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, max);
389                     if (dst[3])
390                         dst[3][pos] = max;
391                 }
392             }
393         }
394         break;
395     case COLOR2:
396         if (s->is_yuv) {
397             for (i = 0; i < h; i++) {
398                 const int iw1 = i * slinesizex;
399                 const int iw2 = i * slinesizey;
400                 for (j = 0; j < w; j++) {
401                     const int x = FFMIN(spx[iw1 + j], max);
402                     const int y = FFMIN(spy[iw2 + j], max);
403                     const int pos = y * dlinesize + x;
404
405                     if (!dpd[pos])
406                         dpd[pos] = FFABS(mid - x) + FFABS(mid - y);
407                     dpx[pos] = x;
408                     dpy[pos] = y;
409                     if (dst[3])
410                         dst[3][pos] = max;
411                 }
412             }
413         } else {
414             for (i = 0; i < h; i++) {
415                 const int iw1 = i * slinesizex;
416                 const int iw2 = i * slinesizey;
417                 for (j = 0; j < w; j++) {
418                     const int x = FFMIN(spx[iw1 + j], max);
419                     const int y = FFMIN(spy[iw2 + j], max);
420                     const int pos = y * dlinesize + x;
421
422                     if (!dpd[pos])
423                         dpd[pos] = FFMIN(x + y, max);
424                     dpx[pos] = x;
425                     dpy[pos] = y;
426                     if (dst[3])
427                         dst[3][pos] = max;
428                 }
429             }
430         }
431         break;
432     case COLOR3:
433         for (i = 0; i < h; i++) {
434             const int iw1 = i * slinesizex;
435             const int iw2 = i * slinesizey;
436             for (j = 0; j < w; j++) {
437                 const int x = FFMIN(spx[iw1 + j], max);
438                 const int y = FFMIN(spy[iw2 + j], max);
439                 const int pos = y * dlinesize + x;
440
441                 dpd[pos] = FFMIN(max, dpd[pos] + intensity);
442                 dpx[pos] = x;
443                 dpy[pos] = y;
444                 if (dst[3])
445                     dst[3][pos] = max;
446             }
447         }
448         break;
449     case COLOR4:
450         for (i = 0; i < in->height; i++) {
451             const int iwx = (i >> vsub) * slinesizex;
452             const int iwy = (i >> vsub) * slinesizey;
453             const int iwd = i * slinesized;
454             for (j = 0; j < in->width; j++) {
455                 const int x = FFMIN(spx[iwx + (j >> hsub)], max);
456                 const int y = FFMIN(spy[iwy + (j >> hsub)], max);
457                 const int pos = y * dlinesize + x;
458
459                 dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]);
460                 dpx[pos] = x;
461                 dpy[pos] = y;
462                 if (dst[3])
463                     dst[3][pos] = max;
464             }
465         }
466         break;
467     default:
468         av_assert0(0);
469     }
470
471     envelope16(s, out);
472
473     if (s->mode == COLOR) {
474         for (i = 0; i < out->height; i++) {
475             for (j = 0; j < out->width; j++) {
476                 if (!dpd[i * dlinesize + j]) {
477                     dpx[i * dlinesize + j] = j;
478                     dpy[i * dlinesize + j] = i;
479                     dpd[i * dlinesize + j] = mid;
480                 }
481             }
482         }
483     }
484 }
485
486 static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int pd)
487 {
488     const uint8_t * const *src = (const uint8_t * const *)in->data;
489     const int slinesizex = in->linesize[s->x];
490     const int slinesizey = in->linesize[s->y];
491     const int slinesized = in->linesize[pd];
492     const int dlinesize = out->linesize[0];
493     const int intensity = s->intensity;
494     const int px = s->x, py = s->y;
495     const int h = s->planeheight[py];
496     const int w = s->planewidth[px];
497     const uint8_t *spx = src[px];
498     const uint8_t *spy = src[py];
499     const uint8_t *spd = src[pd];
500     const int hsub = s->hsub;
501     const int vsub = s->vsub;
502     uint8_t **dst = out->data;
503     uint8_t *dpx = dst[px];
504     uint8_t *dpy = dst[py];
505     uint8_t *dpd = dst[pd];
506     int i, j, k;
507
508     for (k = 0; k < 4 && dst[k]; k++)
509         for (i = 0; i < out->height ; i++)
510             memset(dst[k] + i * out->linesize[k],
511                    s->mode == COLOR && k == s->pd ? 0 : s->bg_color[k], out->width);
512
513     switch (s->mode) {
514     case COLOR:
515     case GRAY:
516         if (s->is_yuv) {
517             for (i = 0; i < h; i++) {
518                 const int iwx = i * slinesizex;
519                 const int iwy = i * slinesizey;
520                 for (j = 0; j < w; j++) {
521                     const int x = spx[iwx + j];
522                     const int y = spy[iwy + j];
523                     const int pos = y * dlinesize + x;
524
525                     dpd[pos] = FFMIN(dpd[pos] + intensity, 255);
526                     if (dst[3])
527                         dst[3][pos] = 255;
528                 }
529             }
530         } else {
531             for (i = 0; i < h; i++) {
532                 const int iwx = i * slinesizex;
533                 const int iwy = i * slinesizey;
534                 for (j = 0; j < w; j++) {
535                     const int x = spx[iwx + j];
536                     const int y = spy[iwy + j];
537                     const int pos = y * dlinesize + x;
538
539                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, 255);
540                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, 255);
541                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, 255);
542                     if (dst[3])
543                         dst[3][pos] = 255;
544                 }
545             }
546         }
547         break;
548     case COLOR2:
549         if (s->is_yuv) {
550             for (i = 0; i < h; i++) {
551                 const int iw1 = i * slinesizex;
552                 const int iw2 = i * slinesizey;
553                 for (j = 0; j < w; j++) {
554                     const int x = spx[iw1 + j];
555                     const int y = spy[iw2 + j];
556                     const int pos = y * dlinesize + x;
557
558                     if (!dpd[pos])
559                         dpd[pos] = FFABS(128 - x) + FFABS(128 - y);
560                     dpx[pos] = x;
561                     dpy[pos] = y;
562                     if (dst[3])
563                         dst[3][pos] = 255;
564                 }
565             }
566         } else {
567             for (i = 0; i < h; i++) {
568                 const int iw1 = i * slinesizex;
569                 const int iw2 = i * slinesizey;
570                 for (j = 0; j < w; j++) {
571                     const int x = spx[iw1 + j];
572                     const int y = spy[iw2 + j];
573                     const int pos = y * dlinesize + x;
574
575                     if (!dpd[pos])
576                         dpd[pos] = FFMIN(x + y, 255);
577                     dpx[pos] = x;
578                     dpy[pos] = y;
579                     if (dst[3])
580                         dst[3][pos] = 255;
581                 }
582             }
583         }
584         break;
585     case COLOR3:
586         for (i = 0; i < h; i++) {
587             const int iw1 = i * slinesizex;
588             const int iw2 = i * slinesizey;
589             for (j = 0; j < w; j++) {
590                 const int x = spx[iw1 + j];
591                 const int y = spy[iw2 + j];
592                 const int pos = y * dlinesize + x;
593
594                 dpd[pos] = FFMIN(255, dpd[pos] + intensity);
595                 dpx[pos] = x;
596                 dpy[pos] = y;
597                 if (dst[3])
598                     dst[3][pos] = 255;
599             }
600         }
601         break;
602     case COLOR4:
603         for (i = 0; i < in->height; i++) {
604             const int iwx = (i >> vsub) * slinesizex;
605             const int iwy = (i >> vsub) * slinesizey;
606             const int iwd = i * slinesized;
607             for (j = 0; j < in->width; j++) {
608                 const int x = spx[iwx + (j >> hsub)];
609                 const int y = spy[iwy + (j >> hsub)];
610                 const int pos = y * dlinesize + x;
611
612                 dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]);
613                 dpx[pos] = x;
614                 dpy[pos] = y;
615                 if (dst[3])
616                     dst[3][pos] = 255;
617             }
618         }
619         break;
620     default:
621         av_assert0(0);
622     }
623
624     envelope(s, out);
625
626     if (s->mode == COLOR) {
627         for (i = 0; i < out->height; i++) {
628             for (j = 0; j < out->width; j++) {
629                 if (!dpd[i * out->linesize[pd] + j]) {
630                     dpx[i * out->linesize[px] + j] = j;
631                     dpy[i * out->linesize[py] + j] = i;
632                     dpd[i * out->linesize[pd] + j] = 128;
633                 }
634             }
635         }
636     }
637 }
638
639 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
640 {
641     AVFilterContext *ctx  = inlink->dst;
642     VectorscopeContext *s = ctx->priv;
643     AVFilterLink *outlink = ctx->outputs[0];
644     AVFrame *out;
645
646     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
647     if (!out) {
648         av_frame_free(&in);
649         return AVERROR(ENOMEM);
650     }
651     out->pts = in->pts;
652
653     s->vectorscope(s, in, out, s->pd);
654
655     av_frame_free(&in);
656     return ff_filter_frame(outlink, out);
657 }
658
659 static int config_input(AVFilterLink *inlink)
660 {
661     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
662     VectorscopeContext *s = inlink->dst->priv;
663
664     s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB);
665     s->size = 1 << desc->comp[0].depth;
666     s->mult = s->size / 256;
667
668     if (s->mode == GRAY && s->is_yuv)
669         s->pd = 0;
670     else {
671         if ((s->x == 1 && s->y == 2) || (s->x == 2 && s->y == 1))
672             s->pd = 0;
673         else if ((s->x == 0 && s->y == 2) || (s->x == 2 && s->y == 0))
674             s->pd = 1;
675         else if ((s->x == 0 && s->y == 1) || (s->x == 1 && s->y == 0))
676             s->pd = 2;
677     }
678
679     if (s->size == 256)
680         s->vectorscope = vectorscope8;
681     else
682         s->vectorscope = vectorscope16;
683
684     switch (inlink->format) {
685     case AV_PIX_FMT_GBRP10:
686     case AV_PIX_FMT_GBRP9:
687     case AV_PIX_FMT_GBRAP:
688     case AV_PIX_FMT_GBRP:
689         s->bg_color = black_gbrp_color;
690         break;
691     default:
692         s->bg_color = black_yuva_color;
693     }
694
695     s->hsub = desc->log2_chroma_w;
696     s->vsub = desc->log2_chroma_h;
697     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
698     s->planeheight[0] = s->planeheight[3] = inlink->h;
699     s->planewidth[1]  = s->planewidth[2]  = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
700     s->planewidth[0]  = s->planewidth[3]  = inlink->w;
701
702     return 0;
703 }
704
705 static const AVFilterPad inputs[] = {
706     {
707         .name         = "default",
708         .type         = AVMEDIA_TYPE_VIDEO,
709         .filter_frame = filter_frame,
710         .config_props = config_input,
711     },
712     { NULL }
713 };
714
715 static const AVFilterPad outputs[] = {
716     {
717         .name         = "default",
718         .type         = AVMEDIA_TYPE_VIDEO,
719         .config_props = config_output,
720     },
721     { NULL }
722 };
723
724 AVFilter ff_vf_vectorscope = {
725     .name          = "vectorscope",
726     .description   = NULL_IF_CONFIG_SMALL("Video vectorscope."),
727     .priv_size     = sizeof(VectorscopeContext),
728     .priv_class    = &vectorscope_class,
729     .query_formats = query_formats,
730     .inputs        = inputs,
731     .outputs       = outputs,
732 };