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