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/avassert.h"
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/parseutils.h"
25 #include "libavutil/pixdesc.h"
27 #include "avfilter.h"
28 #include "drawutils.h"
29 #include "formats.h"
30 #include "internal.h"
31 #include "video.h"
32 
33 typedef struct DatascopeContext {
34  const AVClass *class;
35  int ow, oh;
36  int x, y;
37  int mode;
38  int dformat;
39  int axis;
40  float opacity;
41 
42  int nb_planes;
43  int nb_comps;
44  int chars;
50 
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, FLAGS },
64  { "y", "set y offset", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
65  { "mode", "set scope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mode" },
66  { "mono", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
67  { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
68  { "color2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mode" },
69  { "axis", "draw column/row numbers", OFFSET(axis), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
70  { "opacity", "set background opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
71  { "format", "set display number format", OFFSET(dformat), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "format" },
72  { "hex", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "format" },
73  { "dec", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "format" },
74  { NULL }
75 };
76 
77 AVFILTER_DEFINE_CLASS(datascope);
78 
80 {
82 }
83 
85  int x0, int y0, const uint8_t *text, int vertical)
86 {
87  int x = x0;
88 
89  for (; *text; text++) {
90  if (*text == '\n') {
91  x = x0;
92  y0 += 8;
93  continue;
94  }
95  ff_blend_mask(draw, color, frame->data, frame->linesize,
96  frame->width, frame->height,
97  avpriv_cga_font + *text * 8, 1, 8, 8, 0, 0, x, y0);
98  if (vertical) {
99  x = x0;
100  y0 += 8;
101  } else {
102  x += 8;
103  }
104  }
105 }
106 
107 static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
108 {
109  int p, i;
110 
111  color->rgba[3] = 255;
112  for (p = 0; p < draw->nb_planes; p++) {
113  if (draw->nb_planes == 1) {
114  for (i = 0; i < 4; i++) {
115  value[i] = in->data[0][y * in->linesize[0] + x * draw->pixelstep[0] + i];
116  color->comp[0].u8[i] = value[i];
117  }
118  } else {
119  value[p] = in->data[p][(y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p])];
120  color->comp[p].u8[0] = value[p];
121  }
122  }
123 }
124 
125 static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
126 {
127  int p, i;
128 
129  color->rgba[3] = 255;
130  for (p = 0; p < draw->nb_planes; p++) {
131  if (draw->nb_planes == 1) {
132  for (i = 0; i < 4; i++) {
133  value[i] = AV_RL16(in->data[0] + y * in->linesize[0] + x * draw->pixelstep[0] + i * 2);
134  color->comp[0].u16[i] = value[i];
135  }
136  } else {
137  value[p] = AV_RL16(in->data[p] + (y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p]) * 2);
138  color->comp[p].u16[0] = value[p];
139  }
140  }
141 }
142 
144 {
145  int p;
146 
147  reverse->rgba[3] = 255;
148  for (p = 0; p < draw->nb_planes; p++) {
149  reverse->comp[p].u8[0] = color->comp[p].u8[0] > 127 ? 0 : 255;
150  reverse->comp[p].u8[1] = color->comp[p].u8[1] > 127 ? 0 : 255;
151  reverse->comp[p].u8[2] = color->comp[p].u8[2] > 127 ? 0 : 255;
152  }
153 }
154 
156 {
157  int p;
158 
159  reverse->rgba[3] = 255;
160  for (p = 0; p < draw->nb_planes; p++) {
161  const unsigned max = (1 << draw->desc->comp[p].depth) - 1;
162  const unsigned mid = (max + 1) / 2;
163 
164  reverse->comp[p].u16[0] = color->comp[p].u16[0] > mid ? 0 : max;
165  reverse->comp[p].u16[1] = color->comp[p].u16[1] > mid ? 0 : max;
166  reverse->comp[p].u16[2] = color->comp[p].u16[2] > mid ? 0 : max;
167  }
168 }
169 
170 typedef struct ThreadData {
171  AVFrame *in, *out;
172  int xoff, yoff;
173 } ThreadData;
174 
175 static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
176 {
177  DatascopeContext *s = ctx->priv;
178  AVFilterLink *outlink = ctx->outputs[0];
179  AVFilterLink *inlink = ctx->inputs[0];
180  ThreadData *td = arg;
181  AVFrame *in = td->in;
182  AVFrame *out = td->out;
183  const int xoff = td->xoff;
184  const int yoff = td->yoff;
185  const int P = FFMAX(s->nb_planes, s->nb_comps);
186  const int C = s->chars;
187  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
188  const int W = (outlink->w - xoff) / (C * 10);
189  const int H = (outlink->h - yoff) / (P * 12);
190  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
191  const int slice_start = (W * jobnr) / nb_jobs;
192  const int slice_end = (W * (jobnr+1)) / nb_jobs;
193  int x, y, p;
194 
195  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
196  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
197  FFDrawColor color = { { 0 } };
198  FFDrawColor reverse = { { 0 } };
199  int value[4] = { 0 };
200 
201  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
202  s->reverse_color(&s->draw, &color, &reverse);
203  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
204  xoff + x * C * 10, yoff + y * P * 12, C * 10, P * 12);
205 
206  for (p = 0; p < P; p++) {
207  char text[256];
208 
209  snprintf(text, sizeof(text), format[D], value[p]);
210  draw_text(&s->draw, out, &reverse, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
211  }
212  }
213  }
214 
215  return 0;
216 }
217 
218 static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
219 {
220  DatascopeContext *s = ctx->priv;
221  AVFilterLink *outlink = ctx->outputs[0];
222  AVFilterLink *inlink = ctx->inputs[0];
223  ThreadData *td = arg;
224  AVFrame *in = td->in;
225  AVFrame *out = td->out;
226  const int xoff = td->xoff;
227  const int yoff = td->yoff;
228  const int P = FFMAX(s->nb_planes, s->nb_comps);
229  const int C = s->chars;
230  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
231  const int W = (outlink->w - xoff) / (C * 10);
232  const int H = (outlink->h - yoff) / (P * 12);
233  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
234  const int slice_start = (W * jobnr) / nb_jobs;
235  const int slice_end = (W * (jobnr+1)) / nb_jobs;
236  int x, y, p;
237 
238  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
239  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
240  FFDrawColor color = { { 0 } };
241  int value[4] = { 0 };
242 
243  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
244 
245  for (p = 0; p < P; p++) {
246  char text[256];
247 
248  snprintf(text, sizeof(text), format[D], value[p]);
249  draw_text(&s->draw, out, &color, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
250  }
251  }
252  }
253 
254  return 0;
255 }
256 
257 static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
258 {
259  DatascopeContext *s = ctx->priv;
260  AVFilterLink *outlink = ctx->outputs[0];
261  AVFilterLink *inlink = ctx->inputs[0];
262  ThreadData *td = arg;
263  AVFrame *in = td->in;
264  AVFrame *out = td->out;
265  const int xoff = td->xoff;
266  const int yoff = td->yoff;
267  const int P = FFMAX(s->nb_planes, s->nb_comps);
268  const int C = s->chars;
269  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
270  const int W = (outlink->w - xoff) / (C * 10);
271  const int H = (outlink->h - yoff) / (P * 12);
272  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
273  const int slice_start = (W * jobnr) / nb_jobs;
274  const int slice_end = (W * (jobnr+1)) / nb_jobs;
275  int x, y, p;
276 
277  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
278  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
279  FFDrawColor color = { { 0 } };
280  int value[4] = { 0 };
281 
282  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
283  for (p = 0; p < P; p++) {
284  char text[256];
285 
286  snprintf(text, sizeof(text), format[D], value[p]);
287  draw_text(&s->draw, out, &s->white, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
288  }
289  }
290  }
291 
292  return 0;
293 }
294 
296 {
297  AVFilterContext *ctx = inlink->dst;
298  DatascopeContext *s = ctx->priv;
299  AVFilterLink *outlink = ctx->outputs[0];
300  ThreadData td = { 0 };
301  int ymaxlen = 0;
302  int xmaxlen = 0;
303  AVFrame *out;
304 
305  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
306  if (!out) {
307  av_frame_free(&in);
308  return AVERROR(ENOMEM);
309  }
310  out->pts = in->pts;
311 
312  ff_fill_rectangle(&s->draw, &s->black, out->data, out->linesize,
313  0, 0, outlink->w, outlink->h);
314 
315  if (s->axis) {
316  const int P = FFMAX(s->nb_planes, s->nb_comps);
317  const int C = s->chars;
318  int Y = outlink->h / (P * 12);
319  int X = outlink->w / (C * 10);
320  char text[256] = { 0 };
321  int x, y;
322 
323  snprintf(text, sizeof(text), "%d", s->y + Y);
324  ymaxlen = strlen(text);
325  ymaxlen *= 10;
326  snprintf(text, sizeof(text), "%d", s->x + X);
327  xmaxlen = strlen(text);
328  xmaxlen *= 10;
329 
330  Y = (outlink->h - xmaxlen) / (P * 12);
331  X = (outlink->w - ymaxlen) / (C * 10);
332 
333  for (y = 0; y < Y; y++) {
334  snprintf(text, sizeof(text), "%d", s->y + y);
335 
336  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
337  0, xmaxlen + y * P * 12 + (P + 1) * P - 2, ymaxlen, 10);
338 
339  draw_text(&s->draw, out, &s->yellow, 2, xmaxlen + y * P * 12 + (P + 1) * P, text, 0);
340  }
341 
342  for (x = 0; x < X; x++) {
343  snprintf(text, sizeof(text), "%d", s->x + x);
344 
345  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
346  ymaxlen + x * C * 10 + 2 * C - 2, 0, 10, xmaxlen);
347 
348  draw_text(&s->draw, out, &s->yellow, ymaxlen + x * C * 10 + 2 * C, 2, text, 1);
349  }
350  }
351 
352  td.in = in; td.out = out, td.yoff = xmaxlen, td.xoff = ymaxlen;
353  ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN(ff_filter_get_nb_threads(ctx), FFMAX(outlink->w / 20, 1)));
354 
355  av_frame_free(&in);
356  return ff_filter_frame(outlink, out);
357 }
358 
360 {
361  DatascopeContext *s = inlink->dst->priv;
362  uint8_t alpha = s->opacity * 255;
363 
365  ff_draw_init(&s->draw, inlink->format, 0);
366  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
367  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, alpha} );
368  ff_draw_color(&s->draw, &s->yellow, (uint8_t[]){ 255, 255, 0, 255} );
369  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 77, 77, 77, 255} );
370  s->chars = (s->draw.desc->comp[0].depth + 7) / 8 * 2 + s->dformat;
371  s->nb_comps = s->draw.desc->nb_components;
372 
373  switch (s->mode) {
374  case 0: s->filter = filter_mono; break;
375  case 1: s->filter = filter_color; break;
376  case 2: s->filter = filter_color2; break;
377  }
378 
379  if (s->draw.desc->comp[0].depth <= 8) {
380  s->pick_color = pick_color8;
382  } else {
385  }
386 
387  return 0;
388 }
389 
390 static int config_output(AVFilterLink *outlink)
391 {
392  DatascopeContext *s = outlink->src->priv;
393 
394  outlink->h = s->oh;
395  outlink->w = s->ow;
396  outlink->sample_aspect_ratio = (AVRational){1,1};
397 
398  return 0;
399 }
400 
401 static const AVFilterPad inputs[] = {
402  {
403  .name = "default",
404  .type = AVMEDIA_TYPE_VIDEO,
405  .filter_frame = filter_frame,
406  .config_props = config_input,
407  },
408  { NULL }
409 };
410 
411 static const AVFilterPad outputs[] = {
412  {
413  .name = "default",
414  .type = AVMEDIA_TYPE_VIDEO,
415  .config_props = config_output,
416  },
417  { NULL }
418 };
419 
421  .name = "datascope",
422  .description = NULL_IF_CONFIG_SMALL("Video data analysis."),
423  .priv_size = sizeof(DatascopeContext),
424  .priv_class = &datascope_class,
426  .inputs = inputs,
427  .outputs = outputs,
429 };
430 
431 typedef struct PixscopeContext {
432  const AVClass *class;
433 
434  float xpos, ypos;
435  float wx, wy;
436  int w, h;
437  float o;
438 
439  int x, y;
440  int ww, wh;
441 
443  int nb_comps;
444  int is_rgb;
445  uint8_t rgba_map[4];
453  FFDrawColor *colors[4];
454 
455  uint16_t values[4][80][80];
456 
459 
460 #define POFFSET(x) offsetof(PixscopeContext, x)
461 
462 static const AVOption pixscope_options[] = {
463  { "x", "set scope x offset", POFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
464  { "y", "set scope y offset", POFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
465  { "w", "set scope width", POFFSET(w), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
466  { "h", "set scope height", POFFSET(h), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
467  { "o", "set window opacity", POFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
468  { "wx", "set window x offset", POFFSET(wx), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
469  { "wy", "set window y offset", POFFSET(wy), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
470  { NULL }
471 };
472 
473 AVFILTER_DEFINE_CLASS(pixscope);
474 
476 {
477  PixscopeContext *s = inlink->dst->priv;
478 
480  ff_draw_init(&s->draw, inlink->format, 0);
481  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
482  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
483  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
484  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
485  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
486  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
487  s->nb_comps = s->draw.desc->nb_components;
489 
490  if (s->is_rgb) {
491  s->colors[0] = &s->red;
492  s->colors[1] = &s->green;
493  s->colors[2] = &s->blue;
494  s->colors[3] = &s->white;
495  ff_fill_rgba_map(s->rgba_map, inlink->format);
496  } else {
497  s->colors[0] = &s->white;
498  s->colors[1] = &s->blue;
499  s->colors[2] = &s->red;
500  s->colors[3] = &s->white;
501  s->rgba_map[0] = 0;
502  s->rgba_map[1] = 1;
503  s->rgba_map[2] = 2;
504  s->rgba_map[3] = 3;
505  }
506 
507  if (s->draw.desc->comp[0].depth <= 8) {
508  s->pick_color = pick_color8;
509  } else {
511  }
512 
513  if (inlink->w < 640 || inlink->h < 480) {
514  av_log(inlink->dst, AV_LOG_ERROR, "min supported resolution is 640x480\n");
515  return AVERROR(EINVAL);
516  }
517 
518  s->ww = 300;
519  s->wh = 300 * 1.6;
520  s->x = s->xpos * (inlink->w - 1);
521  s->y = s->ypos * (inlink->h - 1);
522  if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) {
523  av_log(inlink->dst, AV_LOG_WARNING, "scope position is out of range, clipping\n");
524  s->x = FFMIN(s->x, inlink->w - s->w);
525  s->y = FFMIN(s->y, inlink->h - s->h);
526  }
527 
528  return 0;
529 }
530 
531 #define SQR(x) ((x)*(x))
532 
534 {
535  AVFilterContext *ctx = inlink->dst;
536  PixscopeContext *s = ctx->priv;
537  AVFilterLink *outlink = ctx->outputs[0];
538  AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
539  int max[4] = { 0 }, min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
540  float average[4] = { 0 };
541  double std[4] = { 0 }, rms[4] = { 0 };
542  const char rgba[4] = { 'R', 'G', 'B', 'A' };
543  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
544  int x, y, X, Y, i, w, h;
545  char text[128];
546 
547  if (!out) {
548  av_frame_free(&in);
549  return AVERROR(ENOMEM);
550  }
551  av_frame_copy_props(out, in);
552  av_frame_copy(out, in);
553 
554  w = s->ww / s->w;
555  h = s->ww / s->h;
556 
557  if (s->wx >= 0) {
558  X = (in->width - s->ww) * s->wx;
559  } else {
560  X = (in->width - s->ww) * -s->wx;
561  }
562  if (s->wy >= 0) {
563  Y = (in->height - s->wh) * s->wy;
564  } else {
565  Y = (in->height - s->wh) * -s->wy;
566  }
567 
568  if (s->wx < 0) {
569  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
570  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
571  X = (in->width - s->ww) * (1 + s->wx);
572  }
573  }
574 
575  if (s->wy < 0) {
576  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
577  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
578  Y = (in->height - s->wh) * (1 + s->wy);
579  }
580  }
581 
582  ff_blend_rectangle(&s->draw, &s->dark, out->data, out->linesize,
583  out->width, out->height,
584  X,
585  Y,
586  s->ww,
587  s->wh);
588 
589  for (y = 0; y < s->h; y++) {
590  for (x = 0; x < s->w; x++) {
591  FFDrawColor color = { { 0 } };
592  int value[4] = { 0 };
593 
594  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
595  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
596  x * w + (s->ww - 4 - (s->w * w)) / 2 + X, y * h + 2 + Y, w, h);
597  for (i = 0; i < 4; i++) {
598  s->values[i][x][y] = value[i];
599  rms[i] += (double)value[i] * (double)value[i];
600  average[i] += value[i];
601  min[i] = FFMIN(min[i], value[i]);
602  max[i] = FFMAX(max[i], value[i]);
603  }
604  }
605  }
606 
607  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
608  out->width, out->height,
609  s->x - 2, s->y - 2, s->w + 4, 1);
610 
611  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
612  out->width, out->height,
613  s->x - 1, s->y - 1, s->w + 2, 1);
614 
615  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
616  out->width, out->height,
617  s->x - 1, s->y - 1, 1, s->h + 2);
618 
619  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
620  out->width, out->height,
621  s->x - 2, s->y - 2, 1, s->h + 4);
622 
623  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
624  out->width, out->height,
625  s->x - 1, s->y + 1 + s->h, s->w + 3, 1);
626 
627  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
628  out->width, out->height,
629  s->x - 2, s->y + 2 + s->h, s->w + 4, 1);
630 
631  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
632  out->width, out->height,
633  s->x + 1 + s->w, s->y - 1, 1, s->h + 2);
634 
635  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
636  out->width, out->height,
637  s->x + 2 + s->w, s->y - 2, 1, s->h + 5);
638 
639  for (i = 0; i < 4; i++) {
640  rms[i] /= s->w * s->h;
641  rms[i] = sqrt(rms[i]);
642  average[i] /= s->w * s->h;
643  }
644 
645  for (y = 0; y < s->h; y++) {
646  for (x = 0; x < s->w; x++) {
647  for (i = 0; i < 4; i++)
648  std[i] += SQR(s->values[i][x][y] - average[i]);
649  }
650  }
651 
652  for (i = 0; i < 4; i++) {
653  std[i] /= s->w * s->h;
654  std[i] = sqrt(std[i]);
655  }
656 
657  snprintf(text, sizeof(text), "CH AVG MIN MAX RMS\n");
658  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 5, text, 0);
659  for (i = 0; i < s->nb_comps; i++) {
660  int c = s->rgba_map[i];
661 
662  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]);
663  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 1), text, 0);
664  }
665  snprintf(text, sizeof(text), "CH STD\n");
666  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 15 * (0 + 5), text, 0);
667  for (i = 0; i < s->nb_comps; i++) {
668  int c = s->rgba_map[i];
669 
670  snprintf(text, sizeof(text), "%c %07.2f\n", s->is_rgb ? rgba[i] : yuva[i], std[c]);
671  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 6), text, 0);
672  }
673 
674  av_frame_free(&in);
675  return ff_filter_frame(outlink, out);
676 }
677 
678 static const AVFilterPad pixscope_inputs[] = {
679  {
680  .name = "default",
681  .type = AVMEDIA_TYPE_VIDEO,
682  .filter_frame = pixscope_filter_frame,
683  .config_props = pixscope_config_input,
684  },
685  { NULL }
686 };
687 
688 static const AVFilterPad pixscope_outputs[] = {
689  {
690  .name = "default",
691  .type = AVMEDIA_TYPE_VIDEO,
692  },
693  { NULL }
694 };
695 
697  .name = "pixscope",
698  .description = NULL_IF_CONFIG_SMALL("Pixel data analysis."),
699  .priv_size = sizeof(PixscopeContext),
700  .priv_class = &pixscope_class,
702  .inputs = pixscope_inputs,
703  .outputs = pixscope_outputs,
705 };
706 
707 typedef struct PixelValues {
708  uint16_t p[4];
709 } PixelValues;
710 
711 typedef struct OscilloscopeContext {
712  const AVClass *class;
713 
714  float xpos, ypos;
715  float tx, ty;
716  float size;
717  float tilt;
718  float theight, twidth;
719  float o;
721  int grid;
723  int scope;
724 
725  int x1, y1, x2, y2;
726  int ox, oy;
727  int height, width;
728 
729  int max;
731  int nb_comps;
732  int is_rgb;
733  uint8_t rgba_map[4];
744  FFDrawColor *colors[4];
745 
748 
750  void (*draw_trace)(struct OscilloscopeContext *s, AVFrame *frame);
752 
753 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
754 
755 static const AVOption oscilloscope_options[] = {
756  { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
757  { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
758  { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
759  { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
760  { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
761  { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
762  { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGSR },
763  { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGSR },
764  { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGSR },
765  { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGSR },
766  { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
767  { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
768  { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
769  { NULL }
770 };
771 
772 AVFILTER_DEFINE_CLASS(oscilloscope);
773 
775 {
776  OscilloscopeContext *s = ctx->priv;
777 
778  av_freep(&s->values);
779 }
780 
781 static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1,
783 {
784  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
785  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
786  int err = (dx > dy ? dx : -dy) / 2, e2;
787  int p, i;
788 
789  for (;;) {
790  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
791  for (p = 0; p < draw->nb_planes; p++) {
792  if (draw->desc->comp[p].depth == 8) {
793  if (draw->nb_planes == 1) {
794  for (i = 0; i < draw->desc->nb_components; i++) {
795  out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i];
796  }
797  } else {
798  out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0];
799  }
800  } else {
801  if (draw->nb_planes == 1) {
802  for (i = 0; i < draw->desc->nb_components; i++) {
803  AV_WN16(out->data[0] + y0 * out->linesize[0] + (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]);
804  }
805  } else {
806  AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]);
807  }
808  }
809  }
810  }
811 
812  if (x0 == x1 && y0 == y1)
813  break;
814 
815  e2 = err;
816 
817  if (e2 >-dx) {
818  err -= dy;
819  x0 += sx;
820  }
821 
822  if (e2 < dy) {
823  err += dx;
824  y0 += sy;
825  }
826  }
827 }
828 
830 {
831  int i, c;
832 
833  for (i = 1; i < s->nb_values; i++) {
834  for (c = 0; c < s->nb_comps; c++) {
835  if ((1 << c) & s->components) {
836  int x = i * s->width / s->nb_values;
837  int px = (i - 1) * s->width / s->nb_values;
838  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256;
839  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256;
840 
841  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
842  }
843  }
844  }
845 }
846 
847 
849 {
850  int i, c;
851 
852  for (i = 1; i < s->nb_values; i++) {
853  for (c = 0; c < s->nb_comps; c++) {
854  if ((1 << c) & s->components) {
855  int x = i * s->width / s->nb_values;
856  int px = (i - 1) * s->width / s->nb_values;
857  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max;
858  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max;
859 
860  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
861  }
862  }
863  }
864 }
865 
867 {
868  OscilloscopeContext *s = ctx->priv;
869  AVFilterLink *inlink = ctx->inputs[0];
870  int cx, cy, size;
871  double tilt;
872 
873  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
874  s->height = s->theight * inlink->h;
875  s->width = s->twidth * inlink->w;
876  size = hypot(inlink->w, inlink->h);
877  size *= s->size;
878  tilt = (s->tilt - 0.5) * M_PI;
879  cx = s->xpos * (inlink->w - 1);
880  cy = s->ypos * (inlink->h - 1);
881  s->x1 = cx - size / 2.0 * cos(tilt);
882  s->x2 = cx + size / 2.0 * cos(tilt);
883  s->y1 = cy - size / 2.0 * sin(tilt);
884  s->y2 = cy + size / 2.0 * sin(tilt);
885  s->ox = (inlink->w - s->width) * s->tx;
886  s->oy = (inlink->h - s->height) * s->ty;
887 }
888 
890 {
891  OscilloscopeContext *s = inlink->dst->priv;
892  int size;
893 
895  ff_draw_init(&s->draw, inlink->format, 0);
896  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
897  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
898  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
899  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
900  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
901  ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} );
902  ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} );
903  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} );
904  s->nb_comps = s->draw.desc->nb_components;
906 
907  if (s->is_rgb) {
908  s->colors[0] = &s->red;
909  s->colors[1] = &s->green;
910  s->colors[2] = &s->blue;
911  s->colors[3] = &s->white;
912  ff_fill_rgba_map(s->rgba_map, inlink->format);
913  } else {
914  s->colors[0] = &s->white;
915  s->colors[1] = &s->cyan;
916  s->colors[2] = &s->magenta;
917  s->colors[3] = &s->white;
918  s->rgba_map[0] = 0;
919  s->rgba_map[1] = 1;
920  s->rgba_map[2] = 2;
921  s->rgba_map[3] = 3;
922  }
923 
924  if (s->draw.desc->comp[0].depth <= 8) {
925  s->pick_color = pick_color8;
926  s->draw_trace = draw_trace8;
927  } else {
930  }
931 
932  s->max = (1 << s->draw.desc->comp[0].depth);
933  size = hypot(inlink->w, inlink->h);
934 
935  s->values = av_calloc(size, sizeof(*s->values));
936  if (!s->values)
937  return AVERROR(ENOMEM);
938 
939  update_oscilloscope(inlink->dst);
940 
941  return 0;
942 }
943 
944 static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
945  AVFrame *out, PixelValues *p, int state)
946 {
947  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
948  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
949  int err = (dx > dy ? dx : -dy) / 2, e2;
950 
951  for (;;) {
952  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
953  FFDrawColor color = { { 0 } };
954  int value[4] = { 0 };
955 
956  s->pick_color(&s->draw, &color, out, x0, y0, value);
957  s->values[s->nb_values].p[0] = value[0];
958  s->values[s->nb_values].p[1] = value[1];
959  s->values[s->nb_values].p[2] = value[2];
960  s->values[s->nb_values].p[3] = value[3];
961  s->nb_values++;
962 
963  if (s->scope) {
964  if (s->draw.desc->comp[0].depth == 8) {
965  if (s->draw.nb_planes == 1) {
966  int i;
967 
968  for (i = 0; i < s->nb_comps; i++)
969  out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1);
970  } else {
971  out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1);
972  }
973  } else {
974  if (s->draw.nb_planes == 1) {
975  int i;
976 
977  for (i = 0; i < s->nb_comps; i++)
978  AV_WN16(out->data[0] + out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i, (s->max - 1) * ((s->nb_values + state) & 1));
979  } else {
980  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1));
981  }
982  }
983  }
984  }
985 
986  if (x0 == x1 && y0 == y1)
987  break;
988 
989  e2 = err;
990 
991  if (e2 >-dx) {
992  err -= dy;
993  x0 += sx;
994  }
995 
996  if (e2 < dy) {
997  err += dx;
998  y0 += sy;
999  }
1000  }
1001 }
1002 
1004 {
1005  AVFilterContext *ctx = inlink->dst;
1006  OscilloscopeContext *s = ctx->priv;
1007  AVFilterLink *outlink = ctx->outputs[0];
1008  float average[4] = { 0 };
1009  int max[4] = { 0 };
1010  int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
1011  int i, c;
1012 
1013  s->nb_values = 0;
1014  draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
1015  ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
1016  frame->width, frame->height,
1017  s->ox, s->oy, s->width, s->height + 20 * s->statistics);
1018 
1019  if (s->grid && outlink->h >= 10) {
1020  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1021  s->ox, s->oy, s->width - 1, 1);
1022 
1023  for (i = 1; i < 5; i++) {
1024  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1025  s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1);
1026  }
1027 
1028  for (i = 0; i < 10; i++) {
1029  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1030  s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height);
1031  }
1032 
1033  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1034  s->ox + s->width - 1, s->oy, 1, s->height);
1035  }
1036 
1037  s->draw_trace(s, frame);
1038 
1039  for (i = 0; i < s->nb_values; i++) {
1040  for (c = 0; c < s->nb_comps; c++) {
1041  if ((1 << c) & s->components) {
1042  max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]);
1043  min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]);
1044  average[c] += s->values[i].p[s->rgba_map[c]];
1045  }
1046  }
1047  }
1048  for (c = 0; c < s->nb_comps; c++) {
1049  average[c] /= s->nb_values;
1050  }
1051 
1052  if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) {
1053  for (c = 0, i = 0; c < s->nb_comps; c++) {
1054  if ((1 << c) & s->components) {
1055  const char rgba[4] = { 'R', 'G', 'B', 'A' };
1056  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
1057  char text[128];
1058 
1059  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]);
1060  draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0);
1061  }
1062  }
1063  }
1064 
1065  return ff_filter_frame(outlink, frame);
1066 }
1067 
1068 static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1069  char *res, int res_len, int flags)
1070 {
1071  int ret;
1072 
1073  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1074  if (ret < 0)
1075  return ret;
1076 
1077  update_oscilloscope(ctx);
1078 
1079  return 0;
1080 }
1081 
1083  {
1084  .name = "default",
1085  .type = AVMEDIA_TYPE_VIDEO,
1086  .filter_frame = oscilloscope_filter_frame,
1087  .config_props = oscilloscope_config_input,
1088  .needs_writable = 1,
1089  },
1090  { NULL }
1091 };
1092 
1094  {
1095  .name = "default",
1096  .type = AVMEDIA_TYPE_VIDEO,
1097  },
1098  { NULL }
1099 };
1100 
1102  .name = "oscilloscope",
1103  .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."),
1104  .priv_size = sizeof(OscilloscopeContext),
1105  .priv_class = &oscilloscope_class,
1108  .inputs = oscilloscope_inputs,
1109  .outputs = oscilloscope_outputs,
1112 };
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:731
#define NULL
Definition: coverity.c:32
FFDrawContext draw
Definition: vf_datascope.c:734
#define P
AVFrame * out
Definition: af_adeclick.c:494
This structure describes decoded (raw) audio or video data.
Definition: frame.h:314
static const AVOption pixscope_options[]
Definition: vf_datascope.c:462
AVOption.
Definition: opt.h:248
uint16_t u16[8]
Definition: drawutils.h:66
uint8_t hsub[MAX_PLANES]
Definition: drawutils.h:54
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2613
Main libavfilter public API header.
void(* draw_trace)(struct OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:750
static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:175
FFDrawColor magenta
Definition: vf_datascope.c:742
FFDrawColor * colors[4]
Definition: vf_datascope.c:744
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
AVFilter ff_vf_pixscope
Definition: vf_datascope.c:696
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
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:91
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:257
#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:126
FFDrawColor black
Definition: vf_datascope.c:448
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:349
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1091
#define OOFFSET(x)
Definition: vf_datascope.c:753
#define OFFSET(x)
Definition: vf_datascope.c:56
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:125
uint8_t
static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:107
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
FFDrawColor gray
Definition: vf_datascope.c:49
void(* reverse_color)(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:52
AVOptions.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:218
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
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:407
#define height
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:749
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:457
static const AVFilterPad inputs[]
Definition: vf_datascope.c:401
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhqenc.c:54
#define max(a, b)
Definition: cuda_runtime.h:33
ptrdiff_t size
Definition: opengl_enc.c:100
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
static const AVOption datascope_options[]
Definition: vf_datascope.c:60
#define POFFSET(x)
Definition: vf_datascope.c:460
static void draw_trace16(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:848
static void draw_trace8(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:829
int width
Definition: frame.h:372
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
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:588
#define td
Definition: regdef.h:70
const uint8_t avpriv_cga_font[2048]
Definition: xga_font_data.c:29
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:148
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
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:885
void * priv
private data for use by the filter
Definition: avfilter.h:356
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
const char * arg
Definition: jacosubdec.c:66
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:231
simple assert() macros that are a bit more flexible than ISO C assert().
static const AVFilterPad oscilloscope_inputs[]
static const AVFilterPad oscilloscope_outputs[]
#define FFMAX(a, b)
Definition: common.h:94
uint8_t u8[16]
Definition: drawutils.h:67
static void reverse_color16(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:155
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:799
FFDrawColor * colors[4]
Definition: vf_datascope.c:453
static void oscilloscope_uninit(AVFilterContext *ctx)
Definition: vf_datascope.c:774
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
FFDrawContext draw
Definition: vf_datascope.c:45
static void update_oscilloscope(AVFilterContext *ctx)
Definition: vf_datascope.c:866
static av_const double hypot(double x, double y)
Definition: libm.h:366
uint8_t nb_components
The number of components each pixel has, (1-4)
Definition: pixdesc.h:83
int(* filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:53
#define Y
Definition: boxblur.h:38
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:800
#define FFMIN(a, b)
Definition: common.h:96
union FFDrawColor::@209 comp[MAX_PLANES]
uint8_t rgba_map[4]
Definition: vf_datascope.c:445
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:295
#define width
uint8_t w
Definition: llviddspenc.c:38
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return values
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
#define SQR(x)
Definition: vf_datascope.c:531
AVFormatContext * ctx
Definition: movenc.c:48
static int config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:359
static int query_formats(AVFilterContext *ctx)
Definition: vf_datascope.c:79
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
#define s(width, name)
Definition: cbs_vp9.c:257
AVFilter ff_vf_oscilloscope
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:51
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
AVFILTER_DEFINE_CLASS(datascope)
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
#define FLAGS
Definition: vf_datascope.c:57
PixelValues * values
Definition: vf_datascope.c:747
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:622
static const AVFilterPad outputs[]
Definition: vf_datascope.c:411
FFDrawColor dark
Definition: vf_datascope.c:447
misc drawing utilities
static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Used for passing data between threads.
Definition: dsddec.c:67
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:345
unsigned nb_planes
Definition: drawutils.h:51
static const AVOption oscilloscope_options[]
Definition: vf_datascope.c:755
static void draw_text(FFDrawContext *draw, AVFrame *frame, FFDrawColor *color, int x0, int y0, const uint8_t *text, int vertical)
Definition: vf_datascope.c:84
static const int16_t alpha[]
Definition: ilbcdata.h:55
FFDrawContext draw
Definition: vf_datascope.c:446
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
static int pixscope_filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:533
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:145
Rational number (pair of numerator and denominator).
Definition: rational.h:58
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:445
const char * name
Filter name.
Definition: avfilter.h:149
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:178
#define snprintf
Definition: snprintf.h:34
offset must point to two consecutive integers
Definition: opt.h:235
misc parsing utilities
FFDrawColor blue
Definition: vf_datascope.c:451
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:353
Definition: vf_addroi.c:26
uint16_t p[4]
Definition: vf_datascope.c:708
#define flags(name, subs,...)
Definition: cbs_av1.c:560
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:381
#define FLAGSR
Definition: vf_datascope.c:58
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:328
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
int
static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1, AVFrame *out, PixelValues *p, int state)
Definition: vf_datascope.c:944
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_adenorm.c:275
static struct @323 state
D(D(float, sse)
Definition: rematrix_init.c:28
FFDrawColor white
Definition: vf_datascope.c:47
static int config_output(AVFilterLink *outlink)
Definition: vf_datascope.c:390
static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
static int pixscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:475
avfilter_execute_func * execute
Definition: internal.h:136
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2035
FFDrawColor yellow
Definition: vf_datascope.c:46
uint16_t values[4][80][80]
Definition: vf_datascope.c:455
FFDrawColor black
Definition: vf_datascope.c:48
AVFilter ff_vf_datascope
Definition: vf_datascope.c:420
static const AVFilterPad pixscope_outputs[]
Definition: vf_datascope.c:688
int pixelstep[MAX_PLANES]
Definition: drawutils.h:52
#define H
Definition: pixlet.c:39
const struct AVPixFmtDescriptor * desc
Definition: drawutils.h:49
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:318
An instance of a filter.
Definition: avfilter.h:341
int height
Definition: frame.h:372
FILE * out
Definition: movenc.c:54
uint8_t vsub[MAX_PLANES]
Definition: drawutils.h:55
#define av_freep(p)
Definition: vf_addroi.c:26
#define AV_WN16(p, v)
Definition: intreadwrite.h:372
#define M_PI
Definition: mathematics.h:52
FFDrawColor red
Definition: vf_datascope.c:452
AVFrame * in
Definition: af_adenorm.c:223
static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1, AVFrame *out, FFDrawColor *color)
Definition: vf_datascope.c:781
internal API functions
static int oscilloscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:889
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
int depth
Number of bits in the component.
Definition: pixdesc.h:58
FFDrawColor green
Definition: vf_datascope.c:450
float min
static const AVFilterPad pixscope_inputs[]
Definition: vf_datascope.c:678
mode
Use these values in ebur128_init (or&#39;ed).
Definition: ebur128.h:83
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:658
int i
Definition: input.c:407
CGA/EGA/VGA ROM font data.
static void reverse_color8(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:143
uint8_t rgba[4]
Definition: drawutils.h:63
FFDrawColor white
Definition: vf_datascope.c:449