[x264-devel] Re: patch: visualization for X11

Tuukka Toivonen tuukkat at ee.oulu.fi
Fri May 13 14:51:36 CEST 2005


On Thu, 12 May 2005, Loren Merritt wrote:

> On Thu, 12 May 2005, Tuukka Toivonen wrote:
>> I made a visualization tool for x264 to help debugging.
> Applied, along with a CLI option for it.

Huh. You guys are so fast. Just a few hours, and not only was it applied
but improved as well :)

I made some changes, here's the list (patch attached):
- Reference frame number is now also visualized
- Fixed some bugs
- Fixed some comments

It would be also nice to be able to pass parameters for the visualization,
to change zoom or which blocks to draw, maybe as --visualize <string>,
but I'll leave that for another time.

> Just for the sake of consistency, I think it would be better to use the same 
> colorscheme as ffmpeg's visualization.

Tried that... but it doesn't quite work out as ffmpeg (mplayer actually, 
but I suppose it's the same) uses the colors differently.
Besides, I'm not even sure what colors ffmpeg uses, but seems to be
these:
http://www.ee.oulu.fi/~tuukkat/tmp/ffmpeg-vis.png

But the colors are so dull that they don't look very well
when drawn over the frame, as in x264 now:
http://www.ee.oulu.fi/~tuukkat/tmp/x264-vis-ffmpeg-colorscheme.png

I also tried using strong green for inter blocks (which is now
used for skip blocks) but even that was more difficult to see than
blue.

So... I didn't change the colors. You may, if you wish, here's
the colors I tried to make emulate ffmpeg:

/* ffmpeg/mplayer colorscheme
         { I_4x4   , "#da688f" },
         { I_16x16 , "#b46ce2" },
         { I_PCM   , "violet" },
         { P_L0    , "#4bba5c" },
         { P_8x8   , "#4bba5c" },
         { P_SKIP  , "blue" },
         { B_DIRECT, "#8a600f" },
         { B_L0_L0 , "#8a600f" },
         { B_L0_L1 , "#8a600f" },
         { B_L0_BI , "#8a600f" },
         { B_L1_L0 , "#8a600f" },
         { B_L1_L1 , "#8a600f" },
         { B_L1_BI , "#8a600f" },
         { B_BI_L0 , "#8a600f" },
         { B_BI_L1 , "#8a600f" },
         { B_BI_BI , "#8a600f" },
         { B_8x8   , "#8a600f" },
         { B_SKIP  , "#004f65" },

The current color scheme is designed like this:
- Strong red for blocks which take lotsa bits (inter)
- Green for nice blocks that take least bits (skip)
- Blue is well visible, so it for some of the most common blocks (inter)
- Stronger blue for smaller inter partitions (as they take more bits)
-------------- next part --------------
Index: common/visualize.c
===================================================================
--- common/visualize.c	(revision 228)
+++ common/visualize.c	(working copy)
@@ -27,6 +27,10 @@
  * Green: skip block
  * Yellow: B-block (not visualized properly yet)
  *
+ * Motion vectors have black dot at their target (ie. at the MB center),
+ * instead of arrowhead. The black dot is enclosed in filled diamond with radius
+ * depending on reference frame number (one frame back = zero width, normal case).
+ *
  * The intra blocks have generally lines drawn perpendicular
  * to the prediction direction, so for example, if there is a pink block
  * with horizontal line at the top of it, it is interpolated by assuming
@@ -42,7 +46,6 @@
 #endif
 #include <stddef.h>                 /* NULL */
 #include <stdio.h>                  /* getchar */
-#include <stdlib.h>                 /* abort */
 
 #include "common.h"
 #include "visualize.h"
@@ -78,16 +81,23 @@
     return (i>=entries) ? "?" : sl[i].string;
 }
 /* }}} */
-/* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col) */
+/* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col) */
 /* Plot motion vector */
-static void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col)
+static void mv(int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col)
 {
     int dx = dmv[0];
     int dy = dmv[1];
+    int i;
 
-    dx = (dx*zoom)/4;           /* Quarter pixel accurate MVs */
-    dy = (dy*zoom)/4;
+    dx = (dx * zoom + 2) >> 2;                     /* Quarter pixel accurate MVs */
+    dy = (dy * zoom + 2) >> 2;
     disp_line(0, x0, y0, x0+dx, y0+dy);
+    for (i=1; i<ref; i++){
+        disp_line(0, x0, y0-i, x0+i, y0);
+        disp_line(0, x0+i, y0, x0, y0+i);
+        disp_line(0, x0, y0+i, x0-i, y0);
+        disp_line(0, x0-i, y0, x0, y0-i);
+    }
     disp_setcolor("black");
     disp_point(0, x0, y0);
     disp_setcolor(col);
@@ -117,7 +127,7 @@
         for (i=0; i<2; i++) {
             v->mv[l][y][x][i] = h->mb.cache.mv[l][X264_SCAN8_0+y*8+x][i];
         }
-        v->ref[l][y][x] = h->mb.cache.ref[i][X264_SCAN8_0+y*8+x];
+        v->ref[l][y][x] = h->mb.cache.ref[l][X264_SCAN8_0+y*8+x];
     }
     v->i_intra16x16_pred_mode = h->mb.i_intra16x16_pred_mode;
 }
@@ -128,10 +138,9 @@
     x264_free(h->visualize);
 }
 /* }}} */
-/* {{{ [fold] void x264_visualize( x264_t *h ) */
+/* {{{ [fold] void x264_visualize_show( x264_t *h ) */
 /* Display visualization (block types, MVs) of the encoded frame */
-/* FIXME: B-type MBs not handled yet properly
- * Reference frame number not visualized */
+/* FIXME: B-type MBs not handled yet properly */
 void x264_visualize_show( x264_t *h )
 {
     int mb_xy;
@@ -157,12 +166,12 @@
         { B_SKIP  , "yellow" },
     };
 
-    static const int waitkey = 1;
-    static const int drawbox = 1;
-    static const int borders = 0;
+    static const int waitkey = 1;     /* Wait for enter after each frame */
+    static const int drawbox = 1;     /* Draw box around each block */
+    static const int borders = 0;     /* Display extrapolated borders outside frame */
+    static const int zoom = 2;        /* Zoom factor */
 
     static const int pad = 32;
-    static const int zoom = 2;
     uint8_t *const frame = h->fdec->plane[0];
     const int width = h->param.i_width;
     const int height = h->param.i_height;
@@ -176,19 +185,20 @@
 
     for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
     {
-        visualize_t *v = (visualize_t*)h->visualize + mb_xy;
+        visualize_t *const v = (visualize_t*)h->visualize + mb_xy;
         const int mb_y = mb_xy / h->sps->i_mb_width;
         const int mb_x = mb_xy % h->sps->i_mb_width;
+        char *const col = GET_STRING(mb_types, v->i_type);
         int x = mb_x*16*zoom;
         int y = mb_y*16*zoom;
+        int l = 0;
+        unsigned int i, j;
+
+        if (col==NULL) continue;
         if (borders) {
             x += pad*zoom;
             y += pad*zoom;
         }
-        int l = 0;
-        char *col = GET_STRING(mb_types, v->i_type);
-        unsigned int i, j;
-        if (col==NULL) continue;
         disp_setcolor(col);
         if (drawbox) disp_rect(0, x, y, x+16*zoom-1, y+16*zoom-1);
 
@@ -196,54 +206,54 @@
 
             /* Predicted (inter) mode, with motion vector */
             if (v->i_partition==D_16x16 || v->i_type==P_SKIP) {
-                mv(x+8*zoom, y+8*zoom, v->mv[l][0][0], zoom, col);
+                mv(x+8*zoom, y+8*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
             }
             if (v->i_partition==D_16x8) {
                 if (drawbox) disp_rect(0, x, y, x+16*zoom, y+8*zoom);
-                mv(x+8*zoom, y+4*zoom, v->mv[l][0][0], zoom, col);
+                mv(x+8*zoom, y+4*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
                 if (drawbox) disp_rect(0, x, y+8*zoom, x+16*zoom, y+16*zoom);
-                mv(x+8*zoom, y+12*zoom, v->mv[l][2][0], zoom, col);
+                mv(x+8*zoom, y+12*zoom, v->mv[l][2][0], v->ref[l][2][0], zoom, col);
             }
             if (v->i_partition==D_8x16) {
                 if (drawbox) disp_rect(0, x,          y, x+8*zoom,  y+16*zoom);
-                mv(x+4*zoom, y+8*zoom, v->mv[l][0][0], zoom, col);
+                mv(x+4*zoom, y+8*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
                 if (drawbox) disp_rect(0, x+8*zoom,   y, x+16*zoom, y+16*zoom);
-                mv(x+12*zoom, y+8*zoom, v->mv[l][0][2], zoom, col);
+                mv(x+12*zoom, y+8*zoom, v->mv[l][0][2], v->ref[l][0][2], zoom, col);
             }
             if (v->i_partition==D_8x8) {
                 for (i=0; i<2; i++) for (j=0; j<2; j++) {
                     int sp = v->i_sub_partition[i*2+j];
                     const int x0 = x + j*8*zoom;
                     const int y0 = y + i*8*zoom;
-                    if (sp==D_L1_8x8) sp = D_L0_8x8;
-                    if (sp==D_L1_4x8) sp = D_L0_4x8;
-                    if (sp==D_L1_8x4) sp = D_L0_8x4;
-                    if (sp==D_L1_4x4) sp = D_L0_4x4;
+                    if (sp==D_L1_8x8) { sp = D_L0_8x8; l = 1; }                  /* FIXME: not tested if this works */
+                    if (sp==D_L1_4x8) { sp = D_L0_4x8; l = 1; }
+                    if (sp==D_L1_8x4) { sp = D_L0_8x4; l = 1; }
+                    if (sp==D_L1_4x4) { sp = D_L0_4x4; l = 1; }
                     if (sp==D_L0_8x8) {
                         if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+8*zoom);
-                        mv(x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
+                        mv(x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
                     }
                     if (sp==D_L0_8x4) {
                         if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+4*zoom);
                         if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+8*zoom, y0+8*zoom);
-                        mv(x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
-                        mv(x0+4*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
+                        mv(x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
+                        mv(x0+4*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], v->ref[l][2*i+1][2*j], zoom, col);
                     }
                     if (sp==D_L0_4x8) {
                         if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+8*zoom);
                         if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+8*zoom);
-                        mv(x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
-                        mv(x0+6*zoom, y0+4*zoom, v->mv[l][2*i][2*j+1], zoom, col);
+                        mv(x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+4*zoom, v->mv[l][2*i][2*j+1], v->ref[l][2*i][2*j+1], zoom, col);
                     }
                     if (sp==D_L0_4x4) {
                         if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
                         if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+4*zoom);
                         if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+4*zoom, y0+8*zoom);
                         if (drawbox) disp_rect(0, x0+4*zoom, y0+4*zoom, x0+8*zoom, y0+8*zoom);
-                        mv(x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
-                        mv(x0+6*zoom, y0+2*zoom, v->mv[l][2*i][2*j+1], zoom, col);
-                        mv(x0+2*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
-                        mv(x0+6*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j+1], zoom, col);
+                        mv(x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+2*zoom, v->mv[l][2*i][2*j+1], v->ref[l][2*i][2*j+1], zoom, col);
+                        mv(x0+2*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], v->ref[l][2*i+1][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j+1], v->ref[l][2*i+1][2*j+1], zoom, col);
                     }
                 }
             }
@@ -269,7 +279,6 @@
                 case I_PRED_16x16_P:
                     disp_line(0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom);
                     break;
-                default: abort();
                 }
             }
             if (v->i_type==I_4x4) {
@@ -291,25 +300,24 @@
                         disp_line(0, x0+1*zoom, y0+1*zoom, x0+4*zoom, y0+1*zoom);
                         disp_line(0, x0+1*zoom, y0+1*zoom, x0+1*zoom, y0+4*zoom);
                         break;
-                    case I_PRED_4x4_DDL:	/* Topright-downleft */
+                    case I_PRED_4x4_DDL:	/* Topright-bottomleft */
                         disp_line(0, x0+0*zoom, y0+0*zoom, x0+4*zoom, y0+4*zoom);
                         break;
-                    case I_PRED_4x4_DDR:	/* Topleft-downright */
+                    case I_PRED_4x4_DDR:	/* Topleft-bottomright */
                         disp_line(0, x0+0*zoom, y0+4*zoom, x0+4*zoom, y0+0*zoom);
                         break;
-                    case I_PRED_4x4_VR:		/* Mix of topleft-downright and vertical */
+                    case I_PRED_4x4_VR:		/* Mix of topleft-bottomright and vertical */
                         disp_line(0, x0+0*zoom, y0+2*zoom, x0+4*zoom, y0+1*zoom);
                         break;
-                    case I_PRED_4x4_HD:		/* Mix of topleft-downright and horizontal */
+                    case I_PRED_4x4_HD:		/* Mix of topleft-bottomright and horizontal */
                         disp_line(0, x0+2*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
                         break;
-                    case I_PRED_4x4_VL:		/* Mix of topright-downleft and vertical */
+                    case I_PRED_4x4_VL:		/* Mix of topright-bottomleft and vertical */
                         disp_line(0, x0+0*zoom, y0+1*zoom, x0+4*zoom, y0+2*zoom);
                         break;
-                    case I_PRED_4x4_HU:		/* Mix of topright-downleft and horizontal */
+                    case I_PRED_4x4_HU:		/* Mix of topright-bottomleft and horizontal */
                         disp_line(0, x0+1*zoom, y0+0*zoom, x0+2*zoom, y0+4*zoom);
                         break;
-                    default: abort();
                     }
                 }
             }


More information about the x264-devel mailing list