Browse code

avfilter/vf_vectorscope: add graticule

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2016/02/29 19:32:17
Showing 2 changed files
... ...
@@ -12559,6 +12559,28 @@ can still spot out of range values without constantly looking at vectorscope.
12559 12559
 @item peak+instant
12560 12560
 Peak and instant envelope combined together.
12561 12561
 @end table
12562
+
12563
+@item graticule, g
12564
+Set what kind of graticule to draw.
12565
+@table @samp
12566
+@item none
12567
+@item green
12568
+@item color
12569
+@end table
12570
+
12571
+@item opacity, o
12572
+Set graticule opacity.
12573
+
12574
+@item flags, f
12575
+Set graticule flags.
12576
+
12577
+@table @samp
12578
+@item white
12579
+Draw graticule for white point.
12580
+
12581
+@item black
12582
+Draw graticule for black point.
12583
+@end table
12562 12584
 @end table
12563 12585
 
12564 12586
 @anchor{vidstabdetect}
... ...
@@ -50,12 +50,19 @@ typedef struct VectorscopeContext {
50 50
     int x, y, pd;
51 51
     int is_yuv;
52 52
     int size;
53
+    int depth;
53 54
     int mult;
54 55
     int envelope;
56
+    int graticule;
57
+    float opacity;
58
+    int flags;
59
+    int cs;
55 60
     uint8_t peak[1024][1024];
56 61
 
57 62
     void (*vectorscope)(struct VectorscopeContext *s,
58 63
                         AVFrame *in, AVFrame *out, int pd);
64
+    void (*graticulef)(struct VectorscopeContext *s, AVFrame *out,
65
+                       int X, int Y, int D, int P);
59 66
 } VectorscopeContext;
60 67
 
61 68
 #define OFFSET(x) offsetof(VectorscopeContext, x)
... ...
@@ -80,6 +87,17 @@ static const AVOption vectorscope_options[] = {
80 80
     {   "instant",      0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
81 81
     {   "peak",         0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
82 82
     {   "peak+instant", 0, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
83
+    { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule"},
84
+    { "g",         "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule"},
85
+    {   "none",         0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "graticule" },
86
+    {   "green",        0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "graticule" },
87
+    {   "color",        0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "graticule" },
88
+    { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS},
89
+    { "o",       "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS},
90
+    { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 3, FLAGS, "flags"},
91
+    { "f",     "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 3, FLAGS, "flags"},
92
+    {   "white", "draw white point", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "flags" },
93
+    {   "black", "draw black point", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
83 94
     { NULL }
84 95
 };
85 96
 
... ...
@@ -662,6 +680,228 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
662 662
     }
663 663
 }
664 664
 
665
+const static uint16_t positions[][14][3] = {
666
+  { { 210,  16, 146 }, { 170, 166,  16 }, { 145,  54,  34 },
667
+    { 106, 202, 222 }, {  81,  90, 240 }, {  41, 240, 110 },
668
+    { 162,  44, 142 }, { 131, 156,  44 }, { 112,  72,  58 },
669
+    {  84, 184, 198 }, {  65, 100, 212 }, {  35, 212, 114 },
670
+    { 235, 128, 128 }, { 16, 128, 128 } },
671
+  { {  63, 102, 240 }, {  32, 240, 118 }, { 188, 154,  16 },
672
+    { 219,  16, 138 }, { 173,  42,  26 }, {  78, 214, 230 },
673
+    {  28, 212, 120 }, {  51, 109, 212 }, {  63, 193, 204 },
674
+    { 133,  63,  52 }, { 145, 147,  44 }, { 168,  44, 136 },
675
+    { 235, 128, 128 }, { 16, 128, 128 } },
676
+  { { 210*2,  16*2, 146*2 }, { 170*2, 166*2,  16*2 }, { 145*2,  54*2,  34*2 },
677
+    { 106*2, 202*2, 222*2 }, {  81*2,  90*2, 240*2 }, {  41*2, 240*2, 110*2 },
678
+    { 162*2,  44*2, 142*2 }, { 131*2, 156*2,  44*2 }, { 112*2,  72*2,  58*2 },
679
+    {  84*2, 184*2, 198*2 }, {  65*2, 100*2, 212*2 }, {  35*2, 212*2, 114*2 },
680
+    { 470, 256, 256 }, { 32, 256, 256 } },
681
+  { {  63*2, 102*2, 240*2 }, {  32*2, 240*2, 118*2 }, { 188*2, 154*2,  16*2 },
682
+    { 219*2,  16*2, 138*2 }, { 173*2,  42*2,  26*2 }, {  78*2, 214*2, 230*2 },
683
+    {  28*2, 212*2, 120*2 }, {  51*2, 109*2, 212*2 }, {  63*2, 193*2, 204*2 },
684
+    { 133*2,  63*2,  52*2 }, { 145*2, 147*2,  44*2 }, { 168*2,  44*2, 136*2 },
685
+    { 470, 256, 256 }, { 32, 256, 256 } },
686
+  { { 210*4,  16*4, 146*4 }, { 170*4, 166*4,  16*4 }, { 145*4,  54*4,  34*4 },
687
+    { 106*4, 202*4, 222*4 }, {  81*4,  90*4, 240*4 }, {  41*4, 240*4, 110*4 },
688
+    { 162*4,  44*4, 142*4 }, { 131*4, 156*4,  44*4 }, { 112*4,  72*4,  58*4 },
689
+    {  84*4, 184*4, 198*4 }, {  65*4, 100*4, 212*4 }, {  35*4, 212*4, 114*4 },
690
+    { 940, 512, 512 }, { 64, 512, 512 } },
691
+  { {  63*4, 102*4, 240*4 }, {  32*4, 240*4, 118*4 }, { 188*4, 154*4,  16*4 },
692
+    { 219*4,  16*4, 138*4 }, { 173*4,  42*4,  26*4 }, {  78*4, 214*4, 230*4 },
693
+    {  28*4, 212*4, 120*4 }, {  51*4, 109*4, 212*4 }, {  63*4, 193*4, 204*4 },
694
+    { 133*4,  63*4,  52*4 }, { 145*4, 147*4,  44*4 }, { 168*4,  44*4, 136*4 },
695
+    { 940, 512, 512 }, { 64, 512, 512 } },
696
+};
697
+
698
+static void draw_dots(uint8_t *dst, int L, int v, float o)
699
+{
700
+    const float f = 1. - o;
701
+    const float V = o * v;
702
+    int l = L * 2;
703
+
704
+    dst[ l - 3] = dst[ l - 3] * f + V;
705
+    dst[ l + 3] = dst[ l + 3] * f + V;
706
+    dst[-l - 3] = dst[-l - 3] * f + V;
707
+    dst[-l + 3] = dst[-l + 3] * f + V;
708
+
709
+    l += L;
710
+
711
+    dst[ l - 3] = dst[ l - 3] * f + V;
712
+    dst[ l + 3] = dst[ l + 3] * f + V;
713
+    dst[ l - 2] = dst[ l - 2] * f + V;
714
+    dst[ l + 2] = dst[ l + 2] * f + V;
715
+    dst[-l - 3] = dst[-l - 3] * f + V;
716
+    dst[-l + 3] = dst[-l + 3] * f + V;
717
+    dst[-l - 2] = dst[-l - 2] * f + V;
718
+    dst[-l + 2] = dst[-l + 2] * f + V;
719
+}
720
+
721
+static void draw_dots16(uint16_t *dst, int L, int v, float o)
722
+{
723
+    const float f = 1. - o;
724
+    const float V = o * v;
725
+    int l = L * 2;
726
+
727
+    dst[ l - 3] = dst[ l - 3] * f + V;
728
+    dst[ l + 3] = dst[ l + 3] * f + V;
729
+    dst[-l - 3] = dst[-l - 3] * f + V;
730
+    dst[-l + 3] = dst[-l + 3] * f + V;
731
+
732
+    l += L;
733
+
734
+    dst[ l - 3] = dst[ l - 3] * f + V;
735
+    dst[ l + 3] = dst[ l + 3] * f + V;
736
+    dst[ l - 2] = dst[ l - 2] * f + V;
737
+    dst[ l + 2] = dst[ l + 2] * f + V;
738
+    dst[-l - 3] = dst[-l - 3] * f + V;
739
+    dst[-l + 3] = dst[-l + 3] * f + V;
740
+    dst[-l - 2] = dst[-l - 2] * f + V;
741
+    dst[-l + 2] = dst[-l + 2] * f + V;
742
+}
743
+
744
+static void none_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
745
+{
746
+}
747
+
748
+static void color_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
749
+{
750
+    const float o = s->opacity;
751
+    int i;
752
+
753
+    for (i = 0; i < 12; i++) {
754
+        int x = positions[P][i][X];
755
+        int y = positions[P][i][Y];
756
+        int d = positions[P][i][D];
757
+
758
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
759
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
760
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
761
+    }
762
+
763
+    if (s->flags & 1) {
764
+        int x = positions[P][12][X];
765
+        int y = positions[P][12][Y];
766
+        int d = positions[P][12][D];
767
+
768
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
769
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
770
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
771
+    }
772
+
773
+    if (s->flags & 2) {
774
+        int x = positions[P][13][X];
775
+        int y = positions[P][13][Y];
776
+        int d = positions[P][13][D];
777
+
778
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, d, o);
779
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, x, o);
780
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, y, o);
781
+    }
782
+}
783
+
784
+static void color_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
785
+{
786
+    const float o = s->opacity;
787
+    int i;
788
+
789
+    for (i = 0; i < 12; i++) {
790
+        int x = positions[P][i][X];
791
+        int y = positions[P][i][Y];
792
+        int d = positions[P][i][D];
793
+
794
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
795
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
796
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
797
+    }
798
+
799
+    if (s->flags & 1) {
800
+        int x = positions[P][12][X];
801
+        int y = positions[P][12][Y];
802
+        int d = positions[P][12][D];
803
+
804
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
805
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
806
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
807
+    }
808
+
809
+    if (s->flags & 2) {
810
+        int x = positions[P][13][X];
811
+        int y = positions[P][13][Y];
812
+        int d = positions[P][12][D];
813
+
814
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], d, o);
815
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], x, o);
816
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], y, o);
817
+    }
818
+}
819
+
820
+static void green_graticule16(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
821
+{
822
+    const float o = s->opacity;
823
+    const int m = s->mult;
824
+    int i;
825
+
826
+    for (i = 0; i < 12; i++) {
827
+        int x = positions[P][i][X];
828
+        int y = positions[P][i][Y];
829
+
830
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, 128 * m, o);
831
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, 0, o);
832
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, 0, o);
833
+    }
834
+
835
+    if (s->flags & 1) {
836
+        int x = positions[P][12][X];
837
+        int y = positions[P][12][Y];
838
+
839
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, 128 * m, o);
840
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, 0, o);
841
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, 0, o);
842
+    }
843
+
844
+    if (s->flags & 2) {
845
+        int x = positions[P][13][X];
846
+        int y = positions[P][13][Y];
847
+
848
+        draw_dots16((uint16_t *)(out->data[D] + y * out->linesize[D] + x * 2), out->linesize[D] / 2, 128 * m, o);
849
+        draw_dots16((uint16_t *)(out->data[X] + y * out->linesize[X] + x * 2), out->linesize[X] / 2, 0, o);
850
+        draw_dots16((uint16_t *)(out->data[Y] + y * out->linesize[Y] + x * 2), out->linesize[Y] / 2, 0, o);
851
+    }
852
+}
853
+
854
+static void green_graticule(VectorscopeContext *s, AVFrame *out, int X, int Y, int D, int P)
855
+{
856
+    const float o = s->opacity;
857
+    int i;
858
+
859
+    for (i = 0; i < 12; i++) {
860
+        int x = positions[P][i][X];
861
+        int y = positions[P][i][Y];
862
+
863
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], 128, o);
864
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], 0, o);
865
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], 0, o);
866
+    }
867
+
868
+    if (s->flags & 1) {
869
+        int x = positions[P][12][X];
870
+        int y = positions[P][12][Y];
871
+
872
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], 128, o);
873
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], 0, o);
874
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], 0, o);
875
+    }
876
+
877
+    if (s->flags & 2) {
878
+        int x = positions[P][13][X];
879
+        int y = positions[P][13][Y];
880
+
881
+        draw_dots(out->data[D] + y * out->linesize[D] + x, out->linesize[D], 128, o);
882
+        draw_dots(out->data[X] + y * out->linesize[X] + x, out->linesize[X], 0, o);
883
+        draw_dots(out->data[Y] + y * out->linesize[Y] + x, out->linesize[Y], 0, o);
884
+    }
885
+}
886
+
665 887
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
666 888
 {
667 889
     AVFilterContext *ctx  = inlink->dst;
... ...
@@ -669,6 +909,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
669 669
     AVFilterLink *outlink = ctx->outputs[0];
670 670
     AVFrame *out;
671 671
 
672
+    switch (av_frame_get_colorspace(in)) {
673
+    case AVCOL_SPC_SMPTE170M:
674
+    case AVCOL_SPC_BT470BG:
675
+        s->cs = (s->depth - 8) * 2 + 0;
676
+        break;
677
+    case AVCOL_SPC_BT709:
678
+    default:
679
+        s->cs = (s->depth - 8) * 2 + 1;
680
+    }
681
+
672 682
     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
673 683
     if (!out) {
674 684
         av_frame_free(&in);
... ...
@@ -677,6 +927,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
677 677
     out->pts = in->pts;
678 678
 
679 679
     s->vectorscope(s, in, out, s->pd);
680
+    s->graticulef(s, out, s->x, s->y, s->pd, s->cs);
680 681
 
681 682
     av_frame_free(&in);
682 683
     return ff_filter_frame(outlink, out);
... ...
@@ -690,6 +941,7 @@ static int config_input(AVFilterLink *inlink)
690 690
     s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB);
691 691
     s->size = 1 << desc->comp[0].depth;
692 692
     s->mult = s->size / 256;
693
+    s->depth = desc->comp[0].depth;
693 694
 
694 695
     if (s->mode == GRAY && s->is_yuv)
695 696
         s->pd = 0;
... ...
@@ -707,6 +959,20 @@ static int config_input(AVFilterLink *inlink)
707 707
     else
708 708
         s->vectorscope = vectorscope16;
709 709
 
710
+    s->graticulef = none_graticule;
711
+
712
+    if (s->is_yuv && s->size == 256) {
713
+        if (s->graticule == 1)
714
+            s->graticulef = green_graticule;
715
+        else if (s->graticule == 2)
716
+            s->graticulef = color_graticule;
717
+    } else if (s->is_yuv) {
718
+        if (s->graticule == 1)
719
+            s->graticulef = green_graticule16;
720
+        else if (s->graticule == 2)
721
+            s->graticulef = color_graticule16;
722
+    }
723
+
710 724
     switch (inlink->format) {
711 725
     case AV_PIX_FMT_GBRP10:
712 726
     case AV_PIX_FMT_GBRP9: