FFmpeg
vf_datascope.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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/intreadwrite.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/parseutils.h"
24 #include "libavutil/pixdesc.h"
26 #include "avfilter.h"
27 #include "drawutils.h"
28 #include "formats.h"
29 #include "internal.h"
30 #include "video.h"
31 
32 typedef struct DatascopeContext {
33  const AVClass *class;
34  int ow, oh;
35  int x, y;
36  int mode;
37  int dformat;
38  int axis;
40  float opacity;
41 
42  int nb_planes;
43  int nb_comps;
44  int chars;
50 
51  void (*pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value);
53  int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
55 
56 #define OFFSET(x) offsetof(DatascopeContext, x)
57 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
58 #define FLAGSR AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
59 
60 static const AVOption datascope_options[] = {
61  { "size", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
62  { "s", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
63  { "x", "set x offset", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGSR },
64  { "y", "set y offset", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGSR },
65  { "mode", "set scope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGSR, .unit = "mode" },
66  { "mono", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGSR, .unit = "mode" },
67  { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGSR, .unit = "mode" },
68  { "color2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGSR, .unit = "mode" },
69  { "axis", "draw column/row numbers", OFFSET(axis), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGSR },
70  { "opacity", "set background opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGSR },
71  { "format", "set display number format", OFFSET(dformat), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGSR, .unit = "format" },
72  { "hex", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGSR, .unit = "format" },
73  { "dec", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGSR, .unit = "format" },
74  { "components", "set components to display", OFFSET(components), AV_OPT_TYPE_INT, {.i64=15}, 1, 15, FLAGSR },
75  { NULL }
76 };
77 
78 AVFILTER_DEFINE_CLASS(datascope);
79 
81 {
83 }
84 
86  int x0, int y0, const uint8_t *text, int vertical)
87 {
88  int x = x0;
89 
90  for (; *text; text++) {
91  if (*text == '\n') {
92  x = x0;
93  y0 += 8;
94  continue;
95  }
98  avpriv_cga_font + *text * 8, 1, 8, 8, 0, 0, x, y0);
99  if (vertical) {
100  x = x0;
101  y0 += 8;
102  } else {
103  x += 8;
104  }
105  }
106 }
107 
108 static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
109 {
110  int p, i;
111 
112  color->rgba[3] = 255;
113  for (p = 0; p < draw->nb_planes; p++) {
114  if (draw->nb_planes == 1) {
115  for (i = 0; i < 4; i++) {
116  value[i] = in->data[0][y * in->linesize[0] + x * draw->pixelstep[0] + i];
117  color->comp[0].u8[i] = value[i];
118  }
119  } else {
120  value[p] = in->data[p][(y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p])];
121  color->comp[p].u8[0] = value[p];
122  }
123  }
124 }
125 
126 static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
127 {
128  int p, i;
129 
130  color->rgba[3] = 255;
131  for (p = 0; p < draw->nb_planes; p++) {
132  if (draw->nb_planes == 1) {
133  for (i = 0; i < 4; i++) {
134  value[i] = AV_RL16(in->data[0] + y * in->linesize[0] + x * draw->pixelstep[0] + i * 2);
135  color->comp[0].u16[i] = value[i];
136  }
137  } else {
138  value[p] = AV_RL16(in->data[p] + (y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p]) * 2);
139  color->comp[p].u16[0] = value[p];
140  }
141  }
142 }
143 
145 {
146  int p;
147 
148  reverse->rgba[3] = 255;
149  for (p = 0; p < draw->nb_planes; p++) {
150  reverse->comp[p].u8[0] = color->comp[p].u8[0] > 127 ? 0 : 255;
151  reverse->comp[p].u8[1] = color->comp[p].u8[1] > 127 ? 0 : 255;
152  reverse->comp[p].u8[2] = color->comp[p].u8[2] > 127 ? 0 : 255;
153  }
154 }
155 
157 {
158  int p;
159 
160  reverse->rgba[3] = 255;
161  for (p = 0; p < draw->nb_planes; p++) {
162  const unsigned max = (1 << draw->desc->comp[p].depth) - 1;
163  const unsigned mid = (max + 1) / 2;
164 
165  reverse->comp[p].u16[0] = color->comp[p].u16[0] > mid ? 0 : max;
166  reverse->comp[p].u16[1] = color->comp[p].u16[1] > mid ? 0 : max;
167  reverse->comp[p].u16[2] = color->comp[p].u16[2] > mid ? 0 : max;
168  }
169 }
170 
171 typedef struct ThreadData {
172  AVFrame *in, *out;
173  int xoff, yoff, PP;
174 } ThreadData;
175 
176 static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
177 {
178  DatascopeContext *s = ctx->priv;
179  AVFilterLink *outlink = ctx->outputs[0];
180  AVFilterLink *inlink = ctx->inputs[0];
181  ThreadData *td = arg;
182  AVFrame *in = td->in;
183  AVFrame *out = td->out;
184  const int PP = td->PP;
185  const int xoff = td->xoff;
186  const int yoff = td->yoff;
187  const int P = FFMAX(s->nb_planes, s->nb_comps);
188  const int C = s->chars;
189  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
190  const int W = (outlink->w - xoff) / (C * 10);
191  const int H = (outlink->h - yoff) / (PP * 12);
192  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
193  const int slice_start = (W * jobnr) / nb_jobs;
194  const int slice_end = (W * (jobnr+1)) / nb_jobs;
195  int x, y, p;
196 
197  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
198  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
199  FFDrawColor color = { { 0 } };
200  FFDrawColor reverse = { { 0 } };
201  int value[4] = { 0 }, pp = 0;
202 
203  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
204  s->reverse_color(&s->draw, &color, &reverse);
205  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
206  xoff + x * C * 10, yoff + y * PP * 12, C * 10, PP * 12);
207 
208  for (p = 0; p < P; p++) {
209  char text[256];
210 
211  if (!(s->components & (1 << p)))
212  continue;
213  snprintf(text, sizeof(text), format[D], value[p]);
214  draw_text(&s->draw, out, &reverse, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
215  pp++;
216  }
217  }
218  }
219 
220  return 0;
221 }
222 
223 static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
224 {
225  DatascopeContext *s = ctx->priv;
226  AVFilterLink *outlink = ctx->outputs[0];
227  AVFilterLink *inlink = ctx->inputs[0];
228  ThreadData *td = arg;
229  AVFrame *in = td->in;
230  AVFrame *out = td->out;
231  const int PP = td->PP;
232  const int xoff = td->xoff;
233  const int yoff = td->yoff;
234  const int P = FFMAX(s->nb_planes, s->nb_comps);
235  const int C = s->chars;
236  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
237  const int W = (outlink->w - xoff) / (C * 10);
238  const int H = (outlink->h - yoff) / (PP * 12);
239  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
240  const int slice_start = (W * jobnr) / nb_jobs;
241  const int slice_end = (W * (jobnr+1)) / nb_jobs;
242  int x, y, p;
243 
244  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
245  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
246  FFDrawColor color = { { 0 } };
247  int value[4] = { 0 }, pp = 0;
248 
249  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
250 
251  for (p = 0; p < P; p++) {
252  char text[256];
253 
254  if (!(s->components & (1 << p)))
255  continue;
256  snprintf(text, sizeof(text), format[D], value[p]);
257  draw_text(&s->draw, out, &color, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
258  pp++;
259  }
260  }
261  }
262 
263  return 0;
264 }
265 
266 static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
267 {
268  DatascopeContext *s = ctx->priv;
269  AVFilterLink *outlink = ctx->outputs[0];
270  AVFilterLink *inlink = ctx->inputs[0];
271  ThreadData *td = arg;
272  AVFrame *in = td->in;
273  AVFrame *out = td->out;
274  const int PP = td->PP;
275  const int xoff = td->xoff;
276  const int yoff = td->yoff;
277  const int P = FFMAX(s->nb_planes, s->nb_comps);
278  const int C = s->chars;
279  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
280  const int W = (outlink->w - xoff) / (C * 10);
281  const int H = (outlink->h - yoff) / (PP * 12);
282  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
283  const int slice_start = (W * jobnr) / nb_jobs;
284  const int slice_end = (W * (jobnr+1)) / nb_jobs;
285  int x, y, p;
286 
287  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
288  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
289  FFDrawColor color = { { 0 } };
290  int value[4] = { 0 }, pp = 0;
291 
292  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
293  for (p = 0; p < P; p++) {
294  char text[256];
295 
296  if (!(s->components & (1 << p)))
297  continue;
298  snprintf(text, sizeof(text), format[D], value[p]);
299  draw_text(&s->draw, out, &s->white, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
300  pp++;
301  }
302  }
303  }
304 
305  return 0;
306 }
307 
309 {
310  AVFilterContext *ctx = inlink->dst;
311  DatascopeContext *s = ctx->priv;
312  AVFilterLink *outlink = ctx->outputs[0];
313  const int P = FFMAX(s->nb_planes, s->nb_comps);
314  ThreadData td = { 0 };
315  int ymaxlen = 0;
316  int xmaxlen = 0;
317  int PP = 0;
318  AVFrame *out;
319 
320  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
321  if (!out) {
322  av_frame_free(&in);
323  return AVERROR(ENOMEM);
324  }
326 
327  ff_fill_rectangle(&s->draw, &s->black, out->data, out->linesize,
328  0, 0, outlink->w, outlink->h);
329 
330  for (int p = 0; p < P; p++) {
331  if (s->components & (1 << p))
332  PP++;
333  }
334  PP = FFMAX(PP, 1);
335 
336  if (s->axis) {
337  const int C = s->chars;
338  int Y = outlink->h / (PP * 12);
339  int X = outlink->w / (C * 10);
340  char text[256] = { 0 };
341  int x, y;
342 
343  snprintf(text, sizeof(text), "%d", s->y + Y);
344  ymaxlen = strlen(text);
345  ymaxlen *= 10;
346  snprintf(text, sizeof(text), "%d", s->x + X);
347  xmaxlen = strlen(text);
348  xmaxlen *= 10;
349 
350  Y = (outlink->h - xmaxlen) / (PP * 12);
351  X = (outlink->w - ymaxlen) / (C * 10);
352 
353  for (y = 0; y < Y; y++) {
354  snprintf(text, sizeof(text), "%d", s->y + y);
355 
356  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
357  0, xmaxlen + y * PP * 12 + (PP + 1) * PP - 2, ymaxlen, 10);
358 
359  draw_text(&s->draw, out, &s->yellow, 2, xmaxlen + y * PP * 12 + (PP + 1) * PP, text, 0);
360  }
361 
362  for (x = 0; x < X; x++) {
363  snprintf(text, sizeof(text), "%d", s->x + x);
364 
365  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
366  ymaxlen + x * C * 10 + 2 * C - 2, 0, 10, xmaxlen);
367 
368  draw_text(&s->draw, out, &s->yellow, ymaxlen + x * C * 10 + 2 * C, 2, text, 1);
369  }
370  }
371 
372  td.in = in; td.out = out, td.yoff = xmaxlen, td.xoff = ymaxlen, td.PP = PP;
373  ff_filter_execute(ctx, s->filter, &td, NULL,
374  FFMIN(ff_filter_get_nb_threads(ctx), FFMAX(outlink->w / 20, 1)));
375 
376  av_frame_free(&in);
377  return ff_filter_frame(outlink, out);
378 }
379 
381 {
382  DatascopeContext *s = inlink->dst->priv;
383  uint8_t alpha = s->opacity * 255;
384 
385  s->nb_planes = av_pix_fmt_count_planes(inlink->format);
386  ff_draw_init2(&s->draw, inlink->format, inlink->colorspace, inlink->color_range, 0);
387  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
388  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, alpha} );
389  ff_draw_color(&s->draw, &s->yellow, (uint8_t[]){ 255, 255, 0, 255} );
390  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 77, 77, 77, 255} );
391  s->chars = (s->draw.desc->comp[0].depth + 7) / 8 * 2 + s->dformat;
392  s->nb_comps = s->draw.desc->nb_components;
393 
394  switch (s->mode) {
395  case 0: s->filter = filter_mono; break;
396  case 1: s->filter = filter_color; break;
397  case 2: s->filter = filter_color2; break;
398  }
399 
400  if (s->draw.desc->comp[0].depth <= 8) {
401  s->pick_color = pick_color8;
402  s->reverse_color = reverse_color8;
403  } else {
404  s->pick_color = pick_color16;
405  s->reverse_color = reverse_color16;
406  }
407 
408  return 0;
409 }
410 
411 static int config_output(AVFilterLink *outlink)
412 {
413  DatascopeContext *s = outlink->src->priv;
414 
415  outlink->h = s->oh;
416  outlink->w = s->ow;
417  outlink->sample_aspect_ratio = (AVRational){1,1};
418 
419  return 0;
420 }
421 
422 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
423  char *res, int res_len, int flags)
424 {
425  int ret;
426 
427  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
428  if (ret < 0)
429  return ret;
430 
431  return config_input(ctx->inputs[0]);
432 }
433 
434 static const AVFilterPad inputs[] = {
435  {
436  .name = "default",
437  .type = AVMEDIA_TYPE_VIDEO,
438  .filter_frame = filter_frame,
439  .config_props = config_input,
440  },
441 };
442 
443 static const AVFilterPad outputs[] = {
444  {
445  .name = "default",
446  .type = AVMEDIA_TYPE_VIDEO,
447  .config_props = config_output,
448  },
449 };
450 
452  .name = "datascope",
453  .description = NULL_IF_CONFIG_SMALL("Video data analysis."),
454  .priv_size = sizeof(DatascopeContext),
455  .priv_class = &datascope_class,
460  .process_command = process_command,
461 };
462 
463 typedef struct PixscopeContext {
464  const AVClass *class;
465 
466  float xpos, ypos;
467  float wx, wy;
468  int w, h;
469  float o;
470 
471  int x, y;
472  int ww, wh;
473 
475  int nb_comps;
476  int is_rgb;
477  uint8_t rgba_map[4];
486 
487  uint16_t values[4][80][80];
488 
489  void (*pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value);
491 
492 #define POFFSET(x) offsetof(PixscopeContext, x)
493 
494 static const AVOption pixscope_options[] = {
495  { "x", "set scope x offset", POFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
496  { "y", "set scope y offset", POFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
497  { "w", "set scope width", POFFSET(w), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGSR },
498  { "h", "set scope height", POFFSET(h), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGSR },
499  { "o", "set window opacity", POFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
500  { "wx", "set window x offset", POFFSET(wx), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGSR },
501  { "wy", "set window y offset", POFFSET(wy), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGSR },
502  { NULL }
503 };
504 
505 AVFILTER_DEFINE_CLASS(pixscope);
506 
508 {
509  PixscopeContext *s = inlink->dst->priv;
510 
511  s->nb_planes = av_pix_fmt_count_planes(inlink->format);
512  ff_draw_init(&s->draw, inlink->format, 0);
513  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
514  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
515  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
516  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
517  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
518  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
519  s->nb_comps = s->draw.desc->nb_components;
520  s->is_rgb = s->draw.desc->flags & AV_PIX_FMT_FLAG_RGB;
521 
522  if (s->is_rgb) {
523  s->colors[0] = &s->red;
524  s->colors[1] = &s->green;
525  s->colors[2] = &s->blue;
526  s->colors[3] = &s->white;
527  ff_fill_rgba_map(s->rgba_map, inlink->format);
528  } else {
529  s->colors[0] = &s->white;
530  s->colors[1] = &s->blue;
531  s->colors[2] = &s->red;
532  s->colors[3] = &s->white;
533  s->rgba_map[0] = 0;
534  s->rgba_map[1] = 1;
535  s->rgba_map[2] = 2;
536  s->rgba_map[3] = 3;
537  }
538 
539  if (s->draw.desc->comp[0].depth <= 8) {
540  s->pick_color = pick_color8;
541  } else {
542  s->pick_color = pick_color16;
543  }
544 
545  if (inlink->w < 640 || inlink->h < 480) {
546  av_log(inlink->dst, AV_LOG_ERROR, "min supported resolution is 640x480\n");
547  return AVERROR(EINVAL);
548  }
549 
550  s->ww = 300;
551  s->wh = 300 * 1.6;
552  s->x = s->xpos * (inlink->w - 1);
553  s->y = s->ypos * (inlink->h - 1);
554  if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) {
555  av_log(inlink->dst, AV_LOG_WARNING, "scope position is out of range, clipping\n");
556  s->x = FFMIN(s->x, inlink->w - s->w);
557  s->y = FFMIN(s->y, inlink->h - s->h);
558  }
559 
560  return 0;
561 }
562 
563 #define SQR(x) ((x)*(x))
564 
566 {
567  AVFilterContext *ctx = inlink->dst;
568  PixscopeContext *s = ctx->priv;
569  AVFilterLink *outlink = ctx->outputs[0];
570  AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
571  int max[4] = { 0 }, min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
572  float average[4] = { 0 };
573  double std[4] = { 0 }, rms[4] = { 0 };
574  const char rgba[4] = { 'R', 'G', 'B', 'A' };
575  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
576  int x, y, X, Y, i, w, h;
577  char text[128];
578 
579  if (!out) {
580  av_frame_free(&in);
581  return AVERROR(ENOMEM);
582  }
584  av_frame_copy(out, in);
585 
586  w = s->ww / s->w;
587  h = s->ww / s->h;
588 
589  if (s->wx >= 0) {
590  X = (in->width - s->ww) * s->wx;
591  } else {
592  X = (in->width - s->ww) * -s->wx;
593  }
594  if (s->wy >= 0) {
595  Y = (in->height - s->wh) * s->wy;
596  } else {
597  Y = (in->height - s->wh) * -s->wy;
598  }
599 
600  if (s->wx < 0) {
601  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
602  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
603  X = (in->width - s->ww) * (1 + s->wx);
604  }
605  }
606 
607  if (s->wy < 0) {
608  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
609  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
610  Y = (in->height - s->wh) * (1 + s->wy);
611  }
612  }
613 
614  ff_blend_rectangle(&s->draw, &s->dark, out->data, out->linesize,
615  out->width, out->height,
616  X,
617  Y,
618  s->ww,
619  s->wh);
620 
621  for (y = 0; y < s->h; y++) {
622  for (x = 0; x < s->w; x++) {
623  FFDrawColor color = { { 0 } };
624  int value[4] = { 0 };
625 
626  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
627  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
628  x * w + (s->ww - 4 - (s->w * w)) / 2 + X, y * h + 2 + Y, w, h);
629  for (i = 0; i < 4; i++) {
630  s->values[i][x][y] = value[i];
631  rms[i] += (double)value[i] * (double)value[i];
632  average[i] += value[i];
633  min[i] = FFMIN(min[i], value[i]);
634  max[i] = FFMAX(max[i], value[i]);
635  }
636  }
637  }
638 
639  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
640  out->width, out->height,
641  s->x - 2, s->y - 2, s->w + 4, 1);
642 
643  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
644  out->width, out->height,
645  s->x - 1, s->y - 1, s->w + 2, 1);
646 
647  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
648  out->width, out->height,
649  s->x - 1, s->y - 1, 1, s->h + 2);
650 
651  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
652  out->width, out->height,
653  s->x - 2, s->y - 2, 1, s->h + 4);
654 
655  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
656  out->width, out->height,
657  s->x - 1, s->y + 1 + s->h, s->w + 3, 1);
658 
659  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
660  out->width, out->height,
661  s->x - 2, s->y + 2 + s->h, s->w + 4, 1);
662 
663  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
664  out->width, out->height,
665  s->x + 1 + s->w, s->y - 1, 1, s->h + 2);
666 
667  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
668  out->width, out->height,
669  s->x + 2 + s->w, s->y - 2, 1, s->h + 5);
670 
671  for (i = 0; i < 4; i++) {
672  rms[i] /= s->w * s->h;
673  rms[i] = sqrt(rms[i]);
674  average[i] /= s->w * s->h;
675  }
676 
677  for (y = 0; y < s->h; y++) {
678  for (x = 0; x < s->w; x++) {
679  for (i = 0; i < 4; i++)
680  std[i] += SQR(s->values[i][x][y] - average[i]);
681  }
682  }
683 
684  for (i = 0; i < 4; i++) {
685  std[i] /= s->w * s->h;
686  std[i] = sqrt(std[i]);
687  }
688 
689  snprintf(text, sizeof(text), "CH AVG MIN MAX RMS\n");
690  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 5, text, 0);
691  for (i = 0; i < s->nb_comps; i++) {
692  int c = s->rgba_map[i];
693 
694  snprintf(text, sizeof(text), "%c %07.1f %05d %05d %07.1f\n", s->is_rgb ? rgba[i] : yuva[i], average[c], min[c], max[c], rms[c]);
695  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 1), text, 0);
696  }
697  snprintf(text, sizeof(text), "CH STD\n");
698  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 15 * (0 + 5), text, 0);
699  for (i = 0; i < s->nb_comps; i++) {
700  int c = s->rgba_map[i];
701 
702  snprintf(text, sizeof(text), "%c %07.2f\n", s->is_rgb ? rgba[i] : yuva[i], std[c]);
703  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 6), text, 0);
704  }
705 
706  av_frame_free(&in);
707  return ff_filter_frame(outlink, out);
708 }
709 
710 static int pixscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
711  char *res, int res_len, int flags)
712 {
713  int ret;
714 
715  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
716  if (ret < 0)
717  return ret;
718 
719  return pixscope_config_input(ctx->inputs[0]);
720 }
721 
722 static const AVFilterPad pixscope_inputs[] = {
723  {
724  .name = "default",
725  .type = AVMEDIA_TYPE_VIDEO,
726  .filter_frame = pixscope_filter_frame,
727  .config_props = pixscope_config_input,
728  },
729 };
730 
732  .name = "pixscope",
733  .description = NULL_IF_CONFIG_SMALL("Pixel data analysis."),
734  .priv_size = sizeof(PixscopeContext),
735  .priv_class = &pixscope_class,
740  .process_command = pixscope_process_command,
741 };
742 
743 typedef struct PixelValues {
744  uint16_t p[4];
745 } PixelValues;
746 
747 typedef struct OscilloscopeContext {
748  const AVClass *class;
749 
750  float xpos, ypos;
751  float tx, ty;
752  float size;
753  float tilt;
754  float theight, twidth;
755  float o;
757  int grid;
759  int scope;
760 
761  int x1, y1, x2, y2;
762  int ox, oy;
763  int height, width;
764 
765  int max;
767  int nb_comps;
768  int is_rgb;
769  uint8_t rgba_map[4];
781 
784 
785  void (*pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value);
788 
789 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
790 
791 static const AVOption oscilloscope_options[] = {
792  { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
793  { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
794  { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
795  { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
796  { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
797  { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
798  { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGSR },
799  { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGSR },
800  { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGSR },
801  { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGSR },
802  { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
803  { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
804  { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
805  { NULL }
806 };
807 
808 AVFILTER_DEFINE_CLASS(oscilloscope);
809 
811 {
812  OscilloscopeContext *s = ctx->priv;
813 
814  av_freep(&s->values);
815 }
816 
817 static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1,
819 {
820  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
821  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
822  int err = (dx > dy ? dx : -dy) / 2, e2;
823  int p, i;
824 
825  for (;;) {
826  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
827  for (p = 0; p < draw->nb_planes; p++) {
828  if (draw->desc->comp[p].depth == 8) {
829  if (draw->nb_planes == 1) {
830  for (i = 0; i < draw->desc->nb_components; i++) {
831  out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i];
832  }
833  } else {
834  out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0];
835  }
836  } else {
837  if (draw->nb_planes == 1) {
838  for (i = 0; i < draw->desc->nb_components; i++) {
839  AV_WN16(out->data[0] + y0 * out->linesize[0] + (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]);
840  }
841  } else {
842  AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]);
843  }
844  }
845  }
846  }
847 
848  if (x0 == x1 && y0 == y1)
849  break;
850 
851  e2 = err;
852 
853  if (e2 >-dx) {
854  err -= dy;
855  x0 += sx;
856  }
857 
858  if (e2 < dy) {
859  err += dx;
860  y0 += sy;
861  }
862  }
863 }
864 
866 {
867  int i, c;
868 
869  for (i = 1; i < s->nb_values; i++) {
870  for (c = 0; c < s->nb_comps; c++) {
871  if ((1 << c) & s->components) {
872  int x = i * s->width / s->nb_values;
873  int px = (i - 1) * s->width / s->nb_values;
874  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256;
875  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256;
876 
877  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
878  }
879  }
880  }
881 }
882 
883 
885 {
886  int i, c;
887 
888  for (i = 1; i < s->nb_values; i++) {
889  for (c = 0; c < s->nb_comps; c++) {
890  if ((1 << c) & s->components) {
891  int x = i * s->width / s->nb_values;
892  int px = (i - 1) * s->width / s->nb_values;
893  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max;
894  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max;
895 
896  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
897  }
898  }
899  }
900 }
901 
903 {
904  OscilloscopeContext *s = ctx->priv;
905  AVFilterLink *inlink = ctx->inputs[0];
906  int cx, cy, size;
907  double tilt;
908 
909  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
910  s->height = s->theight * inlink->h;
911  s->width = s->twidth * inlink->w;
912  size = hypot(inlink->w, inlink->h);
913  size *= s->size;
914  tilt = (s->tilt - 0.5) * M_PI;
915  cx = s->xpos * (inlink->w - 1);
916  cy = s->ypos * (inlink->h - 1);
917  s->x1 = cx - size / 2.0 * cos(tilt);
918  s->x2 = cx + size / 2.0 * cos(tilt);
919  s->y1 = cy - size / 2.0 * sin(tilt);
920  s->y2 = cy + size / 2.0 * sin(tilt);
921  s->ox = (inlink->w - s->width) * s->tx;
922  s->oy = (inlink->h - s->height) * s->ty;
923 }
924 
926 {
927  OscilloscopeContext *s = inlink->dst->priv;
928  int size;
929 
930  s->nb_planes = av_pix_fmt_count_planes(inlink->format);
931  ff_draw_init(&s->draw, inlink->format, 0);
932  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
933  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
934  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
935  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
936  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
937  ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} );
938  ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} );
939  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} );
940  s->nb_comps = s->draw.desc->nb_components;
941  s->is_rgb = s->draw.desc->flags & AV_PIX_FMT_FLAG_RGB;
942 
943  if (s->is_rgb) {
944  s->colors[0] = &s->red;
945  s->colors[1] = &s->green;
946  s->colors[2] = &s->blue;
947  s->colors[3] = &s->white;
948  ff_fill_rgba_map(s->rgba_map, inlink->format);
949  } else {
950  s->colors[0] = &s->white;
951  s->colors[1] = &s->cyan;
952  s->colors[2] = &s->magenta;
953  s->colors[3] = &s->white;
954  s->rgba_map[0] = 0;
955  s->rgba_map[1] = 1;
956  s->rgba_map[2] = 2;
957  s->rgba_map[3] = 3;
958  }
959 
960  if (s->draw.desc->comp[0].depth <= 8) {
961  s->pick_color = pick_color8;
962  s->draw_trace = draw_trace8;
963  } else {
964  s->pick_color = pick_color16;
965  s->draw_trace = draw_trace16;
966  }
967 
968  s->max = (1 << s->draw.desc->comp[0].depth);
969  size = hypot(inlink->w, inlink->h);
970 
971  s->values = av_calloc(size, sizeof(*s->values));
972  if (!s->values)
973  return AVERROR(ENOMEM);
974 
976 
977  return 0;
978 }
979 
980 static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
981  AVFrame *out, PixelValues *p, int state)
982 {
983  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
984  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
985  int err = (dx > dy ? dx : -dy) / 2, e2;
986 
987  for (;;) {
988  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
989  FFDrawColor color = { { 0 } };
990  int value[4] = { 0 };
991 
992  s->pick_color(&s->draw, &color, out, x0, y0, value);
993  s->values[s->nb_values].p[0] = value[0];
994  s->values[s->nb_values].p[1] = value[1];
995  s->values[s->nb_values].p[2] = value[2];
996  s->values[s->nb_values].p[3] = value[3];
997  s->nb_values++;
998 
999  if (s->scope) {
1000  if (s->draw.desc->comp[0].depth == 8) {
1001  if (s->draw.nb_planes == 1) {
1002  int i;
1003 
1004  for (i = 0; i < s->nb_comps; i++)
1005  out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1);
1006  } else {
1007  out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1);
1008  }
1009  } else {
1010  if (s->draw.nb_planes == 1) {
1011  int i;
1012 
1013  for (i = 0; i < s->nb_comps; i++)
1014  AV_WN16(out->data[0] + out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i, (s->max - 1) * ((s->nb_values + state) & 1));
1015  } else {
1016  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1));
1017  }
1018  }
1019  }
1020  }
1021 
1022  if (x0 == x1 && y0 == y1)
1023  break;
1024 
1025  e2 = err;
1026 
1027  if (e2 >-dx) {
1028  err -= dy;
1029  x0 += sx;
1030  }
1031 
1032  if (e2 < dy) {
1033  err += dx;
1034  y0 += sy;
1035  }
1036  }
1037 }
1038 
1040 {
1041  AVFilterContext *ctx = inlink->dst;
1042  OscilloscopeContext *s = ctx->priv;
1043  AVFilterLink *outlink = ctx->outputs[0];
1044  float average[4] = { 0 };
1045  int max[4] = { 0 };
1046  int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
1047  int i, c;
1048 
1049  s->nb_values = 0;
1050  draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
1051  ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
1052  frame->width, frame->height,
1053  s->ox, s->oy, s->width, s->height + 20 * s->statistics);
1054 
1055  if (s->grid && outlink->h >= 10) {
1056  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1057  s->ox, s->oy, s->width - 1, 1);
1058 
1059  for (i = 1; i < 5; i++) {
1060  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1061  s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1);
1062  }
1063 
1064  for (i = 0; i < 10; i++) {
1065  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1066  s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height);
1067  }
1068 
1069  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1070  s->ox + s->width - 1, s->oy, 1, s->height);
1071  }
1072 
1073  s->draw_trace(s, frame);
1074 
1075  for (i = 0; i < s->nb_values; i++) {
1076  for (c = 0; c < s->nb_comps; c++) {
1077  if ((1 << c) & s->components) {
1078  max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]);
1079  min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]);
1080  average[c] += s->values[i].p[s->rgba_map[c]];
1081  }
1082  }
1083  }
1084  for (c = 0; c < s->nb_comps; c++) {
1085  average[c] /= s->nb_values;
1086  }
1087 
1088  if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) {
1089  for (c = 0, i = 0; c < s->nb_comps; c++) {
1090  if ((1 << c) & s->components) {
1091  const char rgba[4] = { 'R', 'G', 'B', 'A' };
1092  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
1093  char text[128];
1094 
1095  snprintf(text, sizeof(text), "%c avg:%.1f min:%d max:%d\n", s->is_rgb ? rgba[c] : yuva[c], average[c], min[c], max[c]);
1096  draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0);
1097  }
1098  }
1099  }
1100 
1101  return ff_filter_frame(outlink, frame);
1102 }
1103 
1104 static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1105  char *res, int res_len, int flags)
1106 {
1107  int ret;
1108 
1109  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1110  if (ret < 0)
1111  return ret;
1112 
1114 
1115  return 0;
1116 }
1117 
1119  {
1120  .name = "default",
1121  .type = AVMEDIA_TYPE_VIDEO,
1123  .filter_frame = oscilloscope_filter_frame,
1124  .config_props = oscilloscope_config_input,
1125  },
1126 };
1127 
1129  .name = "oscilloscope",
1130  .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."),
1131  .priv_size = sizeof(OscilloscopeContext),
1132  .priv_class = &oscilloscope_class,
1138  .process_command = oscilloscope_process_command,
1139 };
OscilloscopeContext::o
float o
Definition: vf_datascope.c:755
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:112
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
PixscopeContext::colors
FFDrawColor * colors[4]
Definition: vf_datascope.c:485
td
#define td
Definition: regdef.h:70
FFDrawColor
Definition: drawutils.h:50
DatascopeContext::components
int components
Definition: vf_datascope.c:39
DatascopeContext::x
int x
Definition: vf_datascope.c:35
reverse_color8
static void reverse_color8(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:144
pixscope_inputs
static const AVFilterPad pixscope_inputs[]
Definition: vf_datascope.c:722
OscilloscopeContext::oy
int oy
Definition: vf_datascope.c:762
filter_mono
static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:266
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
OscilloscopeContext::components
int components
Definition: vf_datascope.c:756
PixscopeContext::x
int x
Definition: vf_datascope.c:471
out
FILE * out
Definition: movenc.c:54
DatascopeContext::dformat
int dformat
Definition: vf_datascope.c:37
PixscopeContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_datascope.c:477
color
Definition: vf_paletteuse.c:511
pixscope_process_command
static int pixscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_datascope.c:710
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
filter_color2
static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:176
OscilloscopeContext::theight
float theight
Definition: vf_datascope.c:754
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:88
DatascopeContext::gray
FFDrawColor gray
Definition: vf_datascope.c:49
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
PixscopeContext::draw
FFDrawContext draw
Definition: vf_datascope.c:478
pixdesc.h
AVFrame::width
int width
Definition: frame.h:412
w
uint8_t w
Definition: llviddspenc.c:38
FFDrawColor::u16
uint16_t u16[8]
Definition: drawutils.h:54
AVOption
AVOption.
Definition: opt.h:346
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:159
OscilloscopeContext::ox
int ox
Definition: vf_datascope.c:762
FFDrawColor::rgba
uint8_t rgba[4]
Definition: drawutils.h:51
DatascopeContext::opacity
float opacity
Definition: vf_datascope.c:40
PixscopeContext::dark
FFDrawColor dark
Definition: vf_datascope.c:479
max
#define max(a, b)
Definition: cuda_runtime.h:33
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
PixscopeContext::y
int y
Definition: vf_datascope.c:471
OFFSET
#define OFFSET(x)
Definition: vf_datascope.c:56
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
OOFFSET
#define OOFFSET(x)
Definition: vf_datascope.c:789
av_popcount
#define av_popcount
Definition: common.h:152
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:526
pick_color8
static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:108
video.h
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:153
OscilloscopeContext::max
int max
Definition: vf_datascope.c:765
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
D
D(D(float, sse)
Definition: rematrix_init.c:29
formats.h
OscilloscopeContext::white
FFDrawColor white
Definition: vf_datascope.c:773
OscilloscopeContext::draw_trace
void(* draw_trace)(struct OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:786
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3002
OscilloscopeContext::gray
FFDrawColor gray
Definition: vf_datascope.c:779
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:422
ThreadData::yoff
int yoff
Definition: vf_datascope.c:173
DatascopeContext::chars
int chars
Definition: vf_datascope.c:44
OscilloscopeContext::y1
int y1
Definition: vf_datascope.c:761
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_datascope.c:422
ff_blend_mask
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0)
Blend an alpha mask with an uniform color.
Definition: drawutils.c:534
PixscopeContext::is_rgb
int is_rgb
Definition: vf_datascope.c:476
PixscopeContext::blue
FFDrawColor blue
Definition: vf_datascope.c:483
DatascopeContext::reverse_color
void(* reverse_color)(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:52
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
C
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s your new playground is ready Some little details about what s going which in turn will define variables for the build system and the C
Definition: writing_filters.txt:58
slice_start
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition: vvcdec.c:685
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
update_oscilloscope
static void update_oscilloscope(AVFilterContext *ctx)
Definition: vf_datascope.c:902
PixscopeContext::values
uint16_t values[4][80][80]
Definition: vf_datascope.c:487
OscilloscopeContext::ty
float ty
Definition: vf_datascope.c:751
ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:867
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
PixscopeContext::w
int w
Definition: vf_datascope.c:468
filter_color
static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:223
OscilloscopeContext::y2
int y2
Definition: vf_datascope.c:761
DatascopeContext::filter
int(* filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:53
OscilloscopeContext::ypos
float ypos
Definition: vf_datascope.c:750
state
static struct @382 state
width
#define width
intreadwrite.h
oscilloscope_uninit
static void oscilloscope_uninit(AVFilterContext *ctx)
Definition: vf_datascope.c:810
s
#define s(width, name)
Definition: cbs_vp9.c:198
PixelValues::p
uint16_t p[4]
Definition: vf_datascope.c:744
PixscopeContext::wy
float wy
Definition: vf_datascope.c:467
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:380
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:1717
inputs
static const AVFilterPad inputs[]
Definition: vf_datascope.c:434
OscilloscopeContext::nb_planes
int nb_planes
Definition: vf_datascope.c:766
PixscopeContext::red
FFDrawColor red
Definition: vf_datascope.c:484
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
OscilloscopeContext::height
int height
Definition: vf_datascope.c:763
ff_draw_init
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Definition: drawutils.c:151
pick_color16
static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:126
DatascopeContext::draw
FFDrawContext draw
Definition: vf_datascope.c:45
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
PixscopeContext::green
FFDrawColor green
Definition: vf_datascope.c:482
frame
static AVFrame * frame
Definition: demux_decode.c:54
OscilloscopeContext::nb_values
int nb_values
Definition: vf_datascope.c:782
reverse_color16
static void reverse_color16(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:156
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_datascope.c:80
arg
const char * arg
Definition: jacosubdec.c:67
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
POFFSET
#define POFFSET(x)
Definition: vf_datascope.c:492
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:637
PixscopeContext::white
FFDrawColor white
Definition: vf_datascope.c:481
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
OscilloscopeContext::magenta
FFDrawColor magenta
Definition: vf_datascope.c:778
AV_OPT_TYPE_IMAGE_SIZE
@ AV_OPT_TYPE_IMAGE_SIZE
offset must point to two consecutive integers
Definition: opt.h:245
parseutils.h
DatascopeContext
Definition: vf_datascope.c:32
OscilloscopeContext::colors
FFDrawColor * colors[4]
Definition: vf_datascope.c:780
DatascopeContext::oh
int oh
Definition: vf_datascope.c:34
datascope_options
static const AVOption datascope_options[]
Definition: vf_datascope.c:60
oscilloscope_options
static const AVOption oscilloscope_options[]
Definition: vf_datascope.c:791
double
double
Definition: af_crystalizer.c:131
PixscopeContext::nb_planes
int nb_planes
Definition: vf_datascope.c:474
FFDrawColor::u8
uint8_t u8[16]
Definition: drawutils.h:55
DatascopeContext::pick_color
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:51
OscilloscopeContext::tx
float tx
Definition: vf_datascope.c:751
draw_trace8
static void draw_trace8(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:865
PixscopeContext::o
float o
Definition: vf_datascope.c:469
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(datascope)
OscilloscopeContext::red
FFDrawColor red
Definition: vf_datascope.c:776
X
@ X
Definition: vf_addroi.c:27
draw_trace16
static void draw_trace16(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:884
DatascopeContext::ow
int ow
Definition: vf_datascope.c:34
OscilloscopeContext::nb_comps
int nb_comps
Definition: vf_datascope.c:767
PixscopeContext::wh
int wh
Definition: vf_datascope.c:472
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:106
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:308
DatascopeContext::mode
int mode
Definition: vf_datascope.c:36
FLAGS
#define FLAGS
Definition: vf_datascope.c:57
AV_PIX_FMT_FLAG_RGB
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:136
ThreadData::PP
int PP
Definition: vf_datascope.c:173
P
#define P
ff_blend_rectangle
void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, int x0, int y0, int w, int h)
Blend a rectangle with an uniform color.
Definition: drawutils.c:353
av_frame_copy
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:769
oscilloscope_process_command
static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_datascope.c:1104
ff_draw_init2
int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, enum AVColorRange range, unsigned flags)
Init a draw context.
Definition: drawutils.c:80
hypot
static av_const double hypot(double x, double y)
Definition: libm.h:366
outputs
static const AVFilterPad outputs[]
Definition: vf_datascope.c:443
size
int size
Definition: twinvq_data.h:10344
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:94
draw_text
static void draw_text(FFDrawContext *draw, AVFrame *frame, FFDrawColor *color, int x0, int y0, const uint8_t *text, int vertical)
Definition: vf_datascope.c:85
oscilloscope_inputs
static const AVFilterPad oscilloscope_inputs[]
Definition: vf_datascope.c:1118
ff_fill_rectangle
void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_x, int dst_y, int w, int h)
Fill a rectangle with an uniform color.
Definition: drawutils.c:231
OscilloscopeContext::cyan
FFDrawColor cyan
Definition: vf_datascope.c:777
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:890
pixscope_filter_frame
static int pixscope_filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:565
height
#define height
H
#define H
Definition: pixlet.c:38
OscilloscopeContext::pick_color
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:785
OscilloscopeContext::size
float size
Definition: vf_datascope.c:752
xga_font_data.h
OscilloscopeContext::x1
int x1
Definition: vf_datascope.c:761
DatascopeContext::nb_comps
int nb_comps
Definition: vf_datascope.c:43
M_PI
#define M_PI
Definition: mathematics.h:67
Y
#define Y
Definition: boxblur.h:37
ff_vf_pixscope
const AVFilter ff_vf_pixscope
Definition: vf_datascope.c:731
draw
static int draw(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showcwt.c:451
internal.h
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:147
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:238
W
@ W
Definition: vf_addroi.c:27
OscilloscopeContext::scope
int scope
Definition: vf_datascope.c:759
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
OscilloscopeContext
Definition: vf_datascope.c:747
OscilloscopeContext::black
FFDrawColor black
Definition: vf_datascope.c:772
PixscopeContext
Definition: vf_datascope.c:463
OscilloscopeContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_datascope.c:769
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
SQR
#define SQR(x)
Definition: vf_datascope.c:563
DatascopeContext::white
FFDrawColor white
Definition: vf_datascope.c:47
OscilloscopeContext::tilt
float tilt
Definition: vf_datascope.c:753
DatascopeContext::y
int y
Definition: vf_datascope.c:35
OscilloscopeContext::statistics
int statistics
Definition: vf_datascope.c:758
ff_draw_supported_pixel_formats
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:647
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:825
OscilloscopeContext::green
FFDrawColor green
Definition: vf_datascope.c:774
OscilloscopeContext::xpos
float xpos
Definition: vf_datascope.c:750
ThreadData
Used for passing data between threads.
Definition: dsddec.c:69
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
DatascopeContext::black
FFDrawColor black
Definition: vf_datascope.c:48
DatascopeContext::axis
int axis
Definition: vf_datascope.c:38
FFDrawContext
Definition: drawutils.h:35
OscilloscopeContext::dark
FFDrawColor dark
Definition: vf_datascope.c:771
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
FLAGSR
#define FLAGSR
Definition: vf_datascope.c:58
OscilloscopeContext::is_rgb
int is_rgb
Definition: vf_datascope.c:768
DatascopeContext::nb_planes
int nb_planes
Definition: vf_datascope.c:42
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
ff_draw_color
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:156
AVFilter
Filter definition.
Definition: avfilter.h:166
PixscopeContext::pick_color
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:489
ThreadData::xoff
int xoff
Definition: vf_datascope.c:173
ret
ret
Definition: filter_design.txt:187
PixscopeContext::black
FFDrawColor black
Definition: vf_datascope.c:480
OscilloscopeContext::draw
FFDrawContext draw
Definition: vf_datascope.c:770
ff_vf_oscilloscope
const AVFilter ff_vf_oscilloscope
Definition: vf_datascope.c:1128
OscilloscopeContext::twidth
float twidth
Definition: vf_datascope.c:754
AVFrame::height
int height
Definition: frame.h:412
OscilloscopeContext::grid
int grid
Definition: vf_datascope.c:757
PixscopeContext::nb_comps
int nb_comps
Definition: vf_datascope.c:475
mode
mode
Definition: ebur128.h:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avfilter.h
PixscopeContext::xpos
float xpos
Definition: vf_datascope.c:466
PixscopeContext::ypos
float ypos
Definition: vf_datascope.c:466
AVFilterContext
An instance of a filter.
Definition: avfilter.h:407
PixscopeContext::h
int h
Definition: vf_datascope.c:468
OscilloscopeContext::width
int width
Definition: vf_datascope.c:763
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ff_vf_datascope
const AVFilter ff_vf_datascope
Definition: vf_datascope.c:451
PixscopeContext::wx
float wx
Definition: vf_datascope.c:467
draw_scope
static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1, AVFrame *out, PixelValues *p, int state)
Definition: vf_datascope.c:980
avpriv_cga_font
const uint8_t avpriv_cga_font[2048]
Definition: xga_font_data.c:29
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_datascope.c:411
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
FFDrawColor::comp
union FFDrawColor::@248 comp[MAX_PLANES]
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
draw_line
static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1, AVFrame *out, FFDrawColor *color)
Definition: vf_datascope.c:817
pixscope_options
static const AVOption pixscope_options[]
Definition: vf_datascope.c:494
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
pixscope_config_input
static int pixscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:507
ff_fill_rgba_map
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
DatascopeContext::yellow
FFDrawColor yellow
Definition: vf_datascope.c:46
OscilloscopeContext::blue
FFDrawColor blue
Definition: vf_datascope.c:775
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2038
OscilloscopeContext::values
PixelValues * values
Definition: vf_datascope.c:783
drawutils.h
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:134
OscilloscopeContext::x2
int x2
Definition: vf_datascope.c:761
int
int
Definition: ffmpeg_filter.c:425
PixelValues
Definition: vf_datascope.c:743
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244
snprintf
#define snprintf
Definition: snprintf.h:34
oscilloscope_filter_frame
static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_datascope.c:1039
PixscopeContext::ww
int ww
Definition: vf_datascope.c:472
oscilloscope_config_input
static int oscilloscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:925
min
float min
Definition: vorbis_enc_data.h:429
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: internal.h:52
AV_WN16
#define AV_WN16(p, v)
Definition: intreadwrite.h:370