Signed-off-by: Paul B Mahol <onemda@gmail.com>
Paul B Mahol authored on 2017/04/26 02:31:05... | ... |
@@ -10233,6 +10233,84 @@ other parameters is 0. |
10233 | 10233 |
These parameters correspond to the parameters assigned to the |
10234 | 10234 |
libopencv function @code{cvSmooth}. |
10235 | 10235 |
|
10236 |
+@section oscilloscope |
|
10237 |
+ |
|
10238 |
+2D Video Oscilloscope. |
|
10239 |
+ |
|
10240 |
+Useful to measure spatial impulse, step responses, chroma delays, etc. |
|
10241 |
+ |
|
10242 |
+It accepts the following parameters: |
|
10243 |
+ |
|
10244 |
+@table @option |
|
10245 |
+@item x |
|
10246 |
+Set scope center x position. |
|
10247 |
+ |
|
10248 |
+@item y |
|
10249 |
+Set scope center y position. |
|
10250 |
+ |
|
10251 |
+@item s |
|
10252 |
+Set scope size, relative to frame diagonal. |
|
10253 |
+ |
|
10254 |
+@item t |
|
10255 |
+Set scope tilt/rotation. |
|
10256 |
+ |
|
10257 |
+@item o |
|
10258 |
+Set trace opacity. |
|
10259 |
+ |
|
10260 |
+@item tx |
|
10261 |
+Set trace center x position. |
|
10262 |
+ |
|
10263 |
+@item ty |
|
10264 |
+Set trace center y position. |
|
10265 |
+ |
|
10266 |
+@item tw |
|
10267 |
+Set trace width, relative to width of frame. |
|
10268 |
+ |
|
10269 |
+@item th |
|
10270 |
+Set trace height, relative to height of frame. |
|
10271 |
+ |
|
10272 |
+@item c |
|
10273 |
+Set which components to trace. By default it traces first three components. |
|
10274 |
+ |
|
10275 |
+@item g |
|
10276 |
+Draw trace grid. By default is enabled. |
|
10277 |
+ |
|
10278 |
+@item st |
|
10279 |
+Draw some statistics. By default is enabled. |
|
10280 |
+ |
|
10281 |
+@item sc |
|
10282 |
+Draw scope. By default is enabled. |
|
10283 |
+@end table |
|
10284 |
+ |
|
10285 |
+@subsection Examples |
|
10286 |
+ |
|
10287 |
+@itemize |
|
10288 |
+@item |
|
10289 |
+Inspect full first row of video frame. |
|
10290 |
+@example |
|
10291 |
+oscilloscope=x=0.5:y=0:s=1 |
|
10292 |
+@end example |
|
10293 |
+ |
|
10294 |
+@item |
|
10295 |
+Inspect full last row of video frame. |
|
10296 |
+@example |
|
10297 |
+oscilloscope=x=0.5:y=1:s=1 |
|
10298 |
+@end example |
|
10299 |
+ |
|
10300 |
+@item |
|
10301 |
+Inspect full 5th line of video frame of height 1080. |
|
10302 |
+@example |
|
10303 |
+oscilloscope=x=0.5:y=5/1080:s=1 |
|
10304 |
+@end example |
|
10305 |
+ |
|
10306 |
+@item |
|
10307 |
+Inspect full last column of video frame. |
|
10308 |
+@example |
|
10309 |
+oscilloscope=x=1:y=0.5:s=1:t=1 |
|
10310 |
+@end example |
|
10311 |
+ |
|
10312 |
+@end itemize |
|
10313 |
+ |
|
10236 | 10314 |
@anchor{overlay} |
10237 | 10315 |
@section overlay |
10238 | 10316 |
|
... | ... |
@@ -236,6 +236,7 @@ OBJS-$(CONFIG_NULL_FILTER) += vf_null.o |
236 | 236 |
OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o |
237 | 237 |
OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o |
238 | 238 |
OBJS-$(CONFIG_OPENCL) += deshake_opencl.o unsharp_opencl.o |
239 |
+OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o |
|
239 | 240 |
OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o dualinput.o framesync.o |
240 | 241 |
OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o |
241 | 242 |
OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o |
... | ... |
@@ -246,6 +246,7 @@ static void register_all(void) |
246 | 246 |
REGISTER_FILTER(NULL, null, vf); |
247 | 247 |
REGISTER_FILTER(OCR, ocr, vf); |
248 | 248 |
REGISTER_FILTER(OCV, ocv, vf); |
249 |
+ REGISTER_FILTER(OSCILLOSCOPE, oscilloscope, vf); |
|
249 | 250 |
REGISTER_FILTER(OVERLAY, overlay, vf); |
250 | 251 |
REGISTER_FILTER(OWDENOISE, owdenoise, vf); |
251 | 252 |
REGISTER_FILTER(PAD, pad, vf); |
... | ... |
@@ -641,3 +641,384 @@ AVFilter ff_vf_pixscope = { |
641 | 641 |
.inputs = pixscope_inputs, |
642 | 642 |
.outputs = pixscope_outputs, |
643 | 643 |
}; |
644 |
+ |
|
645 |
+typedef struct PixelValues { |
|
646 |
+ uint16_t p[4]; |
|
647 |
+} PixelValues; |
|
648 |
+ |
|
649 |
+typedef struct OscilloscopeContext { |
|
650 |
+ const AVClass *class; |
|
651 |
+ |
|
652 |
+ float xpos, ypos; |
|
653 |
+ float tx, ty; |
|
654 |
+ float size; |
|
655 |
+ float tilt; |
|
656 |
+ float theight, twidth; |
|
657 |
+ float o; |
|
658 |
+ int components; |
|
659 |
+ int grid; |
|
660 |
+ int statistics; |
|
661 |
+ int scope; |
|
662 |
+ |
|
663 |
+ int x1, y1, x2, y2; |
|
664 |
+ int ox, oy; |
|
665 |
+ int height, width; |
|
666 |
+ |
|
667 |
+ int max; |
|
668 |
+ int nb_planes; |
|
669 |
+ int nb_comps; |
|
670 |
+ int is_rgb; |
|
671 |
+ uint8_t rgba_map[4]; |
|
672 |
+ FFDrawContext draw; |
|
673 |
+ FFDrawColor dark; |
|
674 |
+ FFDrawColor black; |
|
675 |
+ FFDrawColor white; |
|
676 |
+ FFDrawColor green; |
|
677 |
+ FFDrawColor blue; |
|
678 |
+ FFDrawColor red; |
|
679 |
+ FFDrawColor cyan; |
|
680 |
+ FFDrawColor magenta; |
|
681 |
+ FFDrawColor gray; |
|
682 |
+ FFDrawColor *colors[4]; |
|
683 |
+ |
|
684 |
+ int nb_values; |
|
685 |
+ PixelValues *values; |
|
686 |
+ |
|
687 |
+ void (*pick_color)(FFDrawContext *draw, FFDrawColor *color, AVFrame *in, int x, int y, int *value); |
|
688 |
+ void (*draw_trace)(struct OscilloscopeContext *s, AVFrame *frame); |
|
689 |
+} OscilloscopeContext; |
|
690 |
+ |
|
691 |
+#define OOFFSET(x) offsetof(OscilloscopeContext, x) |
|
692 |
+ |
|
693 |
+static const AVOption oscilloscope_options[] = { |
|
694 |
+ { "x", "set scope x position", OOFFSET(xpos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, |
|
695 |
+ { "y", "set scope y position", OOFFSET(ypos), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, |
|
696 |
+ { "s", "set scope size", OOFFSET(size), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGS }, |
|
697 |
+ { "t", "set scope tilt", OOFFSET(tilt), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, |
|
698 |
+ { "o", "set trace opacity", OOFFSET(o), AV_OPT_TYPE_FLOAT, {.dbl=0.8}, 0, 1, FLAGS }, |
|
699 |
+ { "tx", "set trace x position", OOFFSET(tx), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, |
|
700 |
+ { "ty", "set trace y position", OOFFSET(ty), AV_OPT_TYPE_FLOAT, {.dbl=0.9}, 0, 1, FLAGS }, |
|
701 |
+ { "tw", "set trace width", OOFFSET(twidth), AV_OPT_TYPE_FLOAT, {.dbl=0.8},.1, 1, FLAGS }, |
|
702 |
+ { "th", "set trace height", OOFFSET(theight), AV_OPT_TYPE_FLOAT, {.dbl=0.3},.1, 1, FLAGS }, |
|
703 |
+ { "c", "set components to trace", OOFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS }, |
|
704 |
+ { "g", "draw trace grid", OOFFSET(grid), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, |
|
705 |
+ { "st", "draw statistics", OOFFSET(statistics), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, |
|
706 |
+ { "sc", "draw scope", OOFFSET(scope), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, |
|
707 |
+ { NULL } |
|
708 |
+}; |
|
709 |
+ |
|
710 |
+AVFILTER_DEFINE_CLASS(oscilloscope); |
|
711 |
+ |
|
712 |
+static void oscilloscope_uninit(AVFilterContext *ctx) |
|
713 |
+{ |
|
714 |
+ OscilloscopeContext *s = ctx->priv; |
|
715 |
+ |
|
716 |
+ av_freep(&s->values); |
|
717 |
+} |
|
718 |
+ |
|
719 |
+static void draw_line(FFDrawContext *draw, int x0, int y0, int x1, int y1, |
|
720 |
+ AVFrame *out, FFDrawColor *color) |
|
721 |
+{ |
|
722 |
+ int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1; |
|
723 |
+ int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1; |
|
724 |
+ int err = (dx > dy ? dx : -dy) / 2, e2; |
|
725 |
+ int p, i; |
|
726 |
+ |
|
727 |
+ for (;;) { |
|
728 |
+ if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) { |
|
729 |
+ for (p = 0; p < draw->nb_planes; p++) { |
|
730 |
+ if (draw->desc->comp[p].depth == 8) { |
|
731 |
+ if (draw->nb_planes == 1) { |
|
732 |
+ for (i = 0; i < 4; i++) { |
|
733 |
+ out->data[0][y0 * out->linesize[0] + x0 * draw->pixelstep[0] + i] = color->comp[0].u8[i]; |
|
734 |
+ } |
|
735 |
+ } else { |
|
736 |
+ out->data[p][out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p])] = color->comp[p].u8[0]; |
|
737 |
+ } |
|
738 |
+ } else { |
|
739 |
+ if (draw->nb_planes == 1) { |
|
740 |
+ for (i = 0; i < 4; i++) { |
|
741 |
+ AV_WN16(out->data[0] + y0 * out->linesize[0] + 2 * (x0 * draw->pixelstep[0] + i), color->comp[0].u16[i]); |
|
742 |
+ } |
|
743 |
+ } else { |
|
744 |
+ AV_WN16(out->data[p] + out->linesize[p] * (y0 >> draw->vsub[p]) + (x0 >> draw->hsub[p]) * 2, color->comp[p].u16[0]); |
|
745 |
+ } |
|
746 |
+ } |
|
747 |
+ } |
|
748 |
+ } |
|
749 |
+ |
|
750 |
+ if (x0 == x1 && y0 == y1) |
|
751 |
+ break; |
|
752 |
+ |
|
753 |
+ e2 = err; |
|
754 |
+ |
|
755 |
+ if (e2 >-dx) { |
|
756 |
+ err -= dy; |
|
757 |
+ x0 += sx; |
|
758 |
+ } |
|
759 |
+ |
|
760 |
+ if (e2 < dy) { |
|
761 |
+ err += dx; |
|
762 |
+ y0 += sy; |
|
763 |
+ } |
|
764 |
+ } |
|
765 |
+} |
|
766 |
+ |
|
767 |
+static void draw_trace8(OscilloscopeContext *s, AVFrame *frame) |
|
768 |
+{ |
|
769 |
+ int i, c; |
|
770 |
+ |
|
771 |
+ for (i = 1; i < s->nb_values; i++) { |
|
772 |
+ for (c = 0; c < s->nb_comps; c++) { |
|
773 |
+ if ((1 << c) & s->components) { |
|
774 |
+ int x = i * s->width / s->nb_values; |
|
775 |
+ int px = (i - 1) * s->width / s->nb_values; |
|
776 |
+ int py = s->height - s->values[i-1].p[c] * s->height / 256; |
|
777 |
+ int y = s->height - s->values[i].p[c] * s->height / 256; |
|
778 |
+ |
|
779 |
+ draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]); |
|
780 |
+ } |
|
781 |
+ } |
|
782 |
+ } |
|
783 |
+} |
|
784 |
+ |
|
785 |
+ |
|
786 |
+static void draw_trace16(OscilloscopeContext *s, AVFrame *frame) |
|
787 |
+{ |
|
788 |
+ int i, c; |
|
789 |
+ |
|
790 |
+ for (i = 1; i < s->nb_values; i++) { |
|
791 |
+ for (c = 0; c < s->nb_comps; c++) { |
|
792 |
+ if ((1 << c) & s->components) { |
|
793 |
+ int x = i * s->width / s->nb_values; |
|
794 |
+ int px = (i - 1) * s->width / s->nb_values; |
|
795 |
+ int py = s->height - s->values[i-1].p[c] * s->height / s->max; |
|
796 |
+ int y = s->height - s->values[i].p[c] * s->height / s->max; |
|
797 |
+ |
|
798 |
+ draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]); |
|
799 |
+ } |
|
800 |
+ } |
|
801 |
+ } |
|
802 |
+} |
|
803 |
+ |
|
804 |
+static int oscilloscope_config_input(AVFilterLink *inlink) |
|
805 |
+{ |
|
806 |
+ OscilloscopeContext *s = inlink->dst->priv; |
|
807 |
+ int cx, cy, size; |
|
808 |
+ double tilt; |
|
809 |
+ |
|
810 |
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format); |
|
811 |
+ ff_draw_init(&s->draw, inlink->format, 0); |
|
812 |
+ ff_draw_color(&s->draw, &s->dark, (uint8_t[]){ 0, 0, 0, s->o * 255} ); |
|
813 |
+ ff_draw_color(&s->draw, &s->black, (uint8_t[]){ 0, 0, 0, 255} ); |
|
814 |
+ ff_draw_color(&s->draw, &s->white, (uint8_t[]){ 255, 255, 255, 255} ); |
|
815 |
+ ff_draw_color(&s->draw, &s->green, (uint8_t[]){ 0, 255, 0, 255} ); |
|
816 |
+ ff_draw_color(&s->draw, &s->blue, (uint8_t[]){ 0, 0, 255, 255} ); |
|
817 |
+ ff_draw_color(&s->draw, &s->red, (uint8_t[]){ 255, 0, 0, 255} ); |
|
818 |
+ ff_draw_color(&s->draw, &s->cyan, (uint8_t[]){ 0, 255, 255, 255} ); |
|
819 |
+ ff_draw_color(&s->draw, &s->magenta, (uint8_t[]){ 255, 0, 255, 255} ); |
|
820 |
+ ff_draw_color(&s->draw, &s->gray, (uint8_t[]){ 128, 128, 128, 255} ); |
|
821 |
+ s->nb_comps = s->draw.desc->nb_components; |
|
822 |
+ s->is_rgb = s->draw.desc->flags & AV_PIX_FMT_FLAG_RGB; |
|
823 |
+ |
|
824 |
+ if (s->is_rgb) { |
|
825 |
+ s->colors[0] = &s->red; |
|
826 |
+ s->colors[1] = &s->green; |
|
827 |
+ s->colors[2] = &s->blue; |
|
828 |
+ s->colors[3] = &s->white; |
|
829 |
+ ff_fill_rgba_map(s->rgba_map, inlink->format); |
|
830 |
+ } else { |
|
831 |
+ s->colors[0] = &s->white; |
|
832 |
+ s->colors[1] = &s->cyan; |
|
833 |
+ s->colors[2] = &s->magenta; |
|
834 |
+ s->colors[3] = &s->white; |
|
835 |
+ s->rgba_map[0] = 0; |
|
836 |
+ s->rgba_map[1] = 1; |
|
837 |
+ s->rgba_map[2] = 2; |
|
838 |
+ s->rgba_map[3] = 3; |
|
839 |
+ } |
|
840 |
+ |
|
841 |
+ if (s->draw.desc->comp[0].depth <= 8) { |
|
842 |
+ s->pick_color = pick_color8; |
|
843 |
+ s->draw_trace = draw_trace8; |
|
844 |
+ } else { |
|
845 |
+ s->pick_color = pick_color16; |
|
846 |
+ s->draw_trace = draw_trace16; |
|
847 |
+ } |
|
848 |
+ |
|
849 |
+ s->max = (1 << s->draw.desc->comp[0].depth); |
|
850 |
+ cx = s->xpos * (inlink->w - 1); |
|
851 |
+ cy = s->ypos * (inlink->h - 1); |
|
852 |
+ s->height = s->theight * inlink->h; |
|
853 |
+ s->width = s->twidth * inlink->w; |
|
854 |
+ size = hypot(inlink->w, inlink->h); |
|
855 |
+ |
|
856 |
+ s->values = av_calloc(size, sizeof(*s->values)); |
|
857 |
+ if (!s->values) |
|
858 |
+ return AVERROR(ENOMEM); |
|
859 |
+ |
|
860 |
+ size *= s->size; |
|
861 |
+ tilt = (s->tilt - 0.5) * M_PI; |
|
862 |
+ s->x1 = cx - size / 2.0 * cos(tilt); |
|
863 |
+ s->x2 = cx + size / 2.0 * cos(tilt); |
|
864 |
+ s->y1 = cy - size / 2.0 * sin(tilt); |
|
865 |
+ s->y2 = cy + size / 2.0 * sin(tilt); |
|
866 |
+ s->ox = (inlink->w - s->width) * s->tx; |
|
867 |
+ s->oy = (inlink->h - s->height) * s->ty; |
|
868 |
+ |
|
869 |
+ return 0; |
|
870 |
+} |
|
871 |
+ |
|
872 |
+static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1, |
|
873 |
+ AVFrame *out, PixelValues *p, int state) |
|
874 |
+{ |
|
875 |
+ int dx = FFABS(x1 - x0), sx = x0 < x1 ? 1 : -1; |
|
876 |
+ int dy = FFABS(y1 - y0), sy = y0 < y1 ? 1 : -1; |
|
877 |
+ int err = (dx > dy ? dx : -dy) / 2, e2; |
|
878 |
+ |
|
879 |
+ for (;;) { |
|
880 |
+ if (x0 >= 0 && y0 >= 0 && x0 < out->width && y0 < out->height) { |
|
881 |
+ FFDrawColor color = { { 0 } }; |
|
882 |
+ int value[4] = { 0 }; |
|
883 |
+ |
|
884 |
+ s->pick_color(&s->draw, &color, out, x0, y0, value); |
|
885 |
+ s->values[s->nb_values].p[0] = value[0]; |
|
886 |
+ s->values[s->nb_values].p[1] = value[1]; |
|
887 |
+ s->values[s->nb_values].p[2] = value[2]; |
|
888 |
+ s->values[s->nb_values].p[3] = value[3]; |
|
889 |
+ s->nb_values++; |
|
890 |
+ |
|
891 |
+ if (s->scope) { |
|
892 |
+ if (s->draw.desc->comp[0].depth == 8) { |
|
893 |
+ if (s->draw.nb_planes == 1) { |
|
894 |
+ int i; |
|
895 |
+ |
|
896 |
+ for (i = 0; i < s->draw.pixelstep[0]; i++) |
|
897 |
+ out->data[0][out->linesize[0] * y0 + x0 * s->draw.pixelstep[0] + i] = 255 * ((s->nb_values + state) & 1); |
|
898 |
+ } else { |
|
899 |
+ out->data[0][out->linesize[0] * y0 + x0] = 255 * ((s->nb_values + state) & 1); |
|
900 |
+ } |
|
901 |
+ } else { |
|
902 |
+ if (s->draw.nb_planes == 1) { |
|
903 |
+ int i; |
|
904 |
+ |
|
905 |
+ for (i = 0; i < s->draw.pixelstep[0]; i++) |
|
906 |
+ AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0 * (s->draw.pixelstep[0] + i), (s->max - 1) * ((s->nb_values + state) & 1)); |
|
907 |
+ } else { |
|
908 |
+ AV_WN16(out->data[0] + out->linesize[0] * y0 + 2 * x0, (s->max - 1) * ((s->nb_values + state) & 1)); |
|
909 |
+ } |
|
910 |
+ } |
|
911 |
+ } |
|
912 |
+ } |
|
913 |
+ |
|
914 |
+ if (x0 == x1 && y0 == y1) |
|
915 |
+ break; |
|
916 |
+ |
|
917 |
+ e2 = err; |
|
918 |
+ |
|
919 |
+ if (e2 >-dx) { |
|
920 |
+ err -= dy; |
|
921 |
+ x0 += sx; |
|
922 |
+ } |
|
923 |
+ |
|
924 |
+ if (e2 < dy) { |
|
925 |
+ err += dx; |
|
926 |
+ y0 += sy; |
|
927 |
+ } |
|
928 |
+ } |
|
929 |
+} |
|
930 |
+ |
|
931 |
+static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame) |
|
932 |
+{ |
|
933 |
+ AVFilterContext *ctx = inlink->dst; |
|
934 |
+ OscilloscopeContext *s = ctx->priv; |
|
935 |
+ AVFilterLink *outlink = ctx->outputs[0]; |
|
936 |
+ float average[4] = { 0 }; |
|
937 |
+ int max[4] = { 0 }; |
|
938 |
+ int min[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; |
|
939 |
+ int i, c; |
|
940 |
+ |
|
941 |
+ s->nb_values = 0; |
|
942 |
+ draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1); |
|
943 |
+ ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize, |
|
944 |
+ frame->width, frame->height, |
|
945 |
+ s->ox, s->oy, s->width, s->height + 20 * s->statistics); |
|
946 |
+ |
|
947 |
+ if (s->grid) { |
|
948 |
+ ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize, |
|
949 |
+ s->ox, s->oy, s->width - 1, 1); |
|
950 |
+ |
|
951 |
+ for (i = 1; i < 5; i++) { |
|
952 |
+ ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize, |
|
953 |
+ s->ox, s->oy + i * (s->height - 1) / 4, s->width, 1); |
|
954 |
+ } |
|
955 |
+ |
|
956 |
+ for (i = 0; i < 10; i++) { |
|
957 |
+ ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize, |
|
958 |
+ s->ox + i * (s->width - 1) / 10, s->oy, 1, s->height); |
|
959 |
+ } |
|
960 |
+ |
|
961 |
+ ff_fill_rectangle(&s->draw, &s->gray, frame->data, frame->linesize, |
|
962 |
+ s->ox + s->width - 1, s->oy, 1, s->height); |
|
963 |
+ } |
|
964 |
+ |
|
965 |
+ s->draw_trace(s, frame); |
|
966 |
+ |
|
967 |
+ for (i = 0; i < s->nb_values; i++) { |
|
968 |
+ for (c = 0; c < s->nb_comps; c++) { |
|
969 |
+ if ((1 << c) & s->components) { |
|
970 |
+ max[c] = FFMAX(max[c], s->values[i].p[c]); |
|
971 |
+ min[c] = FFMIN(min[c], s->values[i].p[c]); |
|
972 |
+ average[c] += s->values[i].p[c]; |
|
973 |
+ } |
|
974 |
+ } |
|
975 |
+ } |
|
976 |
+ for (c = 0; c < s->nb_comps; c++) { |
|
977 |
+ average[c] /= s->nb_values; |
|
978 |
+ } |
|
979 |
+ |
|
980 |
+ if (s->statistics && s->height > 10 && s->width > 280 * av_popcount(s->components)) { |
|
981 |
+ for (c = 0, i = 0; c < s->nb_comps; c++) { |
|
982 |
+ if ((1 << c) & s->components) { |
|
983 |
+ const char rgba[4] = { 'R', 'G', 'B', 'A' }; |
|
984 |
+ const char yuva[4] = { 'Y', 'U', 'V', 'A' }; |
|
985 |
+ char text[128]; |
|
986 |
+ |
|
987 |
+ snprintf(text, sizeof(text), "%c avg:%.1f min:%d max:%d\n", s->is_rgb ? rgba[c] : yuva[c], average[s->rgba_map[c]], min[s->rgba_map[c]], max[s->rgba_map[c]]); |
|
988 |
+ draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0); |
|
989 |
+ } |
|
990 |
+ } |
|
991 |
+ } |
|
992 |
+ |
|
993 |
+ return ff_filter_frame(outlink, frame); |
|
994 |
+} |
|
995 |
+ |
|
996 |
+static const AVFilterPad oscilloscope_inputs[] = { |
|
997 |
+ { |
|
998 |
+ .name = "default", |
|
999 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
1000 |
+ .filter_frame = oscilloscope_filter_frame, |
|
1001 |
+ .config_props = oscilloscope_config_input, |
|
1002 |
+ .needs_writable = 1, |
|
1003 |
+ }, |
|
1004 |
+ { NULL } |
|
1005 |
+}; |
|
1006 |
+ |
|
1007 |
+static const AVFilterPad oscilloscope_outputs[] = { |
|
1008 |
+ { |
|
1009 |
+ .name = "default", |
|
1010 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
1011 |
+ }, |
|
1012 |
+ { NULL } |
|
1013 |
+}; |
|
1014 |
+ |
|
1015 |
+AVFilter ff_vf_oscilloscope = { |
|
1016 |
+ .name = "oscilloscope", |
|
1017 |
+ .description = NULL_IF_CONFIG_SMALL("2D Video Oscilloscope."), |
|
1018 |
+ .priv_size = sizeof(OscilloscopeContext), |
|
1019 |
+ .priv_class = &oscilloscope_class, |
|
1020 |
+ .query_formats = query_formats, |
|
1021 |
+ .uninit = oscilloscope_uninit, |
|
1022 |
+ .inputs = oscilloscope_inputs, |
|
1023 |
+ .outputs = oscilloscope_outputs, |
|
1024 |
+}; |