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