1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2005 x264 project
6 * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
24 * Some explanation of the symbols used:
25 * Red/pink: intra block
28 * Yellow: B-block (not visualized properly yet)
30 * The intra blocks have generally lines drawn perpendicular
31 * to the prediction direction, so for example, if there is a pink block
32 * with horizontal line at the top of it, it is interpolated by assuming
33 * luma to be vertically constant.
34 * DC predicted blocks have both horizontal and vertical lines,
35 * pink blocks with a diagonal line are predicted using the planar function.
43 #include <stddef.h> /* NULL */
44 #include <stdio.h> /* getchar */
45 #include <stdlib.h> /* abort */
48 #include "visualize.h"
49 #include "macroblock.h"
55 int i_sub_partition[4];
56 int i_intra16x16_pred_mode;
57 int intra4x4_pred_mode[4][4];
58 int8_t ref[2][4][4]; /* [list][y][x] */
59 int16_t mv[2][4][4][2]; /* [list][y][x][mvxy] */
62 /* {{{ [fold] char *get_string(const stringlist_t *sl, int entries, int code) */
63 /* Return string from stringlist corresponding to the given code */
64 #define GET_STRING(sl, code) get_string((sl), sizeof(sl)/sizeof(*(sl)), code)
71 static char *get_string(const stringlist_t *sl, int entries, int code)
75 for (i=0; i<entries; i++) {
76 if (sl[i].code==code) break;
78 return (i>=entries) ? "?" : sl[i].string;
81 /* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col) */
82 /* Plot motion vector */
83 static void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col)
88 dx = (dx*zoom)/4; /* Quarter pixel accurate MVs */
90 disp_line(0, x0, y0, x0+dx, y0+dy);
91 disp_setcolor("black");
92 disp_point(0, x0, y0);
97 /* {{{ [fold] void x264_visualize_init( x264_t *h ) */
98 void x264_visualize_init( x264_t *h )
100 int mb = h->sps->i_mb_width * h->sps->i_mb_height;
101 h->visualize = x264_malloc(mb * sizeof(visualize_t));
104 /* {{{ [fold] void x264_visualize_mb( x264_t *h ) */
105 void x264_visualize_mb( x264_t *h )
107 visualize_t *v = (visualize_t*)h->visualize + h->mb.i_mb_xy;
110 /* Save all data for the MB what we need for drawing the visualization */
111 v->i_type = h->mb.i_type;
112 v->i_partition = h->mb.i_partition;
113 for (i=0; i<4; i++) v->i_sub_partition[i] = h->mb.i_sub_partition[i];
114 for (y=0; y<4; y++) for (x=0; x<4; x++)
115 v->intra4x4_pred_mode[y][x] = h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+y*8+x];
116 for (l=0; l<2; l++) for (y=0; y<4; y++) for (x=0; x<4; x++) {
117 for (i=0; i<2; i++) {
118 v->mv[l][y][x][i] = h->mb.cache.mv[l][X264_SCAN8_0+y*8+x][i];
120 v->ref[l][y][x] = h->mb.cache.ref[i][X264_SCAN8_0+y*8+x];
122 v->i_intra16x16_pred_mode = h->mb.i_intra16x16_pred_mode;
125 /* {{{ [fold] void x264_visualize_close( x264_t *h ) */
126 void x264_visualize_close( x264_t *h )
128 x264_free(h->visualize);
131 /* {{{ [fold] void x264_visualize( x264_t *h ) */
132 /* Display visualization (block types, MVs) of the encoded frame */
133 /* FIXME: B-type MBs not handled yet properly
134 * Reference frame number not visualized */
135 void x264_visualize_show( x264_t *h )
138 static const stringlist_t mb_types[] = {
139 /* Block types marked as NULL will not be drawn */
141 { I_16x16 , "pink" },
142 { I_PCM , "violet" },
143 { P_L0 , "SlateBlue" },
145 { P_SKIP , "green" },
146 { B_DIRECT, "yellow" },
147 { B_L0_L0 , "yellow" },
148 { B_L0_L1 , "yellow" },
149 { B_L0_BI , "yellow" },
150 { B_L1_L0 , "yellow" },
151 { B_L1_L1 , "yellow" },
152 { B_L1_BI , "yellow" },
153 { B_BI_L0 , "yellow" },
154 { B_BI_L1 , "yellow" },
155 { B_BI_BI , "yellow" },
156 { B_8x8 , "yellow" },
157 { B_SKIP , "yellow" },
160 static const int waitkey = 1;
161 static const int drawbox = 1;
162 static const int borders = 0;
164 static const int pad = 32;
165 static const int zoom = 2;
166 uint8_t *const frame = h->fdec->plane[0];
167 const int width = h->param.i_width;
168 const int height = h->param.i_height;
169 const int stride = h->fdec->i_stride[0];
172 disp_gray_zoom(0, frame - pad*stride - pad, width+2*pad, height+2*pad, stride, "fdec", zoom);
174 disp_gray_zoom(0, frame, width, height, stride, "fdec", zoom);
177 for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
179 visualize_t *v = (visualize_t*)h->visualize + mb_xy;
180 const int mb_y = mb_xy / h->sps->i_mb_width;
181 const int mb_x = mb_xy % h->sps->i_mb_width;
182 int x = mb_x*16*zoom;
183 int y = mb_y*16*zoom;
189 char *col = GET_STRING(mb_types, v->i_type);
191 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], 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], 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], 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], 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], 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 if (sp==D_L1_8x8) sp = D_L0_8x8;
219 if (sp==D_L1_4x8) sp = D_L0_4x8;
220 if (sp==D_L1_8x4) sp = D_L0_8x4;
221 if (sp==D_L1_4x4) sp = D_L0_4x4;
223 if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+8*zoom);
224 mv(x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
227 if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+4*zoom);
228 if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+8*zoom, y0+8*zoom);
229 mv(x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
230 mv(x0+4*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
233 if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+8*zoom);
234 if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+8*zoom);
235 mv(x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
236 mv(x0+6*zoom, y0+4*zoom, v->mv[l][2*i][2*j+1], zoom, col);
239 if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
240 if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+4*zoom);
241 if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+4*zoom, y0+8*zoom);
242 if (drawbox) disp_rect(0, x0+4*zoom, y0+4*zoom, x0+8*zoom, y0+8*zoom);
243 mv(x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
244 mv(x0+6*zoom, y0+2*zoom, v->mv[l][2*i][2*j+1], zoom, col);
245 mv(x0+2*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
246 mv(x0+6*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j+1], zoom, col);
252 if (v->i_type==I_4x4 || v->i_type==I_16x16 || v->i_type==I_PCM) {
254 if (v->i_type==I_16x16) {
255 switch (v->i_intra16x16_pred_mode) {
257 disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
260 disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
262 case I_PRED_16x16_DC:
263 case I_PRED_16x16_DC_LEFT:
264 case I_PRED_16x16_DC_TOP:
265 case I_PRED_16x16_DC_128:
266 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);
270 disp_line(0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom);
275 if (v->i_type==I_4x4) {
276 for (i=0; i<4; i++) for (j=0; j<4; j++) {
277 const int x0 = x + j*4*zoom;
278 const int y0 = y + i*4*zoom;
279 if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
280 switch (v->intra4x4_pred_mode[i][j]) {
281 case I_PRED_4x4_V: /* Vertical */
282 disp_line(0, x0+0*zoom, y0+1*zoom, x0+4*zoom, y0+1*zoom);
284 case I_PRED_4x4_H: /* Horizontal */
285 disp_line(0, x0+1*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
287 case I_PRED_4x4_DC: /* DC, average from top and left sides */
288 case I_PRED_4x4_DC_LEFT:
289 case I_PRED_4x4_DC_TOP:
290 case I_PRED_4x4_DC_128:
291 disp_line(0, x0+1*zoom, y0+1*zoom, x0+4*zoom, y0+1*zoom);
292 disp_line(0, x0+1*zoom, y0+1*zoom, x0+1*zoom, y0+4*zoom);
294 case I_PRED_4x4_DDL: /* Topright-downleft */
295 disp_line(0, x0+0*zoom, y0+0*zoom, x0+4*zoom, y0+4*zoom);
297 case I_PRED_4x4_DDR: /* Topleft-downright */
298 disp_line(0, x0+0*zoom, y0+4*zoom, x0+4*zoom, y0+0*zoom);
300 case I_PRED_4x4_VR: /* Mix of topleft-downright and vertical */
301 disp_line(0, x0+0*zoom, y0+2*zoom, x0+4*zoom, y0+1*zoom);
303 case I_PRED_4x4_HD: /* Mix of topleft-downright and horizontal */
304 disp_line(0, x0+2*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
306 case I_PRED_4x4_VL: /* Mix of topright-downleft and vertical */
307 disp_line(0, x0+0*zoom, y0+1*zoom, x0+4*zoom, y0+2*zoom);
309 case I_PRED_4x4_HU: /* Mix of topright-downleft and horizontal */
310 disp_line(0, x0+1*zoom, y0+0*zoom, x0+2*zoom, y0+4*zoom);
320 if (waitkey) getchar();