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