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
31
41
50
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
76 };
77
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 }
99 if (vertical) {
100 x = x0;
101 y0 += 8;
102 } else {
103 x += 8;
104 }
105 }
106 }
107
109 {
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++) {
118 }
119 } else {
122 }
123 }
124 }
125
127 {
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++) {
136 }
137 } else {
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
168 }
169 }
170
175
177 {
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++) {
201 int value[4] = { 0 }, pp = 0;
202
204 s->reverse_color(&
s->draw, &
color, &reverse);
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;
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
224 {
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++) {
247 int value[4] = { 0 }, pp = 0;
248
250
251 for (p = 0; p <
P; p++) {
252 char text[256];
253
254 if (!(
s->components & (1 << p)))
255 continue;
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
267 {
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++) {
290 int value[4] = { 0 }, pp = 0;
291
293 for (p = 0; p <
P; p++) {
294 char text[256];
295
296 if (!(
s->components & (1 << p)))
297 continue;
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 {
313 const int P =
FFMAX(
s->nb_planes,
s->nb_comps);
315 int ymaxlen = 0;
316 int xmaxlen = 0;
317 int PP = 0;
319
324 }
326
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 }
335
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
344 ymaxlen = strlen(text);
345 ymaxlen *= 10;
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
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
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;
375
378 }
379
381 {
383 uint8_t
alpha =
s->opacity * 255;
384
391 s->chars = (
s->draw.desc->comp[0].depth + 7) / 8 * 2 +
s->dformat;
392 s->nb_comps =
s->draw.desc->nb_components;
393
398 }
399
400 if (
s->draw.desc->comp[0].depth <= 8) {
403 } else {
406 }
407
408 return 0;
409 }
410
412 {
414
418
419 return 0;
420 }
421
423 char *res,
int res_len,
int flags)
424 {
426
430
432 }
433
435 {
440 },
441 };
442
444 {
448 },
449 };
450
455 .priv_class = &datascope_class,
461 };
462
465
470
473
486
488
491
492 #define POFFSET(x) offsetof(PixscopeContext, x)
493
503 };
504
506
508 {
510
519 s->nb_comps =
s->draw.desc->nb_components;
521
523 s->colors[0] = &
s->red;
524 s->colors[1] = &
s->green;
525 s->colors[2] = &
s->blue;
526 s->colors[3] = &
s->white;
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;
537 }
538
539 if (
s->draw.desc->comp[0].depth <= 8) {
541 } else {
543 }
544
548 }
549
558 }
559
560 return 0;
561 }
562
563 #define SQR(x) ((x)*(x))
564
566 {
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
582 }
585
588
591 } else {
593 }
596 } else {
598 }
599
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
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)) {
611 }
612 }
613
620
621 for (y = 0; y <
s->h; y++) {
622 for (x = 0; x <
s->w; x++) {
624 int value[4] = { 0 };
625
628 x *
w + (
s->ww - 4 - (
s->w *
w)) / 2 +
X, y *
h + 2 +
Y,
w,
h);
629 for (
i = 0;
i < 4;
i++) {
635 }
636 }
637 }
638
641 s->x - 2,
s->y - 2,
s->w + 4, 1);
642
645 s->x - 1,
s->y - 1,
s->w + 2, 1);
646
649 s->x - 1,
s->y - 1, 1,
s->h + 2);
650
653 s->x - 2,
s->y - 2, 1,
s->h + 4);
654
657 s->x - 1,
s->y + 1 +
s->h,
s->w + 3, 1);
658
661 s->x - 2,
s->y + 2 +
s->h,
s->w + 4, 1);
662
665 s->x + 1 +
s->w,
s->y - 1, 1,
s->h + 2);
666
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");
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]);
696 }
697 snprintf(text,
sizeof(text),
"CH STD\n");
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]);
704 }
705
708 }
709
711 char *res,
int res_len,
int flags)
712 {
714
718
720 }
721
723 {
728 },
729 };
730
732 {
735 },
736 };
737
742 .priv_class = &pixscope_class,
748 };
749
753
756
767
771
788
791
795
796 #define OOFFSET(x) offsetof(OscilloscopeContext, x)
797
813 };
814
816
818 {
820
822 }
823
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;
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++) {
847 }
848 } else {
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 {
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
885 }
886 }
887 }
888 }
889
890
892 {
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
904 }
905 }
906 }
907 }
908
910 {
915
922 cx =
s->xpos * (
inlink->w - 1);
923 cy =
s->ypos * (
inlink->h - 1);
930 }
931
933 {
936
947 s->nb_comps =
s->draw.desc->nb_components;
949
951 s->colors[0] = &
s->red;
952 s->colors[1] = &
s->green;
953 s->colors[2] = &
s->blue;
954 s->colors[3] = &
s->white;
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;
965 }
966
967 if (
s->draw.desc->comp[0].depth <= 8) {
970 } else {
973 }
974
975 s->max = (1 <<
s->draw.desc->comp[0].depth);
977
981
983
984 return 0;
985 }
986
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) {
997 int value[4] = { 0 };
998
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];
1005
1007 if (
s->draw.desc->comp[0].depth == 8) {
1008 if (
s->draw.nb_planes == 1) {
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) {
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 {
1051 float average[4] = { 0 };
1053 int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
1055
1060 s->ox,
s->oy,
s->width,
s->height + 20 *
s->statistics);
1061
1062 if (
s->grid && outlink->
h >= 10) {
1064 s->ox,
s->oy,
s->width - 1, 1);
1065
1066 for (
i = 1;
i < 5;
i++) {
1068 s->ox,
s->oy +
i * (
s->height - 1) / 4,
s->width, 1);
1069 }
1070
1071 for (
i = 0;
i < 10;
i++) {
1073 s->ox +
i * (
s->width - 1) / 10,
s->oy, 1,
s->height);
1074 }
1075
1077 s->ox +
s->width - 1,
s->oy, 1,
s->height);
1078 }
1079
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) {
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]);
1104 }
1105 }
1106 }
1107
1109 }
1110
1112 char *res,
int res_len,
int flags)
1113 {
1115
1119
1121
1122 return 0;
1123 }
1124
1126 {
1132 },
1133 };
1134
1136 {
1139 },
1140 };
1141
1143 .
name =
"oscilloscope",
1146 .priv_class = &oscilloscope_class,
1153 };