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;
41  float opacity;
42 
43  int nb_planes;
44  int nb_comps;
45  int chars;
51 
54  int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
56 
57 #define OFFSET(x) offsetof(DatascopeContext, x)
58 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
59 #define FLAGSR AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
60 
61 static const AVOption datascope_options[] = {
62  { "size", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
63  { "s", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
64  { "x", "set x offset", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
65  { "y", "set y offset", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
66  { "mode", "set scope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mode" },
67  { "mono", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
68  { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
69  { "color2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mode" },
70  { "axis", "draw column/row numbers", OFFSET(axis), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
71  { "opacity", "set background opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
72  { "format", "set display number format", OFFSET(dformat), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "format" },
73  { "hex", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "format" },
74  { "dec", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "format" },
75  { "components", "set components to display", OFFSET(components), AV_OPT_TYPE_INT, {.i64=15}, 1, 15, FLAGS },
76  { NULL }
77 };
78 
79 AVFILTER_DEFINE_CLASS(datascope);
80 
82 {
84 }
85 
87  int x0, int y0, const uint8_t *text, int vertical)
88 {
89  int x = x0;
90 
91  for (; *text; text++) {
92  if (*text == '\n') {
93  x = x0;
94  y0 += 8;
95  continue;
96  }
97  ff_blend_mask(draw, color, frame->data, frame->linesize,
98  frame->width, frame->height,
99  avpriv_cga_font + *text * 8, 1, 8, 8, 0, 0, x, y0);
100  if (vertical) {
101  x = x0;
102  y0 += 8;
103  } else {
104  x += 8;
105  }
106  }
107 }
108 
109 static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
110 {
111  int p, i;
112 
113  color->rgba[3] = 255;
114  for (p = 0; p < draw->nb_planes; p++) {
115  if (draw->nb_planes == 1) {
116  for (i = 0; i < 4; i++) {
117  value[i] = in->data[0][y * in->linesize[0] + x * draw->pixelstep[0] + i];
118  color->comp[0].u8[i] = value[i];
119  }
120  } else {
121  value[p] = in->data[p][(y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p])];
122  color->comp[p].u8[0] = value[p];
123  }
124  }
125 }
126 
127 static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
128 {
129  int p, i;
130 
131  color->rgba[3] = 255;
132  for (p = 0; p < draw->nb_planes; p++) {
133  if (draw->nb_planes == 1) {
134  for (i = 0; i < 4; i++) {
135  value[i] = AV_RL16(in->data[0] + y * in->linesize[0] + x * draw->pixelstep[0] + i * 2);
136  color->comp[0].u16[i] = value[i];
137  }
138  } else {
139  value[p] = AV_RL16(in->data[p] + (y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p]) * 2);
140  color->comp[p].u16[0] = value[p];
141  }
142  }
143 }
144 
146 {
147  int p;
148 
149  reverse->rgba[3] = 255;
150  for (p = 0; p < draw->nb_planes; p++) {
151  reverse->comp[p].u8[0] = color->comp[p].u8[0] > 127 ? 0 : 255;
152  reverse->comp[p].u8[1] = color->comp[p].u8[1] > 127 ? 0 : 255;
153  reverse->comp[p].u8[2] = color->comp[p].u8[2] > 127 ? 0 : 255;
154  }
155 }
156 
158 {
159  int p;
160 
161  reverse->rgba[3] = 255;
162  for (p = 0; p < draw->nb_planes; p++) {
163  const unsigned max = (1 << draw->desc->comp[p].depth) - 1;
164  const unsigned mid = (max + 1) / 2;
165 
166  reverse->comp[p].u16[0] = color->comp[p].u16[0] > mid ? 0 : max;
167  reverse->comp[p].u16[1] = color->comp[p].u16[1] > mid ? 0 : max;
168  reverse->comp[p].u16[2] = color->comp[p].u16[2] > mid ? 0 : max;
169  }
170 }
171 
172 typedef struct ThreadData {
173  AVFrame *in, *out;
174  int xoff, yoff, PP;
175 } ThreadData;
176 
177 static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
178 {
179  DatascopeContext *s = ctx->priv;
180  AVFilterLink *outlink = ctx->outputs[0];
181  AVFilterLink *inlink = ctx->inputs[0];
182  ThreadData *td = arg;
183  AVFrame *in = td->in;
184  AVFrame *out = td->out;
185  const int PP = td->PP;
186  const int xoff = td->xoff;
187  const int yoff = td->yoff;
188  const int P = FFMAX(s->nb_planes, s->nb_comps);
189  const int C = s->chars;
190  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
191  const int W = (outlink->w - xoff) / (C * 10);
192  const int H = (outlink->h - yoff) / (PP * 12);
193  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
194  const int slice_start = (W * jobnr) / nb_jobs;
195  const int slice_end = (W * (jobnr+1)) / nb_jobs;
196  int x, y, p;
197 
198  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
199  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
200  FFDrawColor color = { { 0 } };
201  FFDrawColor reverse = { { 0 } };
202  int value[4] = { 0 }, pp = 0;
203 
204  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
205  s->reverse_color(&s->draw, &color, &reverse);
206  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
207  xoff + x * C * 10, yoff + y * PP * 12, C * 10, PP * 12);
208 
209  for (p = 0; p < P; p++) {
210  char text[256];
211 
212  if (!(s->components & (1 << p)))
213  continue;
214  snprintf(text, sizeof(text), format[D], value[p]);
215  draw_text(&s->draw, out, &reverse, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
216  pp++;
217  }
218  }
219  }
220 
221  return 0;
222 }
223 
224 static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
225 {
226  DatascopeContext *s = ctx->priv;
227  AVFilterLink *outlink = ctx->outputs[0];
228  AVFilterLink *inlink = ctx->inputs[0];
229  ThreadData *td = arg;
230  AVFrame *in = td->in;
231  AVFrame *out = td->out;
232  const int PP = td->PP;
233  const int xoff = td->xoff;
234  const int yoff = td->yoff;
235  const int P = FFMAX(s->nb_planes, s->nb_comps);
236  const int C = s->chars;
237  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
238  const int W = (outlink->w - xoff) / (C * 10);
239  const int H = (outlink->h - yoff) / (PP * 12);
240  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
241  const int slice_start = (W * jobnr) / nb_jobs;
242  const int slice_end = (W * (jobnr+1)) / nb_jobs;
243  int x, y, p;
244 
245  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
246  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
247  FFDrawColor color = { { 0 } };
248  int value[4] = { 0 }, pp = 0;
249 
250  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
251 
252  for (p = 0; p < P; p++) {
253  char text[256];
254 
255  if (!(s->components & (1 << p)))
256  continue;
257  snprintf(text, sizeof(text), format[D], value[p]);
258  draw_text(&s->draw, out, &color, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
259  pp++;
260  }
261  }
262  }
263 
264  return 0;
265 }
266 
267 static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
268 {
269  DatascopeContext *s = ctx->priv;
270  AVFilterLink *outlink = ctx->outputs[0];
271  AVFilterLink *inlink = ctx->inputs[0];
272  ThreadData *td = arg;
273  AVFrame *in = td->in;
274  AVFrame *out = td->out;
275  const int PP = td->PP;
276  const int xoff = td->xoff;
277  const int yoff = td->yoff;
278  const int P = FFMAX(s->nb_planes, s->nb_comps);
279  const int C = s->chars;
280  const int D = ((s->chars - s->dformat) >> 2) + s->dformat * 2;
281  const int W = (outlink->w - xoff) / (C * 10);
282  const int H = (outlink->h - yoff) / (PP * 12);
283  const char *format[4] = {"%02X\n", "%04X\n", "%03d\n", "%05d\n"};
284  const int slice_start = (W * jobnr) / nb_jobs;
285  const int slice_end = (W * (jobnr+1)) / nb_jobs;
286  int x, y, p;
287 
288  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
289  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
290  FFDrawColor color = { { 0 } };
291  int value[4] = { 0 }, pp = 0;
292 
293  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
294  for (p = 0; p < P; p++) {
295  char text[256];
296 
297  if (!(s->components & (1 << p)))
298  continue;
299  snprintf(text, sizeof(text), format[D], value[p]);
300  draw_text(&s->draw, out, &s->white, xoff + x * C * 10 + 2, yoff + y * PP * 12 + pp * 10 + 2, text, 0);
301  pp++;
302  }
303  }
304  }
305 
306  return 0;
307 }
308 
310 {
311  AVFilterContext *ctx = inlink->dst;
312  DatascopeContext *s = ctx->priv;
313  AVFilterLink *outlink = ctx->outputs[0];
314  const int P = FFMAX(s->nb_planes, s->nb_comps);
315  ThreadData td = { 0 };
316  int ymaxlen = 0;
317  int xmaxlen = 0;
318  int PP = 0;
319  AVFrame *out;
320 
321  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
322  if (!out) {
323  av_frame_free(&in);
324  return AVERROR(ENOMEM);
325  }
326  out->pts = in->pts;
327 
328  ff_fill_rectangle(&s->draw, &s->black, out->data, out->linesize,
329  0, 0, outlink->w, outlink->h);
330 
331  for (int p = 0; p < P; p++) {
332  if (s->components & (1 << p))
333  PP++;
334  }
335  PP = FFMAX(PP, 1);
336 
337  if (s->axis) {
338  const int C = s->chars;
339  int Y = outlink->h / (PP * 12);
340  int X = outlink->w / (C * 10);
341  char text[256] = { 0 };
342  int x, y;
343 
344  snprintf(text, sizeof(text), "%d", s->y + Y);
345  ymaxlen = strlen(text);
346  ymaxlen *= 10;
347  snprintf(text, sizeof(text), "%d", s->x + X);
348  xmaxlen = strlen(text);
349  xmaxlen *= 10;
350 
351  Y = (outlink->h - xmaxlen) / (PP * 12);
352  X = (outlink->w - ymaxlen) / (C * 10);
353 
354  for (y = 0; y < Y; y++) {
355  snprintf(text, sizeof(text), "%d", s->y + y);
356 
357  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
358  0, xmaxlen + y * PP * 12 + (PP + 1) * PP - 2, ymaxlen, 10);
359 
360  draw_text(&s->draw, out, &s->yellow, 2, xmaxlen + y * PP * 12 + (PP + 1) * PP, text, 0);
361  }
362 
363  for (x = 0; x < X; x++) {
364  snprintf(text, sizeof(text), "%d", s->x + x);
365 
366  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
367  ymaxlen + x * C * 10 + 2 * C - 2, 0, 10, xmaxlen);
368 
369  draw_text(&s->draw, out, &s->yellow, ymaxlen + x * C * 10 + 2 * C, 2, text, 1);
370  }
371  }
372 
373  td.in = in; td.out = out, td.yoff = xmaxlen, td.xoff = ymaxlen, td.PP = PP;
374  ctx->internal->execute(ctx, s->filter, &td, NULL, 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 
386  ff_draw_init(&s->draw, inlink->format, 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;
403  } else {
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 const AVFilterPad inputs[] = {
423  {
424  .name = "default",
425  .type = AVMEDIA_TYPE_VIDEO,
426  .filter_frame = filter_frame,
427  .config_props = config_input,
428  },
429  { NULL }
430 };
431 
432 static const AVFilterPad outputs[] = {
433  {
434  .name = "default",
435  .type = AVMEDIA_TYPE_VIDEO,
436  .config_props = config_output,
437  },
438  { NULL }
439 };
440 
442  .name = "datascope",
443  .description = NULL_IF_CONFIG_SMALL("Video data analysis."),
444  .priv_size = sizeof(DatascopeContext),
445  .priv_class = &datascope_class,
447  .inputs = inputs,
448  .outputs = outputs,
450 };
451 
452 typedef struct PixscopeContext {
453  const AVClass *class;
454 
455  float xpos, ypos;
456  float wx, wy;
457  int w, h;
458  float o;
459 
460  int x, y;
461  int ww, wh;
462 
464  int nb_comps;
465  int is_rgb;
466  uint8_t rgba_map[4];
474  FFDrawColor *colors[4];
475 
476  uint16_t values[4][80][80];
477 
480 
481 #define POFFSET(x) offsetof(PixscopeContext, x)
482 
483 static const AVOption pixscope_options[] = {
484  { "x", "set scope x offset", POFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
485  { "y", "set scope y offset", POFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
486  { "w", "set scope width", POFFSET(w), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
487  { "h", "set scope height", POFFSET(h), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
488  { "o", "set window opacity", POFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
489  { "wx", "set window x offset", POFFSET(wx), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
490  { "wy", "set window y offset", POFFSET(wy), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
491  { NULL }
492 };
493 
494 AVFILTER_DEFINE_CLASS(pixscope);
495 
497 {
498  PixscopeContext *s = inlink->dst->priv;
499 
501  ff_draw_init(&s->draw, inlink->format, 0);
502  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
503  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
504  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
505  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
506  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
507  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
508  s->nb_comps = s->draw.desc->nb_components;
510 
511  if (s->is_rgb) {
512  s->colors[0] = &s->red;
513  s->colors[1] = &s->green;
514  s->colors[2] = &s->blue;
515  s->colors[3] = &s->white;
516  ff_fill_rgba_map(s->rgba_map, inlink->format);
517  } else {
518  s->colors[0] = &s->white;
519  s->colors[1] = &s->blue;
520  s->colors[2] = &s->red;
521  s->colors[3] = &s->white;
522  s->rgba_map[0] = 0;
523  s->rgba_map[1] = 1;
524  s->rgba_map[2] = 2;
525  s->rgba_map[3] = 3;
526  }
527 
528  if (s->draw.desc->comp[0].depth <= 8) {
529  s->pick_color = pick_color8;
530  } else {
532  }
533 
534  if (inlink->w < 640 || inlink->h < 480) {
535  av_log(inlink->dst, AV_LOG_ERROR, "min supported resolution is 640x480\n");
536  return AVERROR(EINVAL);
537  }
538 
539  s->ww = 300;
540  s->wh = 300 * 1.6;
541  s->x = s->xpos * (inlink->w - 1);
542  s->y = s->ypos * (inlink->h - 1);
543  if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) {
544  av_log(inlink->dst, AV_LOG_WARNING, "scope position is out of range, clipping\n");
545  s->x = FFMIN(s->x, inlink->w - s->w);
546  s->y = FFMIN(s->y, inlink->h - s->h);
547  }
548 
549  return 0;
550 }
551 
552 #define SQR(x) ((x)*(x))
553 
555 {
556  AVFilterContext *ctx = inlink->dst;
557  PixscopeContext *s = ctx->priv;
558  AVFilterLink *outlink = ctx->outputs[0];
559  AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
560  int max[4] = { 0 }, min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
561  float average[4] = { 0 };
562  double std[4] = { 0 }, rms[4] = { 0 };
563  const char rgba[4] = { 'R', 'G', 'B', 'A' };
564  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
565  int x, y, X, Y, i, w, h;
566  char text[128];
567 
568  if (!out) {
569  av_frame_free(&in);
570  return AVERROR(ENOMEM);
571  }
572  av_frame_copy_props(out, in);
573  av_frame_copy(out, in);
574 
575  w = s->ww / s->w;
576  h = s->ww / s->h;
577 
578  if (s->wx >= 0) {
579  X = (in->width - s->ww) * s->wx;
580  } else {
581  X = (in->width - s->ww) * -s->wx;
582  }
583  if (s->wy >= 0) {
584  Y = (in->height - s->wh) * s->wy;
585  } else {
586  Y = (in->height - s->wh) * -s->wy;
587  }
588 
589  if (s->wx < 0) {
590  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
591  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
592  X = (in->width - s->ww) * (1 + s->wx);
593  }
594  }
595 
596  if (s->wy < 0) {
597  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
598  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
599  Y = (in->height - s->wh) * (1 + s->wy);
600  }
601  }
602 
603  ff_blend_rectangle(&s->draw, &s->dark, out->data, out->linesize,
604  out->width, out->height,
605  X,
606  Y,
607  s->ww,
608  s->wh);
609 
610  for (y = 0; y < s->h; y++) {
611  for (x = 0; x < s->w; x++) {
612  FFDrawColor color = { { 0 } };
613  int value[4] = { 0 };
614 
615  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
616  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
617  x * w + (s->ww - 4 - (s->w * w)) / 2 + X, y * h + 2 + Y, w, h);
618  for (i = 0; i < 4; i++) {
619  s->values[i][x][y] = value[i];
620  rms[i] += (double)value[i] * (double)value[i];
621  average[i] += value[i];
622  min[i] = FFMIN(min[i], value[i]);
623  max[i] = FFMAX(max[i], value[i]);
624  }
625  }
626  }
627 
628  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
629  out->width, out->height,
630  s->x - 2, s->y - 2, s->w + 4, 1);
631 
632  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
633  out->width, out->height,
634  s->x - 1, s->y - 1, s->w + 2, 1);
635 
636  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
637  out->width, out->height,
638  s->x - 1, s->y - 1, 1, s->h + 2);
639 
640  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
641  out->width, out->height,
642  s->x - 2, s->y - 2, 1, s->h + 4);
643 
644  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
645  out->width, out->height,
646  s->x - 1, s->y + 1 + s->h, s->w + 3, 1);
647 
648  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
649  out->width, out->height,
650  s->x - 2, s->y + 2 + s->h, s->w + 4, 1);
651 
652  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
653  out->width, out->height,
654  s->x + 1 + s->w, s->y - 1, 1, s->h + 2);
655 
656  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
657  out->width, out->height,
658  s->x + 2 + s->w, s->y - 2, 1, s->h + 5);
659 
660  for (i = 0; i < 4; i++) {
661  rms[i] /= s->w * s->h;
662  rms[i] = sqrt(rms[i]);
663  average[i] /= s->w * s->h;
664  }
665 
666  for (y = 0; y < s->h; y++) {
667  for (x = 0; x < s->w; x++) {
668  for (i = 0; i < 4; i++)
669  std[i] += SQR(s->values[i][x][y] - average[i]);
670  }
671  }
672 
673  for (i = 0; i < 4; i++) {
674  std[i] /= s->w * s->h;
675  std[i] = sqrt(std[i]);
676  }
677 
678  snprintf(text, sizeof(text), "CH AVG MIN MAX RMS\n");
679  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 5, text, 0);
680  for (i = 0; i < s->nb_comps; i++) {
681  int c = s->rgba_map[i];
682 
683  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]);
684  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 1), text, 0);
685  }
686  snprintf(text, sizeof(text), "CH STD\n");
687  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 15 * (0 + 5), text, 0);
688  for (i = 0; i < s->nb_comps; i++) {
689  int c = s->rgba_map[i];
690 
691  snprintf(text, sizeof(text), "%c %07.2f\n", s->is_rgb ? rgba[i] : yuva[i], std[c]);
692  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 6), text, 0);
693  }
694 
695  av_frame_free(&in);
696  return ff_filter_frame(outlink, out);
697 }
698 
699 static const AVFilterPad pixscope_inputs[] = {
700  {
701  .name = "default",
702  .type = AVMEDIA_TYPE_VIDEO,
703  .filter_frame = pixscope_filter_frame,
704  .config_props = pixscope_config_input,
705  },
706  { NULL }
707 };
708 
709 static const AVFilterPad pixscope_outputs[] = {
710  {
711  .name = "default",
712  .type = AVMEDIA_TYPE_VIDEO,
713  },
714  { NULL }
715 };
716 
718  .name = "pixscope",
719  .description = NULL_IF_CONFIG_SMALL("Pixel data analysis."),
720  .priv_size = sizeof(PixscopeContext),
721  .priv_class = &pixscope_class,
723  .inputs = pixscope_inputs,
724  .outputs = pixscope_outputs,
726 };
727 
728 typedef struct PixelValues {
729  uint16_t p[4];
730 } PixelValues;
731 
732 typedef struct OscilloscopeContext {
733  const AVClass *class;
734 
735  float xpos, ypos;
736  float tx, ty;
737  float size;
738  float tilt;
739  float theight, twidth;
740  float o;
742  int grid;
744  int scope;
745 
746  int x1, y1, x2, y2;
747  int ox, oy;
748  int height, width;
749 
750  int max;
752  int nb_comps;
753  int is_rgb;
754  uint8_t rgba_map[4];
765  FFDrawColor *colors[4];
766 
769 
771  void (*draw_trace)(struct OscilloscopeContext *s, AVFrame *frame);
773 
774 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
775 
776 static const AVOption oscilloscope_options[] = {
777  { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
778  { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
779  { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
780  { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
781  { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
782  { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
783  { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGSR },
784  { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGSR },
785  { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGSR },
786  { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGSR },
787  { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
788  { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
789  { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
790  { NULL }
791 };
792 
793 AVFILTER_DEFINE_CLASS(oscilloscope);
794 
796 {
797  OscilloscopeContext *s = ctx->priv;
798 
799  av_freep(&s->values);
800 }
801 
802 static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1,
804 {
805  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
806  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
807  int err = (dx > dy ? dx : -dy) / 2, e2;
808  int p, i;
809 
810  for (;;) {
811  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
812  for (p = 0; p < draw->nb_planes; p++) {
813  if (draw->desc->comp[p].depth == 8) {
814  if (draw->nb_planes == 1) {
815  for (i = 0; i < draw->desc->nb_components; i++) {
816  out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i];
817  }
818  } else {
819  out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0];
820  }
821  } else {
822  if (draw->nb_planes == 1) {
823  for (i = 0; i < draw->desc->nb_components; i++) {
824  AV_WN16(out->data[0] + y0 * out->linesize[0] + (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]);
825  }
826  } else {
827  AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]);
828  }
829  }
830  }
831  }
832 
833  if (x0 == x1 && y0 == y1)
834  break;
835 
836  e2 = err;
837 
838  if (e2 >-dx) {
839  err -= dy;
840  x0 += sx;
841  }
842 
843  if (e2 < dy) {
844  err += dx;
845  y0 += sy;
846  }
847  }
848 }
849 
851 {
852  int i, c;
853 
854  for (i = 1; i < s->nb_values; i++) {
855  for (c = 0; c < s->nb_comps; c++) {
856  if ((1 << c) & s->components) {
857  int x = i * s->width / s->nb_values;
858  int px = (i - 1) * s->width / s->nb_values;
859  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256;
860  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256;
861 
862  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
863  }
864  }
865  }
866 }
867 
868 
870 {
871  int i, c;
872 
873  for (i = 1; i < s->nb_values; i++) {
874  for (c = 0; c < s->nb_comps; c++) {
875  if ((1 << c) & s->components) {
876  int x = i * s->width / s->nb_values;
877  int px = (i - 1) * s->width / s->nb_values;
878  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max;
879  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max;
880 
881  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
882  }
883  }
884  }
885 }
886 
888 {
889  OscilloscopeContext *s = ctx->priv;
890  AVFilterLink *inlink = ctx->inputs[0];
891  int cx, cy, size;
892  double tilt;
893 
894  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
895  s->height = s->theight * inlink->h;
896  s->width = s->twidth * inlink->w;
897  size = hypot(inlink->w, inlink->h);
898  size *= s->size;
899  tilt = (s->tilt - 0.5) * M_PI;
900  cx = s->xpos * (inlink->w - 1);
901  cy = s->ypos * (inlink->h - 1);
902  s->x1 = cx - size / 2.0 * cos(tilt);
903  s->x2 = cx + size / 2.0 * cos(tilt);
904  s->y1 = cy - size / 2.0 * sin(tilt);
905  s->y2 = cy + size / 2.0 * sin(tilt);
906  s->ox = (inlink->w - s->width) * s->tx;
907  s->oy = (inlink->h - s->height) * s->ty;
908 }
909 
911 {
912  OscilloscopeContext *s = inlink->dst->priv;
913  int size;
914 
916  ff_draw_init(&s->draw, inlink->format, 0);
917  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
918  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
919  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
920  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
921  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
922  ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} );
923  ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} );
924  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} );
925  s->nb_comps = s->draw.desc->nb_components;
927 
928  if (s->is_rgb) {
929  s->colors[0] = &s->red;
930  s->colors[1] = &s->green;
931  s->colors[2] = &s->blue;
932  s->colors[3] = &s->white;
933  ff_fill_rgba_map(s->rgba_map, inlink->format);
934  } else {
935  s->colors[0] = &s->white;
936  s->colors[1] = &s->cyan;
937  s->colors[2] = &s->magenta;
938  s->colors[3] = &s->white;
939  s->rgba_map[0] = 0;
940  s->rgba_map[1] = 1;
941  s->rgba_map[2] = 2;
942  s->rgba_map[3] = 3;
943  }
944 
945  if (s->draw.desc->comp[0].depth <= 8) {
946  s->pick_color = pick_color8;
947  s->draw_trace = draw_trace8;
948  } else {
951  }
952 
953  s->max = (1 << s->draw.desc->comp[0].depth);
954  size = hypot(inlink->w, inlink->h);
955 
956  s->values = av_calloc(size, sizeof(*s->values));
957  if (!s->values)
958  return AVERROR(ENOMEM);
959 
960  update_oscilloscope(inlink->dst);
961 
962  return 0;
963 }
964 
965 static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
966  AVFrame *out, PixelValues *p, int state)
967 {
968  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
969  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
970  int err = (dx > dy ? dx : -dy) / 2, e2;
971 
972  for (;;) {
973  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
974  FFDrawColor color = { { 0 } };
975  int value[4] = { 0 };
976 
977  s->pick_color(&s->draw, &color, out, x0, y0, value);
978  s->values[s->nb_values].p[0] = value[0];
979  s->values[s->nb_values].p[1] = value[1];
980  s->values[s->nb_values].p[2] = value[2];
981  s->values[s->nb_values].p[3] = value[3];
982  s->nb_values++;
983 
984  if (s->scope) {
985  if (s->draw.desc->comp[0].depth == 8) {
986  if (s->draw.nb_planes == 1) {
987  int i;
988 
989  for (i = 0; i < s->nb_comps; i++)
990  out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1);
991  } else {
992  out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1);
993  }
994  } else {
995  if (s->draw.nb_planes == 1) {
996  int i;
997 
998  for (i = 0; i < s->nb_comps; i++)
999  AV_WN16(out->data[0] + out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i, (s->max - 1) * ((s->nb_values + state) & 1));
1000  } else {
1001  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1));
1002  }
1003  }
1004  }
1005  }
1006 
1007  if (x0 == x1 && y0 == y1)
1008  break;
1009 
1010  e2 = err;
1011 
1012  if (e2 >-dx) {
1013  err -= dy;
1014  x0 += sx;
1015  }
1016 
1017  if (e2 < dy) {
1018  err += dx;
1019  y0 += sy;
1020  }
1021  }
1022 }
1023 
1025 {
1026  AVFilterContext *ctx = inlink->dst;
1027  OscilloscopeContext *s = ctx->priv;
1028  AVFilterLink *outlink = ctx->outputs[0];
1029  float average[4] = { 0 };
1030  int max[4] = { 0 };
1031  int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
1032  int i, c;
1033 
1034  s->nb_values = 0;
1035  draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
1036  ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
1037  frame->width, frame->height,
1038  s->ox, s->oy, s->width, s->height + 20 * s->statistics);
1039 
1040  if (s->grid && outlink->h >= 10) {
1041  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1042  s->ox, s->oy, s->width - 1, 1);
1043 
1044  for (i = 1; i < 5; i++) {
1045  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1046  s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1);
1047  }
1048 
1049  for (i = 0; i < 10; i++) {
1050  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1051  s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height);
1052  }
1053 
1054  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1055  s->ox + s->width - 1, s->oy, 1, s->height);
1056  }
1057 
1058  s->draw_trace(s, frame);
1059 
1060  for (i = 0; i < s->nb_values; i++) {
1061  for (c = 0; c < s->nb_comps; c++) {
1062  if ((1 << c) & s->components) {
1063  max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]);
1064  min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]);
1065  average[c] += s->values[i].p[s->rgba_map[c]];
1066  }
1067  }
1068  }
1069  for (c = 0; c < s->nb_comps; c++) {
1070  average[c] /= s->nb_values;
1071  }
1072 
1073  if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) {
1074  for (c = 0, i = 0; c < s->nb_comps; c++) {
1075  if ((1 << c) & s->components) {
1076  const char rgba[4] = { 'R', 'G', 'B', 'A' };
1077  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
1078  char text[128];
1079 
1080  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]);
1081  draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0);
1082  }
1083  }
1084  }
1085 
1086  return ff_filter_frame(outlink, frame);
1087 }
1088 
1089 static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1090  char *res, int res_len, int flags)
1091 {
1092  int ret;
1093 
1094  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1095  if (ret < 0)
1096  return ret;
1097 
1098  update_oscilloscope(ctx);
1099 
1100  return 0;
1101 }
1102 
1104  {
1105  .name = "default",
1106  .type = AVMEDIA_TYPE_VIDEO,
1107  .filter_frame = oscilloscope_filter_frame,
1108  .config_props = oscilloscope_config_input,
1109  .needs_writable = 1,
1110  },
1111  { NULL }
1112 };
1113 
1115  {
1116  .name = "default",
1117  .type = AVMEDIA_TYPE_VIDEO,
1118  },
1119  { NULL }
1120 };
1121 
1123  .name = "oscilloscope",
1124  .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."),
1125  .priv_size = sizeof(OscilloscopeContext),
1126  .priv_class = &oscilloscope_class,
1129  .inputs = oscilloscope_inputs,
1130  .outputs = oscilloscope_outputs,
1133 };
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:755
#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:483
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:771
static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:177
FFDrawColor magenta
Definition: vf_datascope.c:763
FFDrawColor * colors[4]
Definition: vf_datascope.c:765
Definition: vf_addroi.c:26
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:717
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:267
#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:469
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:774
#define OFFSET(x)
Definition: vf_datascope.c:57
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:127
uint8_t
static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:109
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
FFDrawColor gray
Definition: vf_datascope.c:50
void(* reverse_color)(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:53
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:224
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:770
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:478
static const AVFilterPad inputs[]
Definition: vf_datascope.c:422
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhqenc.c:54
#define max(a, b)
Definition: cuda_runtime.h:33
union FFDrawColor::@204 comp[MAX_PLANES]
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:61
#define POFFSET(x)
Definition: vf_datascope.c:481
static void draw_trace16(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:869
static void draw_trace8(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:850
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:115
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:157
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:474
static void oscilloscope_uninit(AVFilterContext *ctx)
Definition: vf_datascope.c:795
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
FFDrawContext draw
Definition: vf_datascope.c:46
static void update_oscilloscope(AVFilterContext *ctx)
Definition: vf_datascope.c:887
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:54
#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
uint8_t rgba_map[4]
Definition: vf_datascope.c:466
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:309
#define width
uint8_t w
Definition: llviddspenc.c:39
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:552
AVFormatContext * ctx
Definition: movenc.c:48
static int config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:380
static int query_formats(AVFilterContext *ctx)
Definition: vf_datascope.c:81
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:52
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:58
PixelValues * values
Definition: vf_datascope.c:768
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:432
FFDrawColor dark
Definition: vf_datascope.c:468
misc drawing utilities
static struct @320 state
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:776
static void draw_text(FFDrawContext *draw, AVFrame *frame, FFDrawColor *color, int x0, int y0, const uint8_t *text, int vertical)
Definition: vf_datascope.c:86
static const int16_t alpha[]
Definition: ilbcdata.h:55
FFDrawContext draw
Definition: vf_datascope.c:467
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:554
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:472
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:353
uint16_t p[4]
Definition: vf_datascope.c:729
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:381
#define FLAGSR
Definition: vf_datascope.c:59
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:965
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_adenorm.c:275
D(D(float, sse)
Definition: rematrix_init.c:28
FFDrawColor white
Definition: vf_datascope.c:48
static int config_output(AVFilterLink *outlink)
Definition: vf_datascope.c:411
static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
static int pixscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:496
avfilter_execute_func * execute
Definition: internal.h:136
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2033
FFDrawColor yellow
Definition: vf_datascope.c:47
uint16_t values[4][80][80]
Definition: vf_datascope.c:476
FFDrawColor black
Definition: vf_datascope.c:49
AVFilter ff_vf_datascope
Definition: vf_datascope.c:441
static const AVFilterPad pixscope_outputs[]
Definition: vf_datascope.c:709
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)
#define AV_WN16(p, v)
Definition: intreadwrite.h:372
#define M_PI
Definition: mathematics.h:52
FFDrawColor red
Definition: vf_datascope.c:473
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:802
internal API functions
static int oscilloscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:910
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
Definition: vf_addroi.c:26
FFDrawColor green
Definition: vf_datascope.c:471
float min
static const AVFilterPad pixscope_inputs[]
Definition: vf_datascope.c:699
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:145
uint8_t rgba[4]
Definition: drawutils.h:63
FFDrawColor white
Definition: vf_datascope.c:470