]> git.sesse.net Git - x264/blob - common/visualize.c
remove unused tables from SPS/PPS. reduces overhead when syncing threads.
[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  * Motion vectors have black dot at their target (ie. at the MB center),
31  * instead of arrowhead. The black dot is enclosed in filled diamond with radius
32  * depending on reference frame number (one frame back = zero width, normal case).
33  *
34  * The intra blocks have generally lines drawn perpendicular
35  * to the prediction direction, so for example, if there is a pink block
36  * with horizontal line at the top of it, it is interpolated by assuming
37  * luma to be vertically constant.
38  * DC predicted blocks have both horizontal and vertical lines,
39  * pink blocks with a diagonal line are predicted using the planar function.
40  */
41
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>
44 #else
45 #include <inttypes.h>
46 #endif
47 #include <stddef.h>                 /* NULL */
48 #include <stdio.h>                  /* getchar */
49
50 #include "common.h"
51 #include "visualize.h"
52 #include "macroblock.h"
53 #include "display.h"
54
55 typedef struct {
56     int     i_type;
57     int     i_partition;
58     int     i_sub_partition[4];
59     int     i_intra16x16_pred_mode;
60     int     intra4x4_pred_mode[4][4];
61     int8_t  ref[2][4][4];                  /* [list][y][x] */
62     int16_t mv[2][4][4][2];                /* [list][y][x][mvxy] */
63 } visualize_t;
64
65 /* {{{ [fold] char *get_string(const stringlist_t *sl, int entries, int code) */
66 /* Return string from stringlist corresponding to the given code */
67 #define GET_STRING(sl, code) get_string((sl), sizeof(sl)/sizeof(*(sl)), code)
68
69 typedef struct {
70     int code;
71     char *string;
72 } stringlist_t;
73
74 static char *get_string(const stringlist_t *sl, int entries, int code)
75 {
76     int i;
77
78     for (i=0; i<entries; i++) {
79         if (sl[i].code==code) break;
80     }
81     return (i>=entries) ? "?" : sl[i].string;
82 }
83 /* }}} */
84 /* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col) */
85 /* Plot motion vector */
86 static void mv(int x0, int y0, int16_t dmv[2], int ref, int zoom, char *col)
87 {
88     int dx = dmv[0];
89     int dy = dmv[1];
90     int i;
91
92     dx = (dx * zoom + 2) >> 2;                     /* Quarter pixel accurate MVs */
93     dy = (dy * zoom + 2) >> 2;
94     disp_line(0, x0, y0, x0+dx, y0+dy);
95     for (i=1; i<ref; i++){
96         disp_line(0, x0, y0-i, x0+i, y0);
97         disp_line(0, x0+i, y0, x0, y0+i);
98         disp_line(0, x0, y0+i, x0-i, y0);
99         disp_line(0, x0-i, y0, x0, y0-i);
100     }
101     disp_setcolor("black");
102     disp_point(0, x0, y0);
103     disp_setcolor(col);
104 }
105 /* }}} */
106
107 /* {{{ [fold] void x264_visualize_init( x264_t *h ) */
108 void x264_visualize_init( x264_t *h )
109 {
110     int mb = h->sps->i_mb_width * h->sps->i_mb_height;
111     h->visualize = x264_malloc(mb * sizeof(visualize_t));
112 }
113 /* }}} */
114 /* {{{ [fold] void x264_visualize_mb( x264_t *h ) */
115 void x264_visualize_mb( x264_t *h )
116 {
117     visualize_t *v = (visualize_t*)h->visualize + h->mb.i_mb_xy;
118     int i, l, x, y;
119
120     /* Save all data for the MB what we need for drawing the visualization */
121     v->i_type = h->mb.i_type;
122     v->i_partition = h->mb.i_partition;
123     for (i=0; i<4; i++) v->i_sub_partition[i] = h->mb.i_sub_partition[i];
124     for (y=0; y<4; y++) for (x=0; x<4; x++)
125         v->intra4x4_pred_mode[y][x] = h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+y*8+x];
126     for (l=0; l<2; l++) for (y=0; y<4; y++) for (x=0; x<4; x++) {
127         for (i=0; i<2; i++) {
128             v->mv[l][y][x][i] = h->mb.cache.mv[l][X264_SCAN8_0+y*8+x][i];
129         }
130         v->ref[l][y][x] = h->mb.cache.ref[l][X264_SCAN8_0+y*8+x];
131     }
132     v->i_intra16x16_pred_mode = h->mb.i_intra16x16_pred_mode;
133 }
134 /* }}} */
135 /* {{{ [fold] void x264_visualize_close( x264_t *h ) */
136 void x264_visualize_close( x264_t *h )
137 {
138     x264_free(h->visualize);
139 }
140 /* }}} */
141 /* {{{ [fold] void x264_visualize_show( x264_t *h ) */
142 /* Display visualization (block types, MVs) of the encoded frame */
143 /* FIXME: B-type MBs not handled yet properly */
144 void x264_visualize_show( x264_t *h )
145 {
146     int mb_xy;
147     static const stringlist_t mb_types[] = {
148         /* Block types marked as NULL will not be drawn */
149         { I_4x4   , "red" },
150         { I_8x8   , "#ff5640" },
151         { I_16x16 , "#ff8060" },
152         { I_PCM   , "violet" },
153         { P_L0    , "SlateBlue" },
154         { P_8x8   , "blue" },
155         { P_SKIP  , "green" },
156         { B_DIRECT, "yellow" },
157         { B_L0_L0 , "yellow" },
158         { B_L0_L1 , "yellow" },
159         { B_L0_BI , "yellow" },
160         { B_L1_L0 , "yellow" },
161         { B_L1_L1 , "yellow" },
162         { B_L1_BI , "yellow" },
163         { B_BI_L0 , "yellow" },
164         { B_BI_L1 , "yellow" },
165         { B_BI_BI , "yellow" },
166         { B_8x8   , "yellow" },
167         { B_SKIP  , "yellow" },
168     };
169
170     static const int waitkey = 1;     /* Wait for enter after each frame */
171     static const int drawbox = 1;     /* Draw box around each block */
172     static const int borders = 0;     /* Display extrapolated borders outside frame */
173     static const int zoom = 2;        /* Zoom factor */
174
175     static const int pad = 32;
176     uint8_t *const frame = h->fdec->plane[0];
177     const int width = h->param.i_width;
178     const int height = h->param.i_height;
179     const int stride = h->fdec->i_stride[0];
180
181     if (borders) {
182         disp_gray_zoom(0, frame - pad*stride - pad, width+2*pad, height+2*pad, stride, "fdec", zoom);
183     } else {
184         disp_gray_zoom(0, frame, width, height, stride, "fdec", zoom);
185     }
186
187     for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
188     {
189         visualize_t *const v = (visualize_t*)h->visualize + mb_xy;
190         const int mb_y = mb_xy / h->sps->i_mb_width;
191         const int mb_x = mb_xy % h->sps->i_mb_width;
192         char *const col = GET_STRING(mb_types, v->i_type);
193         int x = mb_x*16*zoom;
194         int y = mb_y*16*zoom;
195         int l = 0;
196         unsigned int i, j;
197
198         if (col==NULL) continue;
199         if (borders) {
200             x += pad*zoom;
201             y += pad*zoom;
202         }
203         disp_setcolor(col);
204         if (drawbox) disp_rect(0, x, y, x+16*zoom-1, y+16*zoom-1);
205
206         if (v->i_type==P_L0 || v->i_type==P_8x8 || v->i_type==P_SKIP) {
207
208             /* Predicted (inter) mode, with motion vector */
209             if (v->i_partition==D_16x16 || v->i_type==P_SKIP) {
210                 mv(x+8*zoom, y+8*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
211             }
212             if (v->i_partition==D_16x8) {
213                 if (drawbox) disp_rect(0, x, y, x+16*zoom, y+8*zoom);
214                 mv(x+8*zoom, y+4*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
215                 if (drawbox) disp_rect(0, x, y+8*zoom, x+16*zoom, y+16*zoom);
216                 mv(x+8*zoom, y+12*zoom, v->mv[l][2][0], v->ref[l][2][0], zoom, col);
217             }
218             if (v->i_partition==D_8x16) {
219                 if (drawbox) disp_rect(0, x,          y, x+8*zoom,  y+16*zoom);
220                 mv(x+4*zoom, y+8*zoom, v->mv[l][0][0], v->ref[l][0][0], zoom, col);
221                 if (drawbox) disp_rect(0, x+8*zoom,   y, x+16*zoom, y+16*zoom);
222                 mv(x+12*zoom, y+8*zoom, v->mv[l][0][2], v->ref[l][0][2], zoom, col);
223             }
224             if (v->i_partition==D_8x8) {
225                 for (i=0; i<2; i++) for (j=0; j<2; j++) {
226                     int sp = v->i_sub_partition[i*2+j];
227                     const int x0 = x + j*8*zoom;
228                     const int y0 = y + i*8*zoom;
229                     l = x264_mb_partition_listX_table[0][sp] ? 0 : 1; /* FIXME: not tested if this works */
230                     if (IS_SUB8x8(sp)) {
231                         if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+8*zoom);
232                         mv(x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
233                     }
234                     if (IS_SUB8x4(sp)) {
235                         if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+4*zoom);
236                         if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+8*zoom, y0+8*zoom);
237                         mv(x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
238                         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);
239                     }
240                     if (IS_SUB4x8(sp)) {
241                         if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+8*zoom);
242                         if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+8*zoom);
243                         mv(x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
244                         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);
245                     }
246                     if (IS_SUB4x4(sp)) {
247                         if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
248                         if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+4*zoom);
249                         if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+4*zoom, y0+8*zoom);
250                         if (drawbox) disp_rect(0, x0+4*zoom, y0+4*zoom, x0+8*zoom, y0+8*zoom);
251                         mv(x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], v->ref[l][2*i][2*j], zoom, col);
252                         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);
253                         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);
254                         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);
255                     }
256                 }
257             }
258         }
259
260         if (IS_INTRA(v->i_type) || v->i_type==I_PCM) {
261             /* Intra coded */
262             if (v->i_type==I_16x16) {
263                 switch (v->i_intra16x16_pred_mode) {
264                 case I_PRED_16x16_V:
265                     disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
266                     break;
267                 case I_PRED_16x16_H:
268                     disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
269                     break;
270                 case I_PRED_16x16_DC:
271                 case I_PRED_16x16_DC_LEFT:
272                 case I_PRED_16x16_DC_TOP:
273                 case I_PRED_16x16_DC_128:
274                     disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
275                     disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
276                     break;
277                 case I_PRED_16x16_P:
278                     disp_line(0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom);
279                     break;
280                 }
281             }
282             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 (i=0; i<4; i+=di) for (j=0; j<4; j+=di) {
286                     const int x0 = x + j*4*zoom;
287                     const int y0 = y + i*4*zoom;
288                     if (drawbox) disp_rect(0, x0, y0, x0+4*zoom2, y0+4*zoom2);
289                     switch (v->intra4x4_pred_mode[i][j]) {
290                     case I_PRED_4x4_V:          /* Vertical */
291                         disp_line(0, x0+0*zoom2, y0+1*zoom2, x0+4*zoom2, y0+1*zoom2);
292                         break;
293                     case I_PRED_4x4_H:          /* Horizontal */
294                         disp_line(0, x0+1*zoom2, y0+0*zoom2, x0+1*zoom2, y0+4*zoom2);
295                         break;
296                     case I_PRED_4x4_DC:         /* DC, average from top and left sides */
297                     case I_PRED_4x4_DC_LEFT:
298                     case I_PRED_4x4_DC_TOP:
299                     case I_PRED_4x4_DC_128:
300                         disp_line(0, x0+1*zoom2, y0+1*zoom2, x0+4*zoom2, y0+1*zoom2);
301                         disp_line(0, x0+1*zoom2, y0+1*zoom2, x0+1*zoom2, y0+4*zoom2);
302                         break;
303                     case I_PRED_4x4_DDL:        /* Topright-bottomleft */
304                         disp_line(0, x0+0*zoom2, y0+0*zoom2, x0+4*zoom2, y0+4*zoom2);
305                         break;
306                     case I_PRED_4x4_DDR:        /* Topleft-bottomright */
307                         disp_line(0, x0+0*zoom2, y0+4*zoom2, x0+4*zoom2, y0+0*zoom2);
308                         break;
309                     case I_PRED_4x4_VR:         /* Mix of topleft-bottomright and vertical */
310                         disp_line(0, x0+0*zoom2, y0+2*zoom2, x0+4*zoom2, y0+1*zoom2);
311                         break;
312                     case I_PRED_4x4_HD:         /* Mix of topleft-bottomright and horizontal */
313                         disp_line(0, x0+2*zoom2, y0+0*zoom2, x0+1*zoom2, y0+4*zoom2);
314                         break;
315                     case I_PRED_4x4_VL:         /* Mix of topright-bottomleft and vertical */
316                         disp_line(0, x0+0*zoom2, y0+1*zoom2, x0+4*zoom2, y0+2*zoom2);
317                         break;
318                     case I_PRED_4x4_HU:         /* Mix of topright-bottomleft and horizontal */
319                         disp_line(0, x0+1*zoom2, y0+0*zoom2, x0+2*zoom2, y0+4*zoom2);
320                         break;
321                     }
322                 }
323             }
324         }
325     }
326
327     disp_sync();
328     if (waitkey) getchar();
329 }
330 /* }}} */
331
332 //EOF