1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2005 Tuukka Toivonen <tuukkat@ee.oulu.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
19 *****************************************************************************/
22 * Some explanation of the symbols used:
23 * Red/pink: intra block
26 * Yellow: B-block (not visualized properly yet)
28 * Motion vectors have black dot at their target (ie. at the MB center),
29 * instead of arrowhead. The black dot is enclosed in filled diamond with radius
30 * depending on reference frame number (one frame back = zero width, normal case).
32 * The intra blocks have generally lines drawn perpendicular
33 * to the prediction direction, so for example, if there is a pink block
34 * with horizontal line at the top of it, it is interpolated by assuming
35 * luma to be vertically constant.
36 * DC predicted blocks have both horizontal and vertical lines,
37 * pink blocks with a diagonal line are predicted using the planar function.
41 #include "visualize.h"
47 int i_sub_partition
[4];
48 int i_intra16x16_pred_mode
;
49 int intra4x4_pred_mode
[4][4];
50 int8_t ref
[2][4][4]; /* [list][y][x] */
51 int16_t mv
[2][4][4][2]; /* [list][y][x][mvxy] */
54 /* {{{ [fold] char *get_string(const stringlist_t *sl, int entries, int code) */
55 /* Return string from stringlist corresponding to the given code */
56 #define GET_STRING(sl, code) get_string((sl), sizeof(sl)/sizeof(*(sl)), code)
63 static char *get_string(const stringlist_t
*sl
, int entries
, int code
)
67 for (i
=0; i
<entries
; i
++) {
68 if (sl
[i
].code
==code
) break;
70 return (i
>=entries
) ? "?" : sl
[i
].string
;
73 /* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col) */
74 /* Plot motion vector */
75 static void mv(int x0
, int y0
, int16_t dmv
[2], int ref
, int zoom
, char *col
)
81 dx
= (dx
* zoom
+ 2) >> 2; /* Quarter pixel accurate MVs */
82 dy
= (dy
* zoom
+ 2) >> 2;
83 disp_line(0, x0
, y0
, x0
+dx
, y0
+dy
);
84 for (i
=1; i
<ref
; i
++){
85 disp_line(0, x0
, y0
-i
, x0
+i
, y0
);
86 disp_line(0, x0
+i
, y0
, x0
, y0
+i
);
87 disp_line(0, x0
, y0
+i
, x0
-i
, y0
);
88 disp_line(0, x0
-i
, y0
, x0
, y0
-i
);
90 disp_setcolor("black");
91 disp_point(0, x0
, y0
);
96 /* {{{ [fold] void x264_visualize_init( x264_t *h ) */
97 void x264_visualize_init( x264_t
*h
)
99 int mb
= h
->sps
->i_mb_width
* h
->sps
->i_mb_height
;
100 h
->visualize
= x264_malloc(mb
* sizeof(visualize_t
));
103 /* {{{ [fold] void x264_visualize_mb( x264_t *h ) */
104 void x264_visualize_mb( x264_t
*h
)
106 visualize_t
*v
= (visualize_t
*)h
->visualize
+ h
->mb
.i_mb_xy
;
109 /* Save all data for the MB what we need for drawing the visualization */
110 v
->i_type
= h
->mb
.i_type
;
111 v
->i_partition
= h
->mb
.i_partition
;
112 for (i
=0; i
<4; i
++) v
->i_sub_partition
[i
] = h
->mb
.i_sub_partition
[i
];
113 for (y
=0; y
<4; y
++) for (x
=0; x
<4; x
++)
114 v
->intra4x4_pred_mode
[y
][x
] = h
->mb
.cache
.intra4x4_pred_mode
[X264_SCAN8_0
+y
*8+x
];
115 for (l
=0; l
<2; l
++) for (y
=0; y
<4; y
++) for (x
=0; x
<4; x
++) {
116 for (i
=0; i
<2; i
++) {
117 v
->mv
[l
][y
][x
][i
] = h
->mb
.cache
.mv
[l
][X264_SCAN8_0
+y
*8+x
][i
];
119 v
->ref
[l
][y
][x
] = h
->mb
.cache
.ref
[l
][X264_SCAN8_0
+y
*8+x
];
121 v
->i_intra16x16_pred_mode
= h
->mb
.i_intra16x16_pred_mode
;
124 /* {{{ [fold] void x264_visualize_close( x264_t *h ) */
125 void x264_visualize_close( x264_t
*h
)
127 x264_free(h
->visualize
);
130 /* {{{ [fold] void x264_visualize_show( x264_t *h ) */
131 /* Display visualization (block types, MVs) of the encoded frame */
132 /* FIXME: B-type MBs not handled yet properly */
133 void x264_visualize_show( x264_t
*h
)
136 static const stringlist_t mb_types
[] = {
137 /* Block types marked as NULL will not be drawn */
139 { I_8x8
, "#ff5640" },
140 { I_16x16
, "#ff8060" },
141 { I_PCM
, "violet" },
142 { P_L0
, "SlateBlue" },
144 { P_SKIP
, "green" },
145 { B_DIRECT
, "yellow" },
146 { B_L0_L0
, "yellow" },
147 { B_L0_L1
, "yellow" },
148 { B_L0_BI
, "yellow" },
149 { B_L1_L0
, "yellow" },
150 { B_L1_L1
, "yellow" },
151 { B_L1_BI
, "yellow" },
152 { B_BI_L0
, "yellow" },
153 { B_BI_L1
, "yellow" },
154 { B_BI_BI
, "yellow" },
155 { B_8x8
, "yellow" },
156 { B_SKIP
, "yellow" },
159 static const int waitkey
= 1; /* Wait for enter after each frame */
160 static const int drawbox
= 1; /* Draw box around each block */
161 static const int borders
= 0; /* Display extrapolated borders outside frame */
162 static const int zoom
= 2; /* Zoom factor */
164 static const int pad
= 32;
165 uint8_t *const frame
= h
->fdec
->plane
[0];
166 const int width
= h
->param
.i_width
;
167 const int height
= h
->param
.i_height
;
168 const int stride
= h
->fdec
->i_stride
[0];
171 disp_gray_zoom(0, frame
- pad
*stride
- pad
, width
+2*pad
, height
+2*pad
, stride
, "fdec", zoom
);
173 disp_gray_zoom(0, frame
, width
, height
, stride
, "fdec", zoom
);
176 for( mb_xy
= 0; mb_xy
< h
->sps
->i_mb_width
* h
->sps
->i_mb_height
; mb_xy
++ )
178 visualize_t
*const v
= (visualize_t
*)h
->visualize
+ mb_xy
;
179 const int mb_y
= mb_xy
/ h
->sps
->i_mb_width
;
180 const int mb_x
= mb_xy
% h
->sps
->i_mb_width
;
181 char *const col
= GET_STRING(mb_types
, v
->i_type
);
182 int x
= mb_x
*16*zoom
;
183 int y
= mb_y
*16*zoom
;
187 if (col
==NULL
) continue;
193 if (drawbox
) disp_rect(0, x
, y
, x
+16*zoom
-1, y
+16*zoom
-1);
195 if (v
->i_type
==P_L0
|| v
->i_type
==P_8x8
|| v
->i_type
==P_SKIP
) {
197 /* Predicted (inter) mode, with motion vector */
198 if (v
->i_partition
==D_16x16
|| v
->i_type
==P_SKIP
) {
199 mv(x
+8*zoom
, y
+8*zoom
, v
->mv
[l
][0][0], v
->ref
[l
][0][0], zoom
, col
);
201 if (v
->i_partition
==D_16x8
) {
202 if (drawbox
) disp_rect(0, x
, y
, x
+16*zoom
, y
+8*zoom
);
203 mv(x
+8*zoom
, y
+4*zoom
, v
->mv
[l
][0][0], v
->ref
[l
][0][0], zoom
, col
);
204 if (drawbox
) disp_rect(0, x
, y
+8*zoom
, x
+16*zoom
, y
+16*zoom
);
205 mv(x
+8*zoom
, y
+12*zoom
, v
->mv
[l
][2][0], v
->ref
[l
][2][0], zoom
, col
);
207 if (v
->i_partition
==D_8x16
) {
208 if (drawbox
) disp_rect(0, x
, y
, x
+8*zoom
, y
+16*zoom
);
209 mv(x
+4*zoom
, y
+8*zoom
, v
->mv
[l
][0][0], v
->ref
[l
][0][0], zoom
, col
);
210 if (drawbox
) disp_rect(0, x
+8*zoom
, y
, x
+16*zoom
, y
+16*zoom
);
211 mv(x
+12*zoom
, y
+8*zoom
, v
->mv
[l
][0][2], v
->ref
[l
][0][2], zoom
, col
);
213 if (v
->i_partition
==D_8x8
) {
214 for (i
=0; i
<2; i
++) for (j
=0; j
<2; j
++) {
215 int sp
= v
->i_sub_partition
[i
*2+j
];
216 const int x0
= x
+ j
*8*zoom
;
217 const int y0
= y
+ i
*8*zoom
;
218 l
= x264_mb_partition_listX_table
[0][sp
] ? 0 : 1; /* FIXME: not tested if this works */
220 if (drawbox
) disp_rect(0, x0
, y0
, x0
+8*zoom
, y0
+8*zoom
);
221 mv(x0
+4*zoom
, y0
+4*zoom
, v
->mv
[l
][2*i
][2*j
], v
->ref
[l
][2*i
][2*j
], zoom
, col
);
224 if (drawbox
) disp_rect(0, x0
, y0
, x0
+8*zoom
, y0
+4*zoom
);
225 if (drawbox
) disp_rect(0, x0
, y0
+4*zoom
, x0
+8*zoom
, y0
+8*zoom
);
226 mv(x0
+4*zoom
, y0
+2*zoom
, v
->mv
[l
][2*i
][2*j
], v
->ref
[l
][2*i
][2*j
], zoom
, col
);
227 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
);
230 if (drawbox
) disp_rect(0, x0
, y0
, x0
+4*zoom
, y0
+8*zoom
);
231 if (drawbox
) disp_rect(0, x0
+4*zoom
, y0
, x0
+8*zoom
, y0
+8*zoom
);
232 mv(x0
+2*zoom
, y0
+4*zoom
, v
->mv
[l
][2*i
][2*j
], v
->ref
[l
][2*i
][2*j
], zoom
, col
);
233 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
);
236 if (drawbox
) disp_rect(0, x0
, y0
, x0
+4*zoom
, y0
+4*zoom
);
237 if (drawbox
) disp_rect(0, x0
+4*zoom
, y0
, x0
+8*zoom
, y0
+4*zoom
);
238 if (drawbox
) disp_rect(0, x0
, y0
+4*zoom
, x0
+4*zoom
, y0
+8*zoom
);
239 if (drawbox
) disp_rect(0, x0
+4*zoom
, y0
+4*zoom
, x0
+8*zoom
, y0
+8*zoom
);
240 mv(x0
+2*zoom
, y0
+2*zoom
, v
->mv
[l
][2*i
][2*j
], v
->ref
[l
][2*i
][2*j
], zoom
, col
);
241 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
);
242 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
);
243 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
);
249 if (IS_INTRA(v
->i_type
) || v
->i_type
==I_PCM
) {
251 if (v
->i_type
==I_16x16
) {
252 switch (v
->i_intra16x16_pred_mode
) {
254 disp_line(0, x
+2*zoom
, y
+2*zoom
, x
+14*zoom
, y
+2*zoom
);
257 disp_line(0, x
+2*zoom
, y
+2*zoom
, x
+2*zoom
, y
+14*zoom
);
259 case I_PRED_16x16_DC
:
260 case I_PRED_16x16_DC_LEFT
:
261 case I_PRED_16x16_DC_TOP
:
262 case I_PRED_16x16_DC_128
:
263 disp_line(0, x
+2*zoom
, y
+2*zoom
, x
+14*zoom
, y
+2*zoom
);
264 disp_line(0, x
+2*zoom
, y
+2*zoom
, x
+2*zoom
, y
+14*zoom
);
267 disp_line(0, x
+2*zoom
, y
+2*zoom
, x
+8*zoom
, y
+8*zoom
);
271 if (v
->i_type
==I_4x4
|| v
->i_type
==I_8x8
) {
272 const int di
= v
->i_type
==I_8x8
? 2 : 1;
273 const int zoom2
= zoom
* di
;
274 for (i
=0; i
<4; i
+=di
) for (j
=0; j
<4; j
+=di
) {
275 const int x0
= x
+ j
*4*zoom
;
276 const int y0
= y
+ i
*4*zoom
;
277 if (drawbox
) disp_rect(0, x0
, y0
, x0
+4*zoom2
, y0
+4*zoom2
);
278 switch (v
->intra4x4_pred_mode
[i
][j
]) {
279 case I_PRED_4x4_V
: /* Vertical */
280 disp_line(0, x0
+0*zoom2
, y0
+1*zoom2
, x0
+4*zoom2
, y0
+1*zoom2
);
282 case I_PRED_4x4_H
: /* Horizontal */
283 disp_line(0, x0
+1*zoom2
, y0
+0*zoom2
, x0
+1*zoom2
, y0
+4*zoom2
);
285 case I_PRED_4x4_DC
: /* DC, average from top and left sides */
286 case I_PRED_4x4_DC_LEFT
:
287 case I_PRED_4x4_DC_TOP
:
288 case I_PRED_4x4_DC_128
:
289 disp_line(0, x0
+1*zoom2
, y0
+1*zoom2
, x0
+4*zoom2
, y0
+1*zoom2
);
290 disp_line(0, x0
+1*zoom2
, y0
+1*zoom2
, x0
+1*zoom2
, y0
+4*zoom2
);
292 case I_PRED_4x4_DDL
: /* Topright-bottomleft */
293 disp_line(0, x0
+0*zoom2
, y0
+0*zoom2
, x0
+4*zoom2
, y0
+4*zoom2
);
295 case I_PRED_4x4_DDR
: /* Topleft-bottomright */
296 disp_line(0, x0
+0*zoom2
, y0
+4*zoom2
, x0
+4*zoom2
, y0
+0*zoom2
);
298 case I_PRED_4x4_VR
: /* Mix of topleft-bottomright and vertical */
299 disp_line(0, x0
+0*zoom2
, y0
+2*zoom2
, x0
+4*zoom2
, y0
+1*zoom2
);
301 case I_PRED_4x4_HD
: /* Mix of topleft-bottomright and horizontal */
302 disp_line(0, x0
+2*zoom2
, y0
+0*zoom2
, x0
+1*zoom2
, y0
+4*zoom2
);
304 case I_PRED_4x4_VL
: /* Mix of topright-bottomleft and vertical */
305 disp_line(0, x0
+0*zoom2
, y0
+1*zoom2
, x0
+4*zoom2
, y0
+2*zoom2
);
307 case I_PRED_4x4_HU
: /* Mix of topright-bottomleft and horizontal */
308 disp_line(0, x0
+1*zoom2
, y0
+0*zoom2
, x0
+2*zoom2
, y0
+4*zoom2
);
317 if (waitkey
) getchar();