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, FLAGSR },
65  { "y", "set y offset", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGSR },
66  { "mode", "set scope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGSR, "mode" },
67  { "mono", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGSR, "mode" },
68  { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGSR, "mode" },
69  { "color2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGSR, "mode" },
70  { "axis", "draw column/row numbers", OFFSET(axis), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGSR },
71  { "opacity", "set background opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGSR },
72  { "format", "set display number format", OFFSET(dformat), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGSR, "format" },
73  { "hex", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGSR, "format" },
74  { "dec", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGSR, "format" },
75  { "components", "set components to display", OFFSET(components), AV_OPT_TYPE_INT, {.i64=15}, 1, 15, FLAGSR },
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 int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
423  char *res, int res_len, int flags)
424 {
425  int ret;
426 
427  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
428  if (ret < 0)
429  return ret;
430 
431  return config_input(ctx->inputs[0]);
432 }
433 
434 static const AVFilterPad inputs[] = {
435  {
436  .name = "default",
437  .type = AVMEDIA_TYPE_VIDEO,
438  .filter_frame = filter_frame,
439  .config_props = config_input,
440  },
441  { NULL }
442 };
443 
444 static const AVFilterPad outputs[] = {
445  {
446  .name = "default",
447  .type = AVMEDIA_TYPE_VIDEO,
448  .config_props = config_output,
449  },
450  { NULL }
451 };
452 
454  .name = "datascope",
455  .description = NULL_IF_CONFIG_SMALL("Video data analysis."),
456  .priv_size = sizeof(DatascopeContext),
457  .priv_class = &datascope_class,
459  .inputs = inputs,
460  .outputs = outputs,
463 };
464 
465 typedef struct PixscopeContext {
466  const AVClass *class;
467 
468  float xpos, ypos;
469  float wx, wy;
470  int w, h;
471  float o;
472 
473  int x, y;
474  int ww, wh;
475 
477  int nb_comps;
478  int is_rgb;
479  uint8_t rgba_map[4];
487  FFDrawColor *colors[4];
488 
489  uint16_t values[4][80][80];
490 
493 
494 #define POFFSET(x) offsetof(PixscopeContext, x)
495 
496 static const AVOption pixscope_options[] = {
497  { "x", "set scope x offset", POFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
498  { "y", "set scope y offset", POFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
499  { "w", "set scope width", POFFSET(w), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGSR },
500  { "h", "set scope height", POFFSET(h), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGSR },
501  { "o", "set window opacity", POFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
502  { "wx", "set window x offset", POFFSET(wx), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGSR },
503  { "wy", "set window y offset", POFFSET(wy), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGSR },
504  { NULL }
505 };
506 
507 AVFILTER_DEFINE_CLASS(pixscope);
508 
510 {
511  PixscopeContext *s = inlink->dst->priv;
512 
514  ff_draw_init(&s->draw, inlink->format, 0);
515  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
516  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
517  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
518  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
519  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
520  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
521  s->nb_comps = s->draw.desc->nb_components;
523 
524  if (s->is_rgb) {
525  s->colors[0] = &s->red;
526  s->colors[1] = &s->green;
527  s->colors[2] = &s->blue;
528  s->colors[3] = &s->white;
529  ff_fill_rgba_map(s->rgba_map, inlink->format);
530  } else {
531  s->colors[0] = &s->white;
532  s->colors[1] = &s->blue;
533  s->colors[2] = &s->red;
534  s->colors[3] = &s->white;
535  s->rgba_map[0] = 0;
536  s->rgba_map[1] = 1;
537  s->rgba_map[2] = 2;
538  s->rgba_map[3] = 3;
539  }
540 
541  if (s->draw.desc->comp[0].depth <= 8) {
542  s->pick_color = pick_color8;
543  } else {
545  }
546 
547  if (inlink->w < 640 || inlink->h < 480) {
548  av_log(inlink->dst, AV_LOG_ERROR, "min supported resolution is 640x480\n");
549  return AVERROR(EINVAL);
550  }
551 
552  s->ww = 300;
553  s->wh = 300 * 1.6;
554  s->x = s->xpos * (inlink->w - 1);
555  s->y = s->ypos * (inlink->h - 1);
556  if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) {
557  av_log(inlink->dst, AV_LOG_WARNING, "scope position is out of range, clipping\n");
558  s->x = FFMIN(s->x, inlink->w - s->w);
559  s->y = FFMIN(s->y, inlink->h - s->h);
560  }
561 
562  return 0;
563 }
564 
565 #define SQR(x) ((x)*(x))
566 
568 {
569  AVFilterContext *ctx = inlink->dst;
570  PixscopeContext *s = ctx->priv;
571  AVFilterLink *outlink = ctx->outputs[0];
572  AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
573  int max[4] = { 0 }, min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
574  float average[4] = { 0 };
575  double std[4] = { 0 }, rms[4] = { 0 };
576  const char rgba[4] = { 'R', 'G', 'B', 'A' };
577  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
578  int x, y, X, Y, i, w, h;
579  char text[128];
580 
581  if (!out) {
582  av_frame_free(&in);
583  return AVERROR(ENOMEM);
584  }
585  av_frame_copy_props(out, in);
586  av_frame_copy(out, in);
587 
588  w = s->ww / s->w;
589  h = s->ww / s->h;
590 
591  if (s->wx >= 0) {
592  X = (in->width - s->ww) * s->wx;
593  } else {
594  X = (in->width - s->ww) * -s->wx;
595  }
596  if (s->wy >= 0) {
597  Y = (in->height - s->wh) * s->wy;
598  } else {
599  Y = (in->height - s->wh) * -s->wy;
600  }
601 
602  if (s->wx < 0) {
603  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
604  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
605  X = (in->width - s->ww) * (1 + s->wx);
606  }
607  }
608 
609  if (s->wy < 0) {
610  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
611  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
612  Y = (in->height - s->wh) * (1 + s->wy);
613  }
614  }
615 
616  ff_blend_rectangle(&s->draw, &s->dark, out->data, out->linesize,
617  out->width, out->height,
618  X,
619  Y,
620  s->ww,
621  s->wh);
622 
623  for (y = 0; y < s->h; y++) {
624  for (x = 0; x < s->w; x++) {
625  FFDrawColor color = { { 0 } };
626  int value[4] = { 0 };
627 
628  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
629  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
630  x * w + (s->ww - 4 - (s->w * w)) / 2 + X, y * h + 2 + Y, w, h);
631  for (i = 0; i < 4; i++) {
632  s->values[i][x][y] = value[i];
633  rms[i] += (double)value[i] * (double)value[i];
634  average[i] += value[i];
635  min[i] = FFMIN(min[i], value[i]);
636  max[i] = FFMAX(max[i], value[i]);
637  }
638  }
639  }
640 
641  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
642  out->width, out->height,
643  s->x - 2, s->y - 2, s->w + 4, 1);
644 
645  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
646  out->width, out->height,
647  s->x - 1, s->y - 1, s->w + 2, 1);
648 
649  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
650  out->width, out->height,
651  s->x - 1, s->y - 1, 1, s->h + 2);
652 
653  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
654  out->width, out->height,
655  s->x - 2, s->y - 2, 1, s->h + 4);
656 
657  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
658  out->width, out->height,
659  s->x - 1, s->y + 1 + s->h, s->w + 3, 1);
660 
661  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
662  out->width, out->height,
663  s->x - 2, s->y + 2 + s->h, s->w + 4, 1);
664 
665  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
666  out->width, out->height,
667  s->x + 1 + s->w, s->y - 1, 1, s->h + 2);
668 
669  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
670  out->width, out->height,
671  s->x + 2 + s->w, s->y - 2, 1, s->h + 5);
672 
673  for (i = 0; i < 4; i++) {
674  rms[i] /= s->w * s->h;
675  rms[i] = sqrt(rms[i]);
676  average[i] /= s->w * s->h;
677  }
678 
679  for (y = 0; y < s->h; y++) {
680  for (x = 0; x < s->w; x++) {
681  for (i = 0; i < 4; i++)
682  std[i] += SQR(s->values[i][x][y] - average[i]);
683  }
684  }
685 
686  for (i = 0; i < 4; i++) {
687  std[i] /= s->w * s->h;
688  std[i] = sqrt(std[i]);
689  }
690 
691  snprintf(text, sizeof(text), "CH AVG MIN MAX RMS\n");
692  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 5, text, 0);
693  for (i = 0; i < s->nb_comps; i++) {
694  int c = s->rgba_map[i];
695 
696  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]);
697  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 1), text, 0);
698  }
699  snprintf(text, sizeof(text), "CH STD\n");
700  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 15 * (0 + 5), text, 0);
701  for (i = 0; i < s->nb_comps; i++) {
702  int c = s->rgba_map[i];
703 
704  snprintf(text, sizeof(text), "%c %07.2f\n", s->is_rgb ? rgba[i] : yuva[i], std[c]);
705  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 15 * (i + 6), text, 0);
706  }
707 
708  av_frame_free(&in);
709  return ff_filter_frame(outlink, out);
710 }
711 
712 static int pixscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
713  char *res, int res_len, int flags)
714 {
715  int ret;
716 
717  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
718  if (ret < 0)
719  return ret;
720 
721  return pixscope_config_input(ctx->inputs[0]);
722 }
723 
724 static const AVFilterPad pixscope_inputs[] = {
725  {
726  .name = "default",
727  .type = AVMEDIA_TYPE_VIDEO,
728  .filter_frame = pixscope_filter_frame,
729  .config_props = pixscope_config_input,
730  },
731  { NULL }
732 };
733 
734 static const AVFilterPad pixscope_outputs[] = {
735  {
736  .name = "default",
737  .type = AVMEDIA_TYPE_VIDEO,
738  },
739  { NULL }
740 };
741 
743  .name = "pixscope",
744  .description = NULL_IF_CONFIG_SMALL("Pixel data analysis."),
745  .priv_size = sizeof(PixscopeContext),
746  .priv_class = &pixscope_class,
748  .inputs = pixscope_inputs,
749  .outputs = pixscope_outputs,
752 };
753 
754 typedef struct PixelValues {
755  uint16_t p[4];
756 } PixelValues;
757 
758 typedef struct OscilloscopeContext {
759  const AVClass *class;
760 
761  float xpos, ypos;
762  float tx, ty;
763  float size;
764  float tilt;
765  float theight, twidth;
766  float o;
768  int grid;
770  int scope;
771 
772  int x1, y1, x2, y2;
773  int ox, oy;
774  int height, width;
775 
776  int max;
778  int nb_comps;
779  int is_rgb;
780  uint8_t rgba_map[4];
791  FFDrawColor *colors[4];
792 
795 
797  void (*draw_trace)(struct OscilloscopeContext *s, AVFrame *frame);
799 
800 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
801 
802 static const AVOption oscilloscope_options[] = {
803  { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
804  { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
805  { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
806  { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
807  { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGSR },
808  { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGSR },
809  { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGSR },
810  { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGSR },
811  { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGSR },
812  { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGSR },
813  { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
814  { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
815  { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGSR },
816  { NULL }
817 };
818 
819 AVFILTER_DEFINE_CLASS(oscilloscope);
820 
822 {
823  OscilloscopeContext *s = ctx->priv;
824 
825  av_freep(&s->values);
826 }
827 
828 static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1,
830 {
831  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
832  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
833  int err = (dx > dy ? dx : -dy) / 2, e2;
834  int p, i;
835 
836  for (;;) {
837  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
838  for (p = 0; p < draw->nb_planes; p++) {
839  if (draw->desc->comp[p].depth == 8) {
840  if (draw->nb_planes == 1) {
841  for (i = 0; i < draw->desc->nb_components; i++) {
842  out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i];
843  }
844  } else {
845  out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0];
846  }
847  } else {
848  if (draw->nb_planes == 1) {
849  for (i = 0; i < draw->desc->nb_components; i++) {
850  AV_WN16(out->data[0] + y0 * out->linesize[0] + (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]);
851  }
852  } else {
853  AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]);
854  }
855  }
856  }
857  }
858 
859  if (x0 == x1 && y0 == y1)
860  break;
861 
862  e2 = err;
863 
864  if (e2 >-dx) {
865  err -= dy;
866  x0 += sx;
867  }
868 
869  if (e2 < dy) {
870  err += dx;
871  y0 += sy;
872  }
873  }
874 }
875 
877 {
878  int i, c;
879 
880  for (i = 1; i < s->nb_values; i++) {
881  for (c = 0; c < s->nb_comps; c++) {
882  if ((1 << c) & s->components) {
883  int x = i * s->width / s->nb_values;
884  int px = (i - 1) * s->width / s->nb_values;
885  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256;
886  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256;
887 
888  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
889  }
890  }
891  }
892 }
893 
894 
896 {
897  int i, c;
898 
899  for (i = 1; i < s->nb_values; i++) {
900  for (c = 0; c < s->nb_comps; c++) {
901  if ((1 << c) & s->components) {
902  int x = i * s->width / s->nb_values;
903  int px = (i - 1) * s->width / s->nb_values;
904  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max;
905  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max;
906 
907  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
908  }
909  }
910  }
911 }
912 
914 {
915  OscilloscopeContext *s = ctx->priv;
916  AVFilterLink *inlink = ctx->inputs[0];
917  int cx, cy, size;
918  double tilt;
919 
920  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
921  s->height = s->theight * inlink->h;
922  s->width = s->twidth * inlink->w;
923  size = hypot(inlink->w, inlink->h);
924  size *= s->size;
925  tilt = (s->tilt - 0.5) * M_PI;
926  cx = s->xpos * (inlink->w - 1);
927  cy = s->ypos * (inlink->h - 1);
928  s->x1 = cx - size / 2.0 * cos(tilt);
929  s->x2 = cx + size / 2.0 * cos(tilt);
930  s->y1 = cy - size / 2.0 * sin(tilt);
931  s->y2 = cy + size / 2.0 * sin(tilt);
932  s->ox = (inlink->w - s->width) * s->tx;
933  s->oy = (inlink->h - s->height) * s->ty;
934 }
935 
937 {
938  OscilloscopeContext *s = inlink->dst->priv;
939  int size;
940 
942  ff_draw_init(&s->draw, inlink->format, 0);
943  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
944  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
945  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
946  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
947  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
948  ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} );
949  ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} );
950  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} );
951  s->nb_comps = s->draw.desc->nb_components;
953 
954  if (s->is_rgb) {
955  s->colors[0] = &s->red;
956  s->colors[1] = &s->green;
957  s->colors[2] = &s->blue;
958  s->colors[3] = &s->white;
959  ff_fill_rgba_map(s->rgba_map, inlink->format);
960  } else {
961  s->colors[0] = &s->white;
962  s->colors[1] = &s->cyan;
963  s->colors[2] = &s->magenta;
964  s->colors[3] = &s->white;
965  s->rgba_map[0] = 0;
966  s->rgba_map[1] = 1;
967  s->rgba_map[2] = 2;
968  s->rgba_map[3] = 3;
969  }
970 
971  if (s->draw.desc->comp[0].depth <= 8) {
972  s->pick_color = pick_color8;
973  s->draw_trace = draw_trace8;
974  } else {
977  }
978 
979  s->max = (1 << s->draw.desc->comp[0].depth);
980  size = hypot(inlink->w, inlink->h);
981 
982  s->values = av_calloc(size, sizeof(*s->values));
983  if (!s->values)
984  return AVERROR(ENOMEM);
985 
986  update_oscilloscope(inlink->dst);
987 
988  return 0;
989 }
990 
991 static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
992  AVFrame *out, PixelValues *p, int state)
993 {
994  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
995  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
996  int err = (dx > dy ? dx : -dy) / 2, e2;
997 
998  for (;;) {
999  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
1000  FFDrawColor color = { { 0 } };
1001  int value[4] = { 0 };
1002 
1003  s->pick_color(&s->draw, &color, out, x0, y0, value);
1004  s->values[s->nb_values].p[0] = value[0];
1005  s->values[s->nb_values].p[1] = value[1];
1006  s->values[s->nb_values].p[2] = value[2];
1007  s->values[s->nb_values].p[3] = value[3];
1008  s->nb_values++;
1009 
1010  if (s->scope) {
1011  if (s->draw.desc->comp[0].depth == 8) {
1012  if (s->draw.nb_planes == 1) {
1013  int i;
1014 
1015  for (i = 0; i < s->nb_comps; i++)
1016  out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1);
1017  } else {
1018  out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1);
1019  }
1020  } else {
1021  if (s->draw.nb_planes == 1) {
1022  int i;
1023 
1024  for (i = 0; i < s->nb_comps; i++)
1025  AV_WN16(out->data[0] + out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i, (s->max - 1) * ((s->nb_values + state) & 1));
1026  } else {
1027  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1));
1028  }
1029  }
1030  }
1031  }
1032 
1033  if (x0 == x1 && y0 == y1)
1034  break;
1035 
1036  e2 = err;
1037 
1038  if (e2 >-dx) {
1039  err -= dy;
1040  x0 += sx;
1041  }
1042 
1043  if (e2 < dy) {
1044  err += dx;
1045  y0 += sy;
1046  }
1047  }
1048 }
1049 
1051 {
1052  AVFilterContext *ctx = inlink->dst;
1053  OscilloscopeContext *s = ctx->priv;
1054  AVFilterLink *outlink = ctx->outputs[0];
1055  float average[4] = { 0 };
1056  int max[4] = { 0 };
1057  int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
1058  int i, c;
1059 
1060  s->nb_values = 0;
1061  draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
1062  ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
1063  frame->width, frame->height,
1064  s->ox, s->oy, s->width, s->height + 20 * s->statistics);
1065 
1066  if (s->grid && outlink->h >= 10) {
1067  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1068  s->ox, s->oy, s->width - 1, 1);
1069 
1070  for (i = 1; i < 5; i++) {
1071  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1072  s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1);
1073  }
1074 
1075  for (i = 0; i < 10; i++) {
1076  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1077  s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height);
1078  }
1079 
1080  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
1081  s->ox + s->width - 1, s->oy, 1, s->height);
1082  }
1083 
1084  s->draw_trace(s, frame);
1085 
1086  for (i = 0; i < s->nb_values; i++) {
1087  for (c = 0; c < s->nb_comps; c++) {
1088  if ((1 << c) & s->components) {
1089  max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]);
1090  min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]);
1091  average[c] += s->values[i].p[s->rgba_map[c]];
1092  }
1093  }
1094  }
1095  for (c = 0; c < s->nb_comps; c++) {
1096  average[c] /= s->nb_values;
1097  }
1098 
1099  if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) {
1100  for (c = 0, i = 0; c < s->nb_comps; c++) {
1101  if ((1 << c) & s->components) {
1102  const char rgba[4] = { 'R', 'G', 'B', 'A' };
1103  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
1104  char text[128];
1105 
1106  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]);
1107  draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0);
1108  }
1109  }
1110  }
1111 
1112  return ff_filter_frame(outlink, frame);
1113 }
1114 
1115 static int oscilloscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1116  char *res, int res_len, int flags)
1117 {
1118  int ret;
1119 
1120  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1121  if (ret < 0)
1122  return ret;
1123 
1124  update_oscilloscope(ctx);
1125 
1126  return 0;
1127 }
1128 
1130  {
1131  .name = "default",
1132  .type = AVMEDIA_TYPE_VIDEO,
1133  .filter_frame = oscilloscope_filter_frame,
1134  .config_props = oscilloscope_config_input,
1135  .needs_writable = 1,
1136  },
1137  { NULL }
1138 };
1139 
1141  {
1142  .name = "default",
1143  .type = AVMEDIA_TYPE_VIDEO,
1144  },
1145  { NULL }
1146 };
1147 
1149  .name = "oscilloscope",
1150  .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."),
1151  .priv_size = sizeof(OscilloscopeContext),
1152  .priv_class = &oscilloscope_class,
1155  .inputs = oscilloscope_inputs,
1156  .outputs = oscilloscope_outputs,
1159 };
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:637
static int pixscope_process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_datascope.c:712
#define NULL
Definition: coverity.c:32
FFDrawContext draw
Definition: vf_datascope.c:781
#define P
AVFrame * out
Definition: af_adeclick.c:502
This structure describes decoded (raw) audio or video data.
Definition: frame.h:314
static const AVOption pixscope_options[]
Definition: vf_datascope.c:496
AVOption.
Definition: opt.h:248
uint16_t u16[8]
Definition: drawutils.h:53
uint8_t hsub[MAX_PLANES]
Definition: drawutils.h:41
#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:797
static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:177
FFDrawColor magenta
Definition: vf_datascope.c:789
FFDrawColor * colors[4]
Definition: vf_datascope.c:791
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:742
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:482
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:1093
#define OOFFSET(x)
Definition: vf_datascope.c:800
#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:796
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:491
static const AVFilterPad inputs[]
Definition: vf_datascope.c:434
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhqenc.c:51
#define max(a, b)
Definition: cuda_runtime.h:33
union FFDrawColor::@204 comp[MAX_PLANES]
ptrdiff_t size
Definition: opengl_enc.c:100
static struct @321 state
#define av_log(a,...)
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_datascope.c:422
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:494
static void draw_trace16(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:895
static void draw_trace8(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:876
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:881
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:137
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:103
uint8_t u8[16]
Definition: drawutils.h:54
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:487
static void oscilloscope_uninit(AVFilterContext *ctx)
Definition: vf_datascope.c:821
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:913
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:801
#define FFMIN(a, b)
Definition: common.h:105
uint8_t rgba_map[4]
Definition: vf_datascope.c:479
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:565
AVFormatContext * ctx
Definition: movenc.c:48
static int config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:380
#define av_popcount
Definition: common.h:176
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:794
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:528
static const AVFilterPad outputs[]
Definition: vf_datascope.c:444
FFDrawColor dark
Definition: vf_datascope.c:481
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:38
static const AVOption oscilloscope_options[]
Definition: vf_datascope.c:802
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:480
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:567
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:351
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:84
#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:485
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:353
uint16_t p[4]
Definition: vf_datascope.c:755
#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:991
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:509
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:489
FFDrawColor black
Definition: vf_datascope.c:49
AVFilter ff_vf_datascope
Definition: vf_datascope.c:453
static const AVFilterPad pixscope_outputs[]
Definition: vf_datascope.c:734
int pixelstep[MAX_PLANES]
Definition: drawutils.h:39
#define H
Definition: pixlet.c:39
const struct AVPixFmtDescriptor * desc
Definition: drawutils.h:36
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:224
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:42
#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:486
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:828
internal API functions
static int oscilloscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:936
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:484
float min
static const AVFilterPad pixscope_inputs[]
Definition: vf_datascope.c:724
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:50
FFDrawColor white
Definition: vf_datascope.c:483