]> git.sesse.net Git - x264/blob - common/visualize.c
CLI option: --visualize
[x264] / common / visualize.c
1 /*****************************************************************************
2  * x264: h264 encoder
3  *****************************************************************************
4  * Copyright (C) 2005 x264 project
5  *
6  * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*
24  * Some explanation of the symbols used:
25  * Red/pink: intra block
26  * Blue: inter block
27  * Green: skip block
28  * Yellow: B-block (not visualized properly yet)
29  *
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.
36  */
37
38 #ifdef HAVE_STDINT_H
39 #include <stdint.h>
40 #else
41 #include <inttypes.h>
42 #endif
43 #include <stddef.h>                 /* NULL */
44 #include <stdio.h>                  /* getchar */
45 #include <stdlib.h>                 /* abort */
46
47 #include "common.h"
48 #include "visualize.h"
49 #include "macroblock.h"
50 #include "display.h"
51
52 typedef struct {
53     int     i_type;
54     int     i_partition;
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] */
60 } visualize_t;
61
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)
65
66 typedef struct {
67     int code;
68     char *string;
69 } stringlist_t;
70
71 static char *get_string(const stringlist_t *sl, int entries, int code)
72 {
73     int i;
74
75     for (i=0; i<entries; i++) {
76         if (sl[i].code==code) break;
77     }
78     return (i>=entries) ? "?" : sl[i].string;
79 }
80 /* }}} */
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)
84 {
85     int dx = dmv[0];
86     int dy = dmv[1];
87
88     dx = (dx*zoom)/4;           /* Quarter pixel accurate MVs */
89     dy = (dy*zoom)/4;
90     disp_line(0, x0, y0, x0+dx, y0+dy);
91     disp_setcolor("black");
92     disp_point(0, x0, y0);
93     disp_setcolor(col);
94 }
95 /* }}} */
96
97 /* {{{ [fold] void x264_visualize_init( x264_t *h ) */
98 void x264_visualize_init( x264_t *h )
99 {
100     int mb = h->sps->i_mb_width * h->sps->i_mb_height;
101     h->visualize = x264_malloc(mb * sizeof(visualize_t));
102 }
103 /* }}} */
104 /* {{{ [fold] void x264_visualize_mb( x264_t *h ) */
105 void x264_visualize_mb( x264_t *h )
106 {
107     visualize_t *v = (visualize_t*)h->visualize + h->mb.i_mb_xy;
108     int i, l, x, y;
109
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];
119         }
120         v->ref[l][y][x] = h->mb.cache.ref[i][X264_SCAN8_0+y*8+x];
121     }
122     v->i_intra16x16_pred_mode = h->mb.i_intra16x16_pred_mode;
123 }
124 /* }}} */
125 /* {{{ [fold] void x264_visualize_close( x264_t *h ) */
126 void x264_visualize_close( x264_t *h )
127 {
128     x264_free(h->visualize);
129 }
130 /* }}} */
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 )
136 {
137     int mb_xy;
138     static const stringlist_t mb_types[] = {
139         /* Block types marked as NULL will not be drawn */
140         { I_4x4   , "red" },
141         { I_16x16 , "pink" },
142         { I_PCM   , "violet" },
143         { P_L0    , "SlateBlue" },
144         { P_8x8   , "blue" },
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" },
158     };
159
160     static const int waitkey = 1;
161     static const int drawbox = 1;
162     static const int borders = 0;
163
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];
170
171     if (borders) {
172         disp_gray_zoom(0, frame - pad*stride - pad, width+2*pad, height+2*pad, stride, "fdec", zoom);
173     } else {
174         disp_gray_zoom(0, frame, width, height, stride, "fdec", zoom);
175     }
176
177     for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
178     {
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;
184         if (borders) {
185             x += pad*zoom;
186             y += pad*zoom;
187         }
188         int l = 0;
189         char *col = GET_STRING(mb_types, v->i_type);
190         unsigned int i, j;
191         if (col==NULL) continue;
192         disp_setcolor(col);
193         if (drawbox) disp_rect(0, x, y, x+16*zoom-1, y+16*zoom-1);
194
195         if (v->i_type==P_L0 || v->i_type==P_8x8 || v->i_type==P_SKIP) {
196
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);
200             }
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);
206             }
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);
212             }
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;
222                     if (sp==D_L0_8x8) {
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);
225                     }
226                     if (sp==D_L0_8x4) {
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);
231                     }
232                     if (sp==D_L0_4x8) {
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);
237                     }
238                     if (sp==D_L0_4x4) {
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);
247                     }
248                 }
249             }
250         }
251
252         if (v->i_type==I_4x4 || v->i_type==I_16x16 || v->i_type==I_PCM) {
253             /* Intra coded */
254             if (v->i_type==I_16x16) {
255                 switch (v->i_intra16x16_pred_mode) {
256                 case I_PRED_16x16_V:
257                     disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
258                     break;
259                 case I_PRED_16x16_H:
260                     disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
261                     break;
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);
268                     break;
269                 case I_PRED_16x16_P:
270                     disp_line(0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom);
271                     break;
272                 default: abort();
273                 }
274             }
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);
283                         break;
284                     case I_PRED_4x4_H:          /* Horizontal */
285                         disp_line(0, x0+1*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
286                         break;
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);
293                         break;
294                     case I_PRED_4x4_DDL:        /* Topright-downleft */
295                         disp_line(0, x0+0*zoom, y0+0*zoom, x0+4*zoom, y0+4*zoom);
296                         break;
297                     case I_PRED_4x4_DDR:        /* Topleft-downright */
298                         disp_line(0, x0+0*zoom, y0+4*zoom, x0+4*zoom, y0+0*zoom);
299                         break;
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);
302                         break;
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);
305                         break;
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);
308                         break;
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);
311                         break;
312                     default: abort();
313                     }
314                 }
315             }
316         }
317     }
318
319     disp_sync();
320     if (waitkey) getchar();
321 }
322 /* }}} */
323
324 //EOF