]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_rgb.h
* ./modules/video_chroma/i420_rgb.h: fixed slanted picture output with odd
[vlc] / modules / video_chroma / i420_rgb.h
1 /*****************************************************************************
2  * i420_rgb.h : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  * $Id: i420_rgb.h,v 1.3 2002/11/26 20:04:33 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * chroma_sys_t: chroma method descriptor
26  *****************************************************************************
27  * This structure is part of the chroma transformation descriptor, it
28  * describes the yuv2rgb specific properties.
29  *****************************************************************************/
30 struct chroma_sys_t
31 {
32     u8  *p_buffer;
33     int *p_offset;
34
35 #ifdef MODULE_NAME_IS_i420_rgb
36     /* Pre-calculated conversion tables */
37     void *p_base;                          /* base for all conversion tables */
38     u8   *p_rgb8;                                        /* RGB 8 bits table */
39     u16  *p_rgb16;                                      /* RGB 16 bits table */
40     u32  *p_rgb32;                                      /* RGB 32 bits table */
41 #endif
42 };
43
44 /*****************************************************************************
45  * Prototypes
46  *****************************************************************************/
47 #ifdef MODULE_NAME_IS_i420_rgb
48 void E_(I420_RGB8)         ( vout_thread_t *, picture_t *, picture_t * );
49 void E_(I420_RGB16_dither) ( vout_thread_t *, picture_t *, picture_t * );
50 #endif
51 void E_(I420_RGB16)        ( vout_thread_t *, picture_t *, picture_t * );
52 void E_(I420_RGB32)        ( vout_thread_t *, picture_t *, picture_t * );
53
54 /*****************************************************************************
55  * CONVERT_*_PIXEL: pixel conversion macros
56  *****************************************************************************
57  * These conversion routines are used by YUV conversion functions.
58  * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
59  * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
60  * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
61  *****************************************************************************/
62 #define CONVERT_Y_PIXEL( BPP )                                                \
63     /* Only Y sample is present */                                            \
64     p_ybase = p_yuv + *p_y++;                                                 \
65     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] |     \
66         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT)       \
67         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
68
69 #define CONVERT_YUV_PIXEL( BPP )                                              \
70     /* Y, U and V samples are present */                                      \
71     i_uval =    *p_u++;                                                       \
72     i_vval =    *p_v++;                                                       \
73     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
74     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
75     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
76     CONVERT_Y_PIXEL( BPP )                                                    \
77
78 #define CONVERT_Y_PIXEL_DITHER( BPP )                                         \
79     /* Only Y sample is present */                                            \
80     p_ybase = p_yuv + *p_y++;                                                 \
81     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128+p_dither[i_real_y])>>SHIFT) + i_red] |     \
82         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128+p_dither[i_real_y])>>SHIFT)       \
83         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128+p_dither[i_real_y])>>SHIFT) + i_blue];
84
85 #define CONVERT_YUV_PIXEL_DITHER( BPP )                                       \
86     /* Y, U and V samples are present */                                      \
87     i_uval =    *p_u++;                                                       \
88     i_vval =    *p_v++;                                                       \
89     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
90     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
91     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
92     CONVERT_Y_PIXEL_DITHER( BPP )                                             \
93
94 #define CONVERT_4YUV_PIXEL( CHROMA )                                          \
95     *p_pic++ = p_lookup[                                                      \
96         (((*p_y++ + dither10[i_real_y]) >> 4) << 7)                           \
97       + ((*p_u + dither20[i_real_y]) >> 5) * 9                                \
98       + ((*p_v + dither20[i_real_y]) >> 5) ];                                 \
99     *p_pic++ = p_lookup[                                                      \
100         (((*p_y++ + dither11[i_real_y]) >> 4) << 7)                           \
101       + ((*p_u++ + dither21[i_real_y]) >> 5) * 9                              \
102       + ((*p_v++ + dither21[i_real_y]) >> 5) ];                               \
103     *p_pic++ = p_lookup[                                                      \
104         (((*p_y++ + dither12[i_real_y]) >> 4) << 7)                           \
105       + ((*p_u + dither22[i_real_y]) >> 5) * 9                                \
106       + ((*p_v + dither22[i_real_y]) >> 5) ];                                 \
107     *p_pic++ = p_lookup[                                                      \
108         (((*p_y++ + dither13[i_real_y]) >> 4) << 7)                           \
109       + ((*p_u++ + dither23[i_real_y]) >> 5) * 9                              \
110       + ((*p_v++ + dither23[i_real_y]) >> 5) ];                               \
111
112 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                    \
113     *p_pic++ = p_lookup[                                                      \
114         ( ((*p_y + dither10[i_real_y]) >> 4) << 7)                            \
115         + ((*p_u + dither20[i_real_y]) >> 5) * 9                              \
116         + ((*p_v + dither20[i_real_y]) >> 5) ];                               \
117     p_y += *p_offset++;                                                       \
118     p_u += *p_offset;                                                         \
119     p_v += *p_offset++;                                                       \
120     *p_pic++ = p_lookup[                                                      \
121         ( ((*p_y + dither11[i_real_y]) >> 4) << 7)                            \
122         + ((*p_u + dither21[i_real_y]) >> 5) * 9                              \
123         + ((*p_v + dither21[i_real_y]) >> 5) ];                               \
124     p_y += *p_offset++;                                                       \
125     p_u += *p_offset;                                                         \
126     p_v += *p_offset++;                                                       \
127     *p_pic++ = p_lookup[                                                      \
128         ( ((*p_y + dither12[i_real_y]) >> 4) << 7)                            \
129         + ((*p_u + dither22[i_real_y]) >> 5) * 9                              \
130         + ((*p_v + dither22[i_real_y]) >> 5) ];                               \
131     p_y += *p_offset++;                                                       \
132     p_u += *p_offset;                                                         \
133     p_v += *p_offset++;                                                       \
134     *p_pic++ = p_lookup[                                                      \
135         ( ((*p_y + dither13[i_real_y]) >> 4) << 7)                            \
136         + ((*p_u + dither23[i_real_y]) >> 5) * 9                              \
137         + ((*p_v + dither23[i_real_y]) >> 5) ];                               \
138     p_y += *p_offset++;                                                       \
139     p_u += *p_offset;                                                         \
140     p_v += *p_offset++;                                                       \
141
142 /*****************************************************************************
143  * SCALE_WIDTH: scale a line horizontally
144  *****************************************************************************
145  * This macro scales a line using rendering buffer and offset array. It works
146  * for 1, 2 and 4 Bpp.
147  *****************************************************************************/
148 #define SCALE_WIDTH                                                           \
149     if( b_hscale )                                                            \
150     {                                                                         \
151         /* Horizontal scaling, conversion has been done to buffer.            \
152          * Rewind buffer and offset, then copy and scale line */              \
153         p_buffer = p_buffer_start;                                            \
154         p_offset = p_offset_start;                                            \
155         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
156         {                                                                     \
157             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
158             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
159             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
160             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
161             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
162             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
163             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
164             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
165             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
166             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
167             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
168             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
169             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
170             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
171             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
172             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
173         }                                                                     \
174         for( i_x = p_vout->output.i_width & 15; i_x--; )                      \
175         {                                                                     \
176             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
177         }                                                                     \
178         (u8*)p_pic += i_right_margin;                                         \
179     }                                                                         \
180     else                                                                      \
181     {                                                                         \
182         /* No scaling, conversion has been done directly in picture memory.   \
183          * Increment of picture pointer to end of line is still needed */     \
184         (u8*)p_pic += p_dest->p->i_pitch;                                     \
185     }                                                                         \
186
187 /*****************************************************************************
188  * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
189  *****************************************************************************
190  * This macro scales a line using an offset array.
191  *****************************************************************************/
192 #define SCALE_WIDTH_DITHER( CHROMA )                                          \
193     if( b_hscale )                                                            \
194     {                                                                         \
195         /* Horizontal scaling - we can't use a buffer due to dithering */     \
196         p_offset = p_offset_start;                                            \
197         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
198         {                                                                     \
199             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
200             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
201             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
202             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
203         }                                                                     \
204     }                                                                         \
205     else                                                                      \
206     {                                                                         \
207         for( i_x = p_vout->render.i_width / 16; i_x--;  )                     \
208         {                                                                     \
209             CONVERT_4YUV_PIXEL( CHROMA )                                      \
210             CONVERT_4YUV_PIXEL( CHROMA )                                      \
211             CONVERT_4YUV_PIXEL( CHROMA )                                      \
212             CONVERT_4YUV_PIXEL( CHROMA )                                      \
213         }                                                                     \
214     }                                                                         \
215     /* Increment of picture pointer to end of line is still needed */         \
216     (u8*)p_pic += i_right_margin;                                             \
217                                                                               \
218     /* Increment the Y coordinate in the matrix, modulo 4 */                  \
219     i_real_y = (i_real_y + 1) & 0x3;                                          \
220
221 /*****************************************************************************
222  * SCALE_HEIGHT: handle vertical scaling
223  *****************************************************************************
224  * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
225  * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
226  * and 4 Bpp.
227  *****************************************************************************/
228 #define SCALE_HEIGHT( CHROMA, BPP )                                           \
229     /* If line is odd, rewind 4:2:0 U and V samples */                        \
230     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
231     {                                                                         \
232         p_u -= i_chroma_width;                                                \
233         p_v -= i_chroma_width;                                                \
234     }                                                                         \
235                                                                               \
236     /*                                                                        \
237      * Handle vertical scaling. The current line can be copied or next one    \
238      * can be ignored.                                                        \
239      */                                                                       \
240     switch( i_vscale )                                                        \
241     {                                                                         \
242     case -1:                             /* vertical scaling factor is < 1 */ \
243         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
244         {                                                                     \
245             /* Height reduction: skip next source line */                     \
246             p_y += p_vout->render.i_width;                                    \
247             i_y++;                                                            \
248             if( (CHROMA == 420) || (CHROMA == 422) )                          \
249             {                                                                 \
250                 if( i_y & 0x1 )                                               \
251                 {                                                             \
252                     p_u += i_chroma_width;                                    \
253                     p_v += i_chroma_width;                                    \
254                 }                                                             \
255             }                                                                 \
256             else if( CHROMA == 444 )                                          \
257             {                                                                 \
258                 p_u += p_vout->render.i_width;                                \
259                 p_v += p_vout->render.i_width;                                \
260             }                                                                 \
261         }                                                                     \
262         i_scale_count += p_vout->render.i_height;                             \
263         break;                                                                \
264     case 1:                              /* vertical scaling factor is > 1 */ \
265         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
266         {                                                                     \
267             /* Height increment: copy previous picture line */                \
268             p_vout->p_vlc->pf_memcpy( p_pic, p_pic_start,                     \
269                                       p_vout->output.i_width * BPP );         \
270             (u8*)p_pic += p_dest->p->i_pitch;                                 \
271         }                                                                     \
272         i_scale_count += p_vout->output.i_height;                             \
273         break;                                                                \
274     }                                                                         \
275
276 /*****************************************************************************
277  * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
278  *****************************************************************************
279  * This macro handles vertical scaling for a picture. CHROMA may be 420,
280  * 422 or 444 for RGB conversion, or 400 for gray conversion.
281  *****************************************************************************/
282 #define SCALE_HEIGHT_DITHER( CHROMA )                                         \
283                                                                               \
284     /* If line is odd, rewind 4:2:0 U and V samples */                        \
285     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
286     {                                                                         \
287         p_u -= i_chroma_width;                                                \
288         p_v -= i_chroma_width;                                                \
289     }                                                                         \
290                                                                               \
291     /*                                                                        \
292      * Handle vertical scaling. The current line can be copied or next one    \
293      * can be ignored.                                                        \
294      */                                                                       \
295                                                                               \
296     switch( i_vscale )                                                        \
297     {                                                                         \
298     case -1:                             /* vertical scaling factor is < 1 */ \
299         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
300         {                                                                     \
301             /* Height reduction: skip next source line */                     \
302             p_y += p_vout->render.i_width;                                    \
303             i_y++;                                                            \
304             if( (CHROMA == 420) || (CHROMA == 422) )                          \
305             {                                                                 \
306                 if( i_y & 0x1 )                                               \
307                 {                                                             \
308                     p_u += i_chroma_width;                                    \
309                     p_v += i_chroma_width;                                    \
310                 }                                                             \
311             }                                                                 \
312             else if( CHROMA == 444 )                                          \
313             {                                                                 \
314                 p_u += p_vout->render.i_width;                                \
315                 p_v += p_vout->render.i_width;                                \
316             }                                                                 \
317         }                                                                     \
318         i_scale_count += p_vout->render.i_height;                             \
319         break;                                                                \
320     case 1:                              /* vertical scaling factor is > 1 */ \
321         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
322         {                                                                     \
323             p_y -= p_vout->render.i_width;                                    \
324             p_u -= i_chroma_width;                                            \
325             p_v -= i_chroma_width;                                            \
326             SCALE_WIDTH_DITHER( CHROMA );                                     \
327         }                                                                     \
328         i_scale_count += p_vout->output.i_height;                             \
329         break;                                                                \
330     }                                                                         \
331