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 axis;
39  float opacity;
40 
41  int nb_planes;
42  int nb_comps;
43  int chars;
49 
52  int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
54 
55 #define OFFSET(x) offsetof(DatascopeContext, x)
56 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
57 
58 static const AVOption datascope_options[] = {
59  { "size", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
60  { "s", "set output size", OFFSET(ow), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS },
61  { "x", "set x offset", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
62  { "y", "set y offset", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
63  { "mode", "set scope mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mode" },
64  { "mono", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
65  { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
66  { "color2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mode" },
67  { "axis", "draw column/row numbers", OFFSET(axis), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
68  { "opacity", "set background opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
69  { NULL }
70 };
71 
72 AVFILTER_DEFINE_CLASS(datascope);
73 
75 {
77 }
78 
80  int x0, int y0, const uint8_t *text, int vertical)
81 {
82  int x = x0;
83 
84  for (; *text; text++) {
85  if (*text == '\n') {
86  x = x0;
87  y0 += 8;
88  continue;
89  }
90  ff_blend_mask(draw, color, frame->data, frame->linesize,
91  frame->width, frame->height,
92  avpriv_cga_font + *text * 8, 1, 8, 8, 0, 0, x, y0);
93  if (vertical) {
94  x = x0;
95  y0 += 8;
96  } else {
97  x += 8;
98  }
99  }
100 }
101 
102 static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
103 {
104  int p, i;
105 
106  color->rgba[3] = 255;
107  for (p = 0; p < draw->nb_planes; p++) {
108  if (draw->nb_planes == 1) {
109  for (i = 0; i < 4; i++) {
110  value[i] = in->data[0][y * in->linesize[0] + x * draw->pixelstep[0] + i];
111  color->comp[0].u8[i] = value[i];
112  }
113  } else {
114  value[p] = in->data[p][(y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p])];
115  color->comp[p].u8[0] = value[p];
116  }
117  }
118 }
119 
120 static void pick_color16(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
121 {
122  int p, i;
123 
124  color->rgba[3] = 255;
125  for (p = 0; p < draw->nb_planes; p++) {
126  if (draw->nb_planes == 1) {
127  for (i = 0; i < 4; i++) {
128  value[i] = AV_RL16(in->data[0] + y * in->linesize[0] + x * draw->pixelstep[0] + i * 2);
129  color->comp[0].u16[i] = value[i];
130  }
131  } else {
132  value[p] = AV_RL16(in->data[p] + (y >> draw->vsub[p]) * in->linesize[p] + (x >> draw->hsub[p]) * 2);
133  color->comp[p].u16[0] = value[p];
134  }
135  }
136 }
137 
139 {
140  int p;
141 
142  reverse->rgba[3] = 255;
143  for (p = 0; p < draw->nb_planes; p++) {
144  reverse->comp[p].u8[0] = color->comp[p].u8[0] > 127 ? 0 : 255;
145  reverse->comp[p].u8[1] = color->comp[p].u8[1] > 127 ? 0 : 255;
146  reverse->comp[p].u8[2] = color->comp[p].u8[2] > 127 ? 0 : 255;
147  }
148 }
149 
151 {
152  int p;
153 
154  reverse->rgba[3] = 255;
155  for (p = 0; p < draw->nb_planes; p++) {
156  const unsigned max = (1 << draw->desc->comp[p].depth) - 1;
157  const unsigned mid = (max + 1) / 2;
158 
159  reverse->comp[p].u16[0] = color->comp[p].u16[0] > mid ? 0 : max;
160  reverse->comp[p].u16[1] = color->comp[p].u16[1] > mid ? 0 : max;
161  reverse->comp[p].u16[2] = color->comp[p].u16[2] > mid ? 0 : max;
162  }
163 }
164 
165 typedef struct ThreadData {
166  AVFrame *in, *out;
167  int xoff, yoff;
168 } ThreadData;
169 
170 static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
171 {
172  DatascopeContext *s = ctx->priv;
173  AVFilterLink *outlink = ctx->outputs[0];
174  AVFilterLink *inlink = ctx->inputs[0];
175  ThreadData *td = arg;
176  AVFrame *in = td->in;
177  AVFrame *out = td->out;
178  const int xoff = td->xoff;
179  const int yoff = td->yoff;
180  const int P = FFMAX(s->nb_planes, s->nb_comps);
181  const int C = s->chars;
182  const int W = (outlink->w - xoff) / (C * 10);
183  const int H = (outlink->h - yoff) / (P * 12);
184  const char *format[2] = {"%02X\n", "%04X\n"};
185  const int slice_start = (W * jobnr) / nb_jobs;
186  const int slice_end = (W * (jobnr+1)) / nb_jobs;
187  int x, y, p;
188 
189  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
190  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
191  FFDrawColor color = { { 0 } };
192  FFDrawColor reverse = { { 0 } };
193  int value[4] = { 0 };
194 
195  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
196  s->reverse_color(&s->draw, &color, &reverse);
197  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
198  xoff + x * C * 10, yoff + y * P * 12, C * 10, P * 12);
199 
200  for (p = 0; p < P; p++) {
201  char text[256];
202 
203  snprintf(text, sizeof(text), format[C>>2], value[p]);
204  draw_text(&s->draw, out, &reverse, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
205  }
206  }
207  }
208 
209  return 0;
210 }
211 
212 static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
213 {
214  DatascopeContext *s = ctx->priv;
215  AVFilterLink *outlink = ctx->outputs[0];
216  AVFilterLink *inlink = ctx->inputs[0];
217  ThreadData *td = arg;
218  AVFrame *in = td->in;
219  AVFrame *out = td->out;
220  const int xoff = td->xoff;
221  const int yoff = td->yoff;
222  const int P = FFMAX(s->nb_planes, s->nb_comps);
223  const int C = s->chars;
224  const int W = (outlink->w - xoff) / (C * 10);
225  const int H = (outlink->h - yoff) / (P * 12);
226  const char *format[2] = {"%02X\n", "%04X\n"};
227  const int slice_start = (W * jobnr) / nb_jobs;
228  const int slice_end = (W * (jobnr+1)) / nb_jobs;
229  int x, y, p;
230 
231  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
232  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
233  FFDrawColor color = { { 0 } };
234  int value[4] = { 0 };
235 
236  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
237 
238  for (p = 0; p < P; p++) {
239  char text[256];
240 
241  snprintf(text, sizeof(text), format[C>>2], value[p]);
242  draw_text(&s->draw, out, &color, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
243  }
244  }
245  }
246 
247  return 0;
248 }
249 
250 static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
251 {
252  DatascopeContext *s = ctx->priv;
253  AVFilterLink *outlink = ctx->outputs[0];
254  AVFilterLink *inlink = ctx->inputs[0];
255  ThreadData *td = arg;
256  AVFrame *in = td->in;
257  AVFrame *out = td->out;
258  const int xoff = td->xoff;
259  const int yoff = td->yoff;
260  const int P = FFMAX(s->nb_planes, s->nb_comps);
261  const int C = s->chars;
262  const int W = (outlink->w - xoff) / (C * 10);
263  const int H = (outlink->h - yoff) / (P * 12);
264  const char *format[2] = {"%02X\n", "%04X\n"};
265  const int slice_start = (W * jobnr) / nb_jobs;
266  const int slice_end = (W * (jobnr+1)) / nb_jobs;
267  int x, y, p;
268 
269  for (y = 0; y < H && (y + s->y < inlink->h); y++) {
270  for (x = slice_start; x < slice_end && (x + s->x < inlink->w); x++) {
271  FFDrawColor color = { { 0 } };
272  int value[4] = { 0 };
273 
274  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
275  for (p = 0; p < P; p++) {
276  char text[256];
277 
278  snprintf(text, sizeof(text), format[C>>2], value[p]);
279  draw_text(&s->draw, out, &s->white, xoff + x * C * 10 + 2, yoff + y * P * 12 + p * 10 + 2, text, 0);
280  }
281  }
282  }
283 
284  return 0;
285 }
286 
288 {
289  AVFilterContext *ctx = inlink->dst;
290  DatascopeContext *s = ctx->priv;
291  AVFilterLink *outlink = ctx->outputs[0];
292  ThreadData td = { 0 };
293  int ymaxlen = 0;
294  int xmaxlen = 0;
295  AVFrame *out;
296 
297  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
298  if (!out) {
299  av_frame_free(&in);
300  return AVERROR(ENOMEM);
301  }
302  out->pts = in->pts;
303 
304  ff_fill_rectangle(&s->draw, &s->black, out->data, out->linesize,
305  0, 0, outlink->w, outlink->h);
306 
307  if (s->axis) {
308  const int P = FFMAX(s->nb_planes, s->nb_comps);
309  const int C = s->chars;
310  int Y = outlink->h / (P * 12);
311  int X = outlink->w / (C * 10);
312  char text[256] = { 0 };
313  int x, y;
314 
315  snprintf(text, sizeof(text), "%d", s->y + Y);
316  ymaxlen = strlen(text);
317  ymaxlen *= 10;
318  snprintf(text, sizeof(text), "%d", s->x + X);
319  xmaxlen = strlen(text);
320  xmaxlen *= 10;
321 
322  Y = (outlink->h - xmaxlen) / (P * 12);
323  X = (outlink->w - ymaxlen) / (C * 10);
324 
325  for (y = 0; y < Y; y++) {
326  snprintf(text, sizeof(text), "%d", s->y + y);
327 
328  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
329  0, xmaxlen + y * P * 12 + (P + 1) * P - 2, ymaxlen, 10);
330 
331  draw_text(&s->draw, out, &s->yellow, 2, xmaxlen + y * P * 12 + (P + 1) * P, text, 0);
332  }
333 
334  for (x = 0; x < X; x++) {
335  snprintf(text, sizeof(text), "%d", s->x + x);
336 
337  ff_fill_rectangle(&s->draw, &s->gray, out->data, out->linesize,
338  ymaxlen + x * C * 10 + 2 * C - 2, 0, 10, xmaxlen);
339 
340  draw_text(&s->draw, out, &s->yellow, ymaxlen + x * C * 10 + 2 * C, 2, text, 1);
341  }
342  }
343 
344  td.in = in; td.out = out, td.yoff = xmaxlen, td.xoff = ymaxlen;
345  ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN(ff_filter_get_nb_threads(ctx), FFMAX(outlink->w / 20, 1)));
346 
347  av_frame_free(&in);
348  return ff_filter_frame(outlink, out);
349 }
350 
352 {
353  DatascopeContext *s = inlink->dst->priv;
354  uint8_t alpha = s->opacity * 255;
355 
357  ff_draw_init(&s->draw, inlink->format, 0);
358  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
359  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, alpha} );
360  ff_draw_color(&s->draw, &s->yellow, (uint8_t[]){ 255, 255, 0, 255} );
361  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 77, 77, 77, 255} );
362  s->chars = (s->draw.desc->comp[0].depth + 7) / 8 * 2;
363  s->nb_comps = s->draw.desc->nb_components;
364 
365  switch (s->mode) {
366  case 0: s->filter = filter_mono; break;
367  case 1: s->filter = filter_color; break;
368  case 2: s->filter = filter_color2; break;
369  }
370 
371  if (s->draw.desc->comp[0].depth <= 8) {
372  s->pick_color = pick_color8;
374  } else {
377  }
378 
379  return 0;
380 }
381 
382 static int config_output(AVFilterLink *outlink)
383 {
384  DatascopeContext *s = outlink->src->priv;
385 
386  outlink->h = s->oh;
387  outlink->w = s->ow;
388  outlink->sample_aspect_ratio = (AVRational){1,1};
389 
390  return 0;
391 }
392 
393 static const AVFilterPad inputs[] = {
394  {
395  .name = "default",
396  .type = AVMEDIA_TYPE_VIDEO,
397  .filter_frame = filter_frame,
398  .config_props = config_input,
399  },
400  { NULL }
401 };
402 
403 static const AVFilterPad outputs[] = {
404  {
405  .name = "default",
406  .type = AVMEDIA_TYPE_VIDEO,
407  .config_props = config_output,
408  },
409  { NULL }
410 };
411 
413  .name = "datascope",
414  .description = NULL_IF_CONFIG_SMALL("Video data analysis."),
415  .priv_size = sizeof(DatascopeContext),
416  .priv_class = &datascope_class,
418  .inputs = inputs,
419  .outputs = outputs,
421 };
422 
423 typedef struct PixscopeContext {
424  const AVClass *class;
425 
426  float xpos, ypos;
427  float wx, wy;
428  int w, h;
429  float o;
430 
431  int x, y;
432  int ww, wh;
433 
435  int nb_comps;
436  int is_rgb;
437  uint8_t rgba_map[4];
445  FFDrawColor *colors[4];
446 
449 
450 #define POFFSET(x) offsetof(PixscopeContext, x)
451 
452 static const AVOption pixscope_options[] = {
453  { "x", "set scope x offset", POFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
454  { "y", "set scope y offset", POFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
455  { "w", "set scope width", POFFSET(w), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
456  { "h", "set scope height", POFFSET(h), AV_OPT_TYPE_INT, {.i64=7}, 1, 80, FLAGS },
457  { "o", "set window opacity", POFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
458  { "wx", "set window x offset", POFFSET(wx), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
459  { "wy", "set window y offset", POFFSET(wy), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 1, FLAGS },
460  { NULL }
461 };
462 
463 AVFILTER_DEFINE_CLASS(pixscope);
464 
466 {
467  PixscopeContext *s = inlink->dst->priv;
468 
470  ff_draw_init(&s->draw, inlink->format, 0);
471  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
472  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
473  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
474  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
475  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
476  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
477  s->nb_comps = s->draw.desc->nb_components;
479 
480  if (s->is_rgb) {
481  s->colors[0] = &s->red;
482  s->colors[1] = &s->green;
483  s->colors[2] = &s->blue;
484  s->colors[3] = &s->white;
485  ff_fill_rgba_map(s->rgba_map, inlink->format);
486  } else {
487  s->colors[0] = &s->white;
488  s->colors[1] = &s->blue;
489  s->colors[2] = &s->red;
490  s->colors[3] = &s->white;
491  s->rgba_map[0] = 0;
492  s->rgba_map[1] = 1;
493  s->rgba_map[2] = 2;
494  s->rgba_map[3] = 3;
495  }
496 
497  if (s->draw.desc->comp[0].depth <= 8) {
498  s->pick_color = pick_color8;
499  } else {
501  }
502 
503  if (inlink->w < 640 || inlink->h < 480) {
504  av_log(inlink->dst, AV_LOG_ERROR, "min supported resolution is 640x480\n");
505  return AVERROR(EINVAL);
506  }
507 
508  s->ww = 300;
509  s->wh = 300 * 1.6;
510  s->x = s->xpos * (inlink->w - 1);
511  s->y = s->ypos * (inlink->h - 1);
512  if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) {
513  av_log(inlink->dst, AV_LOG_WARNING, "scope position is out of range, clipping\n");
514  s->x = FFMIN(s->x, inlink->w - s->w);
515  s->y = FFMIN(s->y, inlink->h - s->h);
516  }
517 
518  return 0;
519 }
520 
522 {
523  AVFilterContext *ctx = inlink->dst;
524  PixscopeContext *s = ctx->priv;
525  AVFilterLink *outlink = ctx->outputs[0];
526  AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
527  int max[4] = { 0 }, min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
528  float average[4] = { 0 };
529  double rms[4] = { 0 };
530  const char rgba[4] = { 'R', 'G', 'B', 'A' };
531  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
532  int x, y, X, Y, i, w, h;
533  char text[128];
534 
535  if (!out) {
536  av_frame_free(&in);
537  return AVERROR(ENOMEM);
538  }
539  av_frame_copy_props(out, in);
540  av_frame_copy(out, in);
541 
542  w = s->ww / s->w;
543  h = s->ww / s->h;
544 
545  if (s->wx >= 0) {
546  X = (in->width - s->ww) * s->wx;
547  } else {
548  X = (in->width - s->ww) * -s->wx;
549  }
550  if (s->wy >= 0) {
551  Y = (in->height - s->wh) * s->wy;
552  } else {
553  Y = (in->height - s->wh) * -s->wy;
554  }
555 
556  if (s->wx < 0) {
557  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
558  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
559  X = (in->width - s->ww) * (1 + s->wx);
560  }
561  }
562 
563  if (s->wy < 0) {
564  if (s->x + s->w >= X && (s->x + s->w <= X + s->ww) &&
565  s->y + s->h >= Y && (s->y + s->h <= Y + s->wh)) {
566  Y = (in->height - s->wh) * (1 + s->wy);
567  }
568  }
569 
570  ff_blend_rectangle(&s->draw, &s->dark, out->data, out->linesize,
571  out->width, out->height,
572  X,
573  Y,
574  s->ww,
575  s->wh);
576 
577  for (y = 0; y < s->h; y++) {
578  for (x = 0; x < s->w; x++) {
579  FFDrawColor color = { { 0 } };
580  int value[4] = { 0 };
581 
582  s->pick_color(&s->draw, &color, in, x + s->x, y + s->y, value);
583  ff_fill_rectangle(&s->draw, &color, out->data, out->linesize,
584  x * w + (s->ww - 4 - (s->w * w)) / 2 + X, y * h + 2 + Y, w, h);
585  for (i = 0; i < 4; i++) {
586  rms[i] += (double)value[i] * (double)value[i];
587  average[i] += value[i];
588  min[i] = FFMIN(min[i], value[i]);
589  max[i] = FFMAX(max[i], value[i]);
590  }
591  }
592  }
593 
594  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
595  out->width, out->height,
596  s->x - 2, s->y - 2, s->w + 4, 1);
597 
598  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
599  out->width, out->height,
600  s->x - 1, s->y - 1, s->w + 2, 1);
601 
602  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
603  out->width, out->height,
604  s->x - 1, s->y - 1, 1, s->h + 2);
605 
606  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
607  out->width, out->height,
608  s->x - 2, s->y - 2, 1, s->h + 4);
609 
610  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
611  out->width, out->height,
612  s->x - 1, s->y + 1 + s->h, s->w + 3, 1);
613 
614  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
615  out->width, out->height,
616  s->x - 2, s->y + 2 + s->h, s->w + 4, 1);
617 
618  ff_blend_rectangle(&s->draw, &s->white, out->data, out->linesize,
619  out->width, out->height,
620  s->x + 1 + s->w, s->y - 1, 1, s->h + 2);
621 
622  ff_blend_rectangle(&s->draw, &s->black, out->data, out->linesize,
623  out->width, out->height,
624  s->x + 2 + s->w, s->y - 2, 1, s->h + 5);
625 
626  for (i = 0; i < 4; i++) {
627  rms[i] /= s->w * s->h;
628  rms[i] = sqrt(rms[i]);
629  average[i] /= s->w * s->h;
630  }
631 
632  snprintf(text, sizeof(text), "CH AVG MIN MAX RMS\n");
633  draw_text(&s->draw, out, &s->white, X + 28, Y + s->ww + 20, text, 0);
634  for (i = 0; i < s->nb_comps; i++) {
635  int c = s->rgba_map[i];
636 
637  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]);
638  draw_text(&s->draw, out, s->colors[i], X + 28, Y + s->ww + 20 * (i + 2), text, 0);
639  }
640 
641  av_frame_free(&in);
642  return ff_filter_frame(outlink, out);
643 }
644 
645 static const AVFilterPad pixscope_inputs[] = {
646  {
647  .name = "default",
648  .type = AVMEDIA_TYPE_VIDEO,
649  .filter_frame = pixscope_filter_frame,
650  .config_props = pixscope_config_input,
651  },
652  { NULL }
653 };
654 
655 static const AVFilterPad pixscope_outputs[] = {
656  {
657  .name = "default",
658  .type = AVMEDIA_TYPE_VIDEO,
659  },
660  { NULL }
661 };
662 
664  .name = "pixscope",
665  .description = NULL_IF_CONFIG_SMALL("Pixel data analysis."),
666  .priv_size = sizeof(PixscopeContext),
667  .priv_class = &pixscope_class,
669  .inputs = pixscope_inputs,
670  .outputs = pixscope_outputs,
672 };
673 
674 typedef struct PixelValues {
675  uint16_t p[4];
676 } PixelValues;
677 
678 typedef struct OscilloscopeContext {
679  const AVClass *class;
680 
681  float xpos, ypos;
682  float tx, ty;
683  float size;
684  float tilt;
685  float theight, twidth;
686  float o;
688  int grid;
690  int scope;
691 
692  int x1, y1, x2, y2;
693  int ox, oy;
694  int height, width;
695 
696  int max;
698  int nb_comps;
699  int is_rgb;
700  uint8_t rgba_map[4];
711  FFDrawColor *colors[4];
712 
715 
717  void (*draw_trace)(struct OscilloscopeContext *s, AVFrame *frame);
719 
720 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
721 
722 static const AVOption oscilloscope_options[] = {
723  { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
724  { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
725  { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGS },
726  { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
727  { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGS },
728  { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS },
729  { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGS },
730  { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGS },
731  { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGS },
732  { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS },
733  { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
734  { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
735  { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
736  { NULL }
737 };
738 
739 AVFILTER_DEFINE_CLASS(oscilloscope);
740 
742 {
743  OscilloscopeContext *s = ctx->priv;
744 
745  av_freep(&s->values);
746 }
747 
748 static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1,
750 {
751  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
752  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
753  int err = (dx > dy ? dx : -dy) / 2, e2;
754  int p, i;
755 
756  for (;;) {
757  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
758  for (p = 0; p < draw->nb_planes; p++) {
759  if (draw->desc->comp[p].depth == 8) {
760  if (draw->nb_planes == 1) {
761  for (i = 0; i < 4; i++) {
762  out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i];
763  }
764  } else {
765  out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0];
766  }
767  } else {
768  if (draw->nb_planes == 1) {
769  for (i = 0; i < 4; i++) {
770  AV_WN16(out->data[0] + y0 * out->linesize[0] + 2 * (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]);
771  }
772  } else {
773  AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]);
774  }
775  }
776  }
777  }
778 
779  if (x0 == x1 && y0 == y1)
780  break;
781 
782  e2 = err;
783 
784  if (e2 >-dx) {
785  err -= dy;
786  x0 += sx;
787  }
788 
789  if (e2 < dy) {
790  err += dx;
791  y0 += sy;
792  }
793  }
794 }
795 
797 {
798  int i, c;
799 
800  for (i = 1; i < s->nb_values; i++) {
801  for (c = 0; c < s->nb_comps; c++) {
802  if ((1 << c) & s->components) {
803  int x = i * s->width / s->nb_values;
804  int px = (i - 1) * s->width / s->nb_values;
805  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256;
806  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256;
807 
808  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
809  }
810  }
811  }
812 }
813 
814 
816 {
817  int i, c;
818 
819  for (i = 1; i < s->nb_values; i++) {
820  for (c = 0; c < s->nb_comps; c++) {
821  if ((1 << c) & s->components) {
822  int x = i * s->width / s->nb_values;
823  int px = (i - 1) * s->width / s->nb_values;
824  int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max;
825  int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max;
826 
827  draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]);
828  }
829  }
830  }
831 }
832 
834 {
835  OscilloscopeContext *s = inlink->dst->priv;
836  int cx, cy, size;
837  double tilt;
838 
840  ff_draw_init(&s->draw, inlink->format, 0);
841  ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} );
842  ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} );
843  ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} );
844  ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} );
845  ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} );
846  ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} );
847  ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} );
848  ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} );
849  ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} );
850  s->nb_comps = s->draw.desc->nb_components;
852 
853  if (s->is_rgb) {
854  s->colors[0] = &s->red;
855  s->colors[1] = &s->green;
856  s->colors[2] = &s->blue;
857  s->colors[3] = &s->white;
858  ff_fill_rgba_map(s->rgba_map, inlink->format);
859  } else {
860  s->colors[0] = &s->white;
861  s->colors[1] = &s->cyan;
862  s->colors[2] = &s->magenta;
863  s->colors[3] = &s->white;
864  s->rgba_map[0] = 0;
865  s->rgba_map[1] = 1;
866  s->rgba_map[2] = 2;
867  s->rgba_map[3] = 3;
868  }
869 
870  if (s->draw.desc->comp[0].depth <= 8) {
871  s->pick_color = pick_color8;
872  s->draw_trace = draw_trace8;
873  } else {
876  }
877 
878  s->max = (1 << s->draw.desc->comp[0].depth);
879  cx = s->xpos * (inlink->w - 1);
880  cy = s->ypos * (inlink->h - 1);
881  s->height = s->theight * inlink->h;
882  s->width = s->twidth * inlink->w;
883  size = hypot(inlink->w, inlink->h);
884 
885  s->values = av_calloc(size, sizeof(*s->values));
886  if (!s->values)
887  return AVERROR(ENOMEM);
888 
889  size *= s->size;
890  tilt = (s->tilt - 0.5) * M_PI;
891  s->x1 = cx - size / 2.0 * cos(tilt);
892  s->x2 = cx + size / 2.0 * cos(tilt);
893  s->y1 = cy - size / 2.0 * sin(tilt);
894  s->y2 = cy + size / 2.0 * sin(tilt);
895  s->ox = (inlink->w - s->width) * s->tx;
896  s->oy = (inlink->h - s->height) * s->ty;
897 
898  return 0;
899 }
900 
901 static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
902  AVFrame *out, PixelValues *p, int state)
903 {
904  int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1;
905  int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1;
906  int err = (dx > dy ? dx : -dy) / 2, e2;
907 
908  for (;;) {
909  if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) {
910  FFDrawColor color = { { 0 } };
911  int value[4] = { 0 };
912 
913  s->pick_color(&s->draw, &color, out, x0, y0, value);
914  s->values[s->nb_values].p[0] = value[0];
915  s->values[s->nb_values].p[1] = value[1];
916  s->values[s->nb_values].p[2] = value[2];
917  s->values[s->nb_values].p[3] = value[3];
918  s->nb_values++;
919 
920  if (s->scope) {
921  if (s->draw.desc->comp[0].depth == 8) {
922  if (s->draw.nb_planes == 1) {
923  int i;
924 
925  for (i = 0; i < s->draw.pixelstep[0]; i++)
926  out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1);
927  } else {
928  out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1);
929  }
930  } else {
931  if (s->draw.nb_planes == 1) {
932  int i;
933 
934  for (i = 0; i < s->draw.pixelstep[0]; i++)
935  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0 * (s->draw.pixelstep[0] + i), (s->max - 1) * ((s->nb_values + state) & 1));
936  } else {
937  AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1));
938  }
939  }
940  }
941  }
942 
943  if (x0 == x1 && y0 == y1)
944  break;
945 
946  e2 = err;
947 
948  if (e2 >-dx) {
949  err -= dy;
950  x0 += sx;
951  }
952 
953  if (e2 < dy) {
954  err += dx;
955  y0 += sy;
956  }
957  }
958 }
959 
961 {
962  AVFilterContext *ctx = inlink->dst;
963  OscilloscopeContext *s = ctx->priv;
964  AVFilterLink *outlink = ctx->outputs[0];
965  float average[4] = { 0 };
966  int max[4] = { 0 };
967  int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
968  int i, c;
969 
970  s->nb_values = 0;
971  draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
972  ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
973  frame->width, frame->height,
974  s->ox, s->oy, s->width, s->height + 20 * s->statistics);
975 
976  if (s->grid && outlink->h >= 10) {
977  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
978  s->ox, s->oy, s->width - 1, 1);
979 
980  for (i = 1; i < 5; i++) {
981  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
982  s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1);
983  }
984 
985  for (i = 0; i < 10; i++) {
986  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
987  s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height);
988  }
989 
990  ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize,
991  s->ox + s->width - 1, s->oy, 1, s->height);
992  }
993 
994  s->draw_trace(s, frame);
995 
996  for (i = 0; i < s->nb_values; i++) {
997  for (c = 0; c < s->nb_comps; c++) {
998  if ((1 << c) & s->components) {
999  max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]);
1000  min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]);
1001  average[c] += s->values[i].p[s->rgba_map[c]];
1002  }
1003  }
1004  }
1005  for (c = 0; c < s->nb_comps; c++) {
1006  average[c] /= s->nb_values;
1007  }
1008 
1009  if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) {
1010  for (c = 0, i = 0; c < s->nb_comps; c++) {
1011  if ((1 << c) & s->components) {
1012  const char rgba[4] = { 'R', 'G', 'B', 'A' };
1013  const char yuva[4] = { 'Y', 'U', 'V', 'A' };
1014  char text[128];
1015 
1016  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]);
1017  draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0);
1018  }
1019  }
1020  }
1021 
1022  return ff_filter_frame(outlink, frame);
1023 }
1024 
1026  {
1027  .name = "default",
1028  .type = AVMEDIA_TYPE_VIDEO,
1029  .filter_frame = oscilloscope_filter_frame,
1030  .config_props = oscilloscope_config_input,
1031  .needs_writable = 1,
1032  },
1033  { NULL }
1034 };
1035 
1037  {
1038  .name = "default",
1039  .type = AVMEDIA_TYPE_VIDEO,
1040  },
1041  { NULL }
1042 };
1043 
1045  .name = "oscilloscope",
1046  .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."),
1047  .priv_size = sizeof(OscilloscopeContext),
1048  .priv_class = &oscilloscope_class,
1051  .inputs = oscilloscope_inputs,
1052  .outputs = oscilloscope_outputs,
1054 };
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:701
#define P
AVFrame * out
Definition: af_adeclick.c:488
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
static const AVOption pixscope_options[]
Definition: vf_datascope.c:452
AVOption.
Definition: opt.h:246
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:182
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2562
Main libavfilter public API header.
void(* draw_trace)(struct OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:717
Definition: vf_addroi.c:26
static int filter_color2(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:170
FFDrawColor magenta
Definition: vf_datascope.c:709
FFDrawColor * colors[4]
Definition: vf_datascope.c:711
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:663
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:87
Definition: vf_addroi.c:26
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:244
static int filter_mono(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:250
#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:125
FFDrawColor black
Definition: vf_datascope.c:440
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
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:720
#define OFFSET(x)
Definition: vf_datascope.c:55
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:120
uint8_t
static void pick_color8(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:102
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
FFDrawColor gray
Definition: vf_datascope.c:48
void(* reverse_color)(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:51
AVOptions.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhq.c:565
static int filter_color(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_datascope.c:212
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:388
#define height
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:716
void(* pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value)
Definition: vf_datascope.c:447
static const AVFilterPad inputs[]
Definition: vf_datascope.c:393
#define max(a, b)
Definition: cuda_runtime.h:33
ptrdiff_t size
Definition: opengl_enc.c:100
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
static const AVOption datascope_options[]
Definition: vf_datascope.c:58
#define POFFSET(x)
Definition: vf_datascope.c:450
static void draw_trace16(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:815
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
static void draw_trace8(OscilloscopeContext *s, AVFrame *frame)
Definition: vf_datascope.c:796
int width
Definition: frame.h:353
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
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:569
#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:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
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:150
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:792
FFDrawColor * colors[4]
Definition: vf_datascope.c:445
static void oscilloscope_uninit(AVFilterContext *ctx)
Definition: vf_datascope.c:741
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
FFDrawContext draw
Definition: vf_datascope.c:44
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:52
#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:802
#define FFMIN(a, b)
Definition: common.h:96
uint8_t rgba_map[4]
Definition: vf_datascope.c:437
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_datascope.c:287
#define width
uint8_t w
Definition: llviddspenc.c:38
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
AVFormatContext * ctx
Definition: movenc.c:48
static int config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:351
static int query_formats(AVFilterContext *ctx)
Definition: vf_datascope.c:74
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:50
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:56
PixelValues * values
Definition: vf_datascope.c:714
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:403
FFDrawColor dark
Definition: vf_datascope.c:439
misc drawing utilities
static struct @320 state
Used for passing data between threads.
Definition: dsddec.c:64
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
unsigned nb_planes
Definition: drawutils.h:51
static const AVOption oscilloscope_options[]
Definition: vf_datascope.c:722
static void draw_text(FFDrawContext *draw, AVFrame *frame, FFDrawColor *color, int x0, int y0, const uint8_t *text, int vertical)
Definition: vf_datascope.c:79
static const int16_t alpha[]
Definition: ilbcdata.h:55
FFDrawContext draw
Definition: vf_datascope.c:438
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:521
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
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:148
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:233
misc parsing utilities
FFDrawColor blue
Definition: vf_datascope.c:443
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
uint16_t p[4]
Definition: vf_datascope.c:675
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
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:901
FFDrawColor white
Definition: vf_datascope.c:46
static int config_output(AVFilterLink *outlink)
Definition: vf_datascope.c:382
static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_datascope.c:960
static int pixscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:465
avfilter_execute_func * execute
Definition: internal.h:155
union FFDrawColor::@221 comp[MAX_PLANES]
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2036
FFDrawColor yellow
Definition: vf_datascope.c:45
FFDrawColor black
Definition: vf_datascope.c:47
AVFilter ff_vf_datascope
Definition: vf_datascope.c:412
static const AVFilterPad pixscope_outputs[]
Definition: vf_datascope.c:655
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:338
int height
Definition: frame.h:353
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:444
AVFrame * in
Definition: af_afftdn.c:1082
static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1, AVFrame *out, FFDrawColor *color)
Definition: vf_datascope.c:748
internal API functions
static int oscilloscope_config_input(AVFilterLink *inlink)
Definition: vf_datascope.c:833
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int depth
Number of bits in the component.
Definition: pixdesc.h:58
FFDrawColor green
Definition: vf_datascope.c:442
float min
static const AVFilterPad pixscope_inputs[]
Definition: vf_datascope.c:645
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:654
CGA/EGA/VGA ROM font data.
static void reverse_color8(FFDrawContext *draw, FFDrawColor *color, FFDrawColor *reverse)
Definition: vf_datascope.c:138
uint8_t rgba[4]
Definition: drawutils.h:63
FFDrawColor white
Definition: vf_datascope.c:441