1 /*****************************************************************************
2 * x264: visualization module
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"
48 int i_sub_partition[4];
49 int i_intra16x16_pred_mode;
50 int intra4x4_pred_mode[4][4];
51 int8_t ref[2][4][4]; /* [list][y][x] */
52 int16_t mv[2][4][4][2]; /* [list][y][x][mvxy] */
55 /* Return string from stringlist corresponding to the given code */
56 #define GET_STRING(sl, code) get_string((sl), sizeof(sl)/sizeof(*(sl)), code)
64 static char *get_string( const stringlist_t *sl, int entries, int code )
66 for( int i = 0; i < entries; i++ )
67 if( sl[i].code == code )
72 /* Plot motion vector */
73 static void mv( int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col )
78 dx = (dx * zoom + 2) >> 2;
79 dy = (dy * zoom + 2) >> 2;
80 disp_line( 0, x0, y0, x0+dx, y0+dy );
81 for( int i = 1; i < ref; i++ )
83 disp_line( 0, x0 , y0-i, x0+i, y0 );
84 disp_line( 0, x0+i, y0 , x0 , y0+i );
85 disp_line( 0, x0 , y0+i, x0-i, y0 );
86 disp_line( 0, x0-i, y0 , x0 , y0-i );
88 disp_setcolor( "black" );
89 disp_point( 0, x0, y0 );
93 int x264_visualize_init( x264_t *h )
95 CHECKED_MALLOC( h->visualize, h->sps->i_mb_width * h->sps->i_mb_height * sizeof(visualize_t) );
101 void x264_visualize_mb( x264_t *h )
103 visualize_t *v = (visualize_t*)h->visualize + h->mb.i_mb_xy;
105 /* Save all data for the MB that we need for drawing the visualization */
106 v->i_type = h->mb.i_type;
107 v->i_partition = h->mb.i_partition;
108 for( int i = 0; i < 4; i++ )
109 v->i_sub_partition[i] = h->mb.i_sub_partition[i];
110 for( int y = 0; y < 4; y++ )
111 for( int x = 0; x < 4; x++ )
112 v->intra4x4_pred_mode[y][x] = h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+y*8+x];
113 for( int l = 0; l < 2; l++ )
114 for( int y = 0; y < 4; y++ )
115 for( int x = 0; x < 4; x++ )
117 for( int i = 0; i < 2; i++ )
118 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 void x264_visualize_close( x264_t *h )
126 x264_free(h->visualize);
129 /* Display visualization (block types, MVs) of the encoded frame */
130 /* FIXME: B-type MBs not handled yet properly */
131 void x264_visualize_show( x264_t *h )
133 static const stringlist_t mb_types[] =
135 /* Block types marked as NULL will not be drawn */
137 { I_8x8 , "#ff5640" },
138 { I_16x16 , "#ff8060" },
139 { I_PCM , "violet" },
140 { P_L0 , "SlateBlue" },
142 { P_SKIP , "green" },
143 { B_DIRECT, "yellow" },
144 { B_L0_L0 , "yellow" },
145 { B_L0_L1 , "yellow" },
146 { B_L0_BI , "yellow" },
147 { B_L1_L0 , "yellow" },
148 { B_L1_L1 , "yellow" },
149 { B_L1_BI , "yellow" },
150 { B_BI_L0 , "yellow" },
151 { B_BI_L1 , "yellow" },
152 { B_BI_BI , "yellow" },
153 { B_8x8 , "yellow" },
154 { B_SKIP , "yellow" },
157 static const int waitkey = 1; /* Wait for enter after each frame */
158 static const int drawbox = 1; /* Draw box around each block */
159 static const int borders = 0; /* Display extrapolated borders outside frame */
160 static const int zoom = 2; /* Zoom factor */
162 static const int pad = 32;
163 uint8_t *const frame = h->fdec->plane[0];
164 const int width = h->param.i_width;
165 const int height = h->param.i_height;
166 const int stride = h->fdec->i_stride[0];
169 disp_gray_zoom( 0, frame - pad*stride - pad, width+2*pad, height+2*pad, stride, "fdec", zoom );
171 disp_gray_zoom( 0, frame, width, height, stride, "fdec", zoom );
173 for( int mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
175 visualize_t *const v = (visualize_t*)h->visualize + mb_xy;
176 const int mb_y = mb_xy / h->sps->i_mb_width;
177 const int mb_x = mb_xy % h->sps->i_mb_width;
178 char *const col = GET_STRING( mb_types, v->i_type );
179 int x = mb_x*16*zoom;
180 int y = mb_y*16*zoom;
192 disp_setcolor( col );
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 );
200 else 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 else if( v->i_partition==D_8x16 )
209 if( drawbox ) disp_rect( 0, x, y, x+8*zoom, y+16*zoom );
210 mv( x+4*zoom, y+8*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col );
211 if( drawbox ) disp_rect( 0, x+8*zoom, y, x+16*zoom, y+16*zoom );
212 mv( x+12*zoom, y+8*zoom, v->mv[l][0][2], v->ref[l][0][2], zoom, col );
214 else if( v->i_partition==D_8x8 )
216 for( int i = 0; i < 2; i++ )
217 for( int j = 0; j < 2; j++ )
219 int sp = v->i_sub_partition[i*2+j];
220 const int x0 = x + j*8*zoom;
221 const int y0 = y + i*8*zoom;
222 l = x264_mb_partition_listX_table[0][sp] ? 0 : 1; /* FIXME: not tested if this works */
225 if( drawbox ) disp_rect( 0, x0, y0, x0+8*zoom, y0+8*zoom );
226 mv( x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col );
228 else if( IS_SUB8x4(sp) )
230 if( drawbox ) disp_rect( 0, x0, y0, x0+8*zoom, y0+4*zoom );
231 if( drawbox ) disp_rect( 0, x0, y0+4*zoom, x0+8*zoom, y0+8*zoom );
232 mv( x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col );
233 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 );
235 else if( IS_SUB4x8(sp) )
237 if( drawbox ) disp_rect( 0, x0, y0, x0+4*zoom, y0+8*zoom );
238 if( drawbox ) disp_rect( 0, x0+4*zoom, y0, x0+8*zoom, y0+8*zoom );
239 mv( x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col );
240 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 );
242 else if( IS_SUB4x4(sp) )
244 if( drawbox ) disp_rect( 0, x0, y0, x0+4*zoom, y0+4*zoom );
245 if( drawbox ) disp_rect( 0, x0+4*zoom, y0, x0+8*zoom, y0+4*zoom );
246 if( drawbox ) disp_rect( 0, x0, y0+4*zoom, x0+4*zoom, y0+8*zoom );
247 if( drawbox ) disp_rect( 0, x0+4*zoom, y0+4*zoom, x0+8*zoom, y0+8*zoom );
248 mv( x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col );
249 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 );
250 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 );
251 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 );
257 if( IS_INTRA(v->i_type) || v->i_type == I_PCM )
260 if( v->i_type == I_16x16 )
262 switch (v->i_intra16x16_pred_mode) {
264 disp_line( 0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom );
267 disp_line( 0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom );
269 case I_PRED_16x16_DC:
270 case I_PRED_16x16_DC_LEFT:
271 case I_PRED_16x16_DC_TOP:
272 case I_PRED_16x16_DC_128:
273 disp_line( 0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom );
274 disp_line( 0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom );
277 disp_line( 0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom );
281 if( v->i_type==I_4x4 || v->i_type==I_8x8 )
283 const int di = v->i_type == I_8x8 ? 2 : 1;
284 const int zoom2 = zoom * di;
285 for( int i = 0; i < 4; i += di )
286 for( int j = 0; j < 4; j += di )
288 const int x0 = x + j*4*zoom;
289 const int y0 = y + i*4*zoom;
290 if( drawbox ) disp_rect( 0, x0, y0, x0+4*zoom2, y0+4*zoom2 );
291 switch( v->intra4x4_pred_mode[i][j] )
293 case I_PRED_4x4_V: /* Vertical */
294 disp_line( 0, x0+0*zoom2, y0+1*zoom2, x0+4*zoom2, y0+1*zoom2 );
296 case I_PRED_4x4_H: /* Horizontal */
297 disp_line( 0, x0+1*zoom2, y0+0*zoom2, x0+1*zoom2, y0+4*zoom2 );
299 case I_PRED_4x4_DC: /* DC, average from top and left sides */
300 case I_PRED_4x4_DC_LEFT:
301 case I_PRED_4x4_DC_TOP:
302 case I_PRED_4x4_DC_128:
303 disp_line( 0, x0+1*zoom2, y0+1*zoom2, x0+4*zoom2, y0+1*zoom2 );
304 disp_line( 0, x0+1*zoom2, y0+1*zoom2, x0+1*zoom2, y0+4*zoom2 );
306 case I_PRED_4x4_DDL: /* Topright-bottomleft */
307 disp_line( 0, x0+0*zoom2, y0+0*zoom2, x0+4*zoom2, y0+4*zoom2 );
309 case I_PRED_4x4_DDR: /* Topleft-bottomright */
310 disp_line( 0, x0+0*zoom2, y0+4*zoom2, x0+4*zoom2, y0+0*zoom2 );
312 case I_PRED_4x4_VR: /* Mix of topleft-bottomright and vertical */
313 disp_line( 0, x0+0*zoom2, y0+2*zoom2, x0+4*zoom2, y0+1*zoom2 );
315 case I_PRED_4x4_HD: /* Mix of topleft-bottomright and horizontal */
316 disp_line( 0, x0+2*zoom2, y0+0*zoom2, x0+1*zoom2, y0+4*zoom2 );
318 case I_PRED_4x4_VL: /* Mix of topright-bottomleft and vertical */
319 disp_line( 0, x0+0*zoom2, y0+1*zoom2, x0+4*zoom2, y0+2*zoom2 );
321 case I_PRED_4x4_HU: /* Mix of topright-bottomleft and horizontal */
322 disp_line( 0, x0+1*zoom2, y0+0*zoom2, x0+2*zoom2, y0+4*zoom2 );