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