]> git.sesse.net Git - vlc/blob - plugins/chroma/i420_rgb.h
7871ef9d9bfda090a5ec3220ad42046343e3e9c1
[vlc] / plugins / 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.4 2002/03/16 23:03:19 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 typedef struct chroma_sys_s
31 {
32     u8  *p_buffer;
33     int *p_offset;
34
35 #ifdef MODULE_NAME_IS_chroma_i420_rgb
36     /* Pre-calculated conversion tables */
37     void *              p_base;            /* base for all conversion tables */
38     union
39     {
40         u8 *            p_rgb8;                          /* RGB 8 bits table */
41         u16 *           p_rgb16;                        /* RGB 16 bits table */
42         u32 *           p_rgb32;                        /* RGB 32 bits table */
43     } yuv;
44 #endif
45
46 } chroma_sys_t;
47
48 /*****************************************************************************
49  * Prototypes
50  *****************************************************************************/
51 #ifdef MODULE_NAME_IS_chroma_i420_rgb
52 void _M( I420_RGB8 ) ( vout_thread_t *, picture_t *, picture_t * );
53 #endif
54 void _M( I420_RGB15 )( vout_thread_t *, picture_t *, picture_t * );
55 void _M( I420_RGB16 )( vout_thread_t *, picture_t *, picture_t * );
56 void _M( I420_RGB32 )( vout_thread_t *, picture_t *, picture_t * );
57
58 /*****************************************************************************
59  * CONVERT_*_PIXEL: pixel conversion macros
60  *****************************************************************************
61  * These conversion routines are used by YUV conversion functions.
62  * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
63  * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
64  * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
65  *****************************************************************************/
66 #define CONVERT_Y_PIXEL( BPP )                                                \
67     /* Only Y sample is present */                                            \
68     p_ybase = p_yuv + *p_y++;                                                 \
69     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] |     \
70         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT)       \
71         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
72
73 #define CONVERT_YUV_PIXEL( BPP )                                              \
74     /* Y, U and V samples are present */                                      \
75     i_uval =    *p_u++;                                                       \
76     i_vval =    *p_v++;                                                       \
77     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
78     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
79     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
80     CONVERT_Y_PIXEL( BPP )                                                    \
81
82 #define CONVERT_4YUV_PIXEL( CHROMA )                                          \
83     *p_pic++ = p_lookup[                                                      \
84         (((*p_y++ + dither10[i_real_y]) >> 4) << 7)                           \
85       + ((*p_u + dither20[i_real_y]) >> 5) * 9                                \
86       + ((*p_v + dither20[i_real_y]) >> 5) ];                                 \
87     *p_pic++ = p_lookup[                                                      \
88         (((*p_y++ + dither11[i_real_y]) >> 4) << 7)                           \
89       + ((*p_u++ + dither21[i_real_y]) >> 5) * 9                              \
90       + ((*p_v++ + dither21[i_real_y]) >> 5) ];                               \
91     *p_pic++ = p_lookup[                                                      \
92         (((*p_y++ + dither12[i_real_y]) >> 4) << 7)                           \
93       + ((*p_u + dither22[i_real_y]) >> 5) * 9                                \
94       + ((*p_v + dither22[i_real_y]) >> 5) ];                                 \
95     *p_pic++ = p_lookup[                                                      \
96         (((*p_y++ + dither13[i_real_y]) >> 4) << 7)                           \
97       + ((*p_u++ + dither23[i_real_y]) >> 5) * 9                              \
98       + ((*p_v++ + dither23[i_real_y]) >> 5) ];                               \
99
100 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                    \
101     *p_pic++ = p_lookup[                                                      \
102         ( ((*p_y + dither10[i_real_y]) >> 4) << 7)                            \
103         + ((*p_u + dither20[i_real_y]) >> 5) * 9                              \
104         + ((*p_v + dither20[i_real_y]) >> 5) ];                               \
105     p_y += *p_offset++;                                                       \
106     p_u += *p_offset;                                                         \
107     p_v += *p_offset++;                                                       \
108     *p_pic++ = p_lookup[                                                      \
109         ( ((*p_y + dither11[i_real_y]) >> 4) << 7)                            \
110         + ((*p_u + dither21[i_real_y]) >> 5) * 9                              \
111         + ((*p_v + dither21[i_real_y]) >> 5) ];                               \
112     p_y += *p_offset++;                                                       \
113     p_u += *p_offset;                                                         \
114     p_v += *p_offset++;                                                       \
115     *p_pic++ = p_lookup[                                                      \
116         ( ((*p_y + dither12[i_real_y]) >> 4) << 7)                            \
117         + ((*p_u + dither22[i_real_y]) >> 5) * 9                              \
118         + ((*p_v + dither22[i_real_y]) >> 5) ];                               \
119     p_y += *p_offset++;                                                       \
120     p_u += *p_offset;                                                         \
121     p_v += *p_offset++;                                                       \
122     *p_pic++ = p_lookup[                                                      \
123         ( ((*p_y + dither13[i_real_y]) >> 4) << 7)                            \
124         + ((*p_u + dither23[i_real_y]) >> 5) * 9                              \
125         + ((*p_v + dither23[i_real_y]) >> 5) ];                               \
126     p_y += *p_offset++;                                                       \
127     p_u += *p_offset;                                                         \
128     p_v += *p_offset++;                                                       \
129
130 /*****************************************************************************
131  * SCALE_WIDTH: scale a line horizontally
132  *****************************************************************************
133  * This macro scales a line using rendering buffer and offset array. It works
134  * for 1, 2 and 4 Bpp.
135  *****************************************************************************/
136 #define SCALE_WIDTH                                                           \
137     if( b_hscale )                                                            \
138     {                                                                         \
139         /* Horizontal scaling, conversion has been done to buffer.            \
140          * Rewind buffer and offset, then copy and scale line */              \
141         p_buffer = p_buffer_start;                                            \
142         p_offset = p_offset_start;                                            \
143         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
144         {                                                                     \
145             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
146             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
147             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
148             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
149             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
150             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
151             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
152             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
153             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
154             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
155             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
156             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
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         }                                                                     \
162         for( i_x = p_vout->output.i_width & 15; i_x--; )                      \
163         {                                                                     \
164             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
165         }                                                                     \
166         p_pic += i_right_margin;                                              \
167     }                                                                         \
168     else                                                                      \
169     {                                                                         \
170         /* No scaling, conversion has been done directly in picture memory.   \
171          * Increment of picture pointer to end of line is still needed */     \
172         (u8*)p_pic += p_dest->p->i_pitch;                                     \
173     }                                                                         \
174
175 /*****************************************************************************
176  * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
177  *****************************************************************************
178  * This macro scales a line using an offset array.
179  *****************************************************************************/
180 #define SCALE_WIDTH_DITHER( CHROMA )                                          \
181     if( b_hscale )                                                            \
182     {                                                                         \
183         /* Horizontal scaling - we can't use a buffer due to dithering */     \
184         p_offset = p_offset_start;                                            \
185         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
186         {                                                                     \
187             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
188             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
189             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
190             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
191         }                                                                     \
192     }                                                                         \
193     else                                                                      \
194     {                                                                         \
195         for( i_x = p_vout->render.i_width / 16; i_x--;  )                     \
196         {                                                                     \
197             CONVERT_4YUV_PIXEL( CHROMA )                                      \
198             CONVERT_4YUV_PIXEL( CHROMA )                                      \
199             CONVERT_4YUV_PIXEL( CHROMA )                                      \
200             CONVERT_4YUV_PIXEL( CHROMA )                                      \
201         }                                                                     \
202     }                                                                         \
203     /* Increment of picture pointer to end of line is still needed */         \
204     p_pic += i_right_margin;                                                  \
205                                                                               \
206     /* Increment the Y coordinate in the matrix, modulo 4 */                  \
207     i_real_y = (i_real_y + 1) & 0x3;                                          \
208
209 /*****************************************************************************
210  * SCALE_HEIGHT: handle vertical scaling
211  *****************************************************************************
212  * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
213  * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
214  * and 4 Bpp.
215  *****************************************************************************/
216 #define SCALE_HEIGHT( CHROMA, BPP )                                           \
217     /* If line is odd, rewind 4:2:0 U and V samples */                        \
218     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
219     {                                                                         \
220         p_u -= i_chroma_width;                                                \
221         p_v -= i_chroma_width;                                                \
222     }                                                                         \
223                                                                               \
224     /*                                                                        \
225      * Handle vertical scaling. The current line can be copied or next one    \
226      * can be ignored.                                                        \
227      */                                                                       \
228     switch( i_vscale )                                                        \
229     {                                                                         \
230     case -1:                             /* vertical scaling factor is < 1 */ \
231         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
232         {                                                                     \
233             /* Height reduction: skip next source line */                     \
234             p_y += p_vout->render.i_width;                                    \
235             i_y++;                                                            \
236             if( (CHROMA == 420) || (CHROMA == 422) )                          \
237             {                                                                 \
238                 if( i_y & 0x1 )                                               \
239                 {                                                             \
240                     p_u += i_chroma_width;                                    \
241                     p_v += i_chroma_width;                                    \
242                 }                                                             \
243             }                                                                 \
244             else if( CHROMA == 444 )                                          \
245             {                                                                 \
246                 p_u += p_vout->render.i_width;                                \
247                 p_v += p_vout->render.i_width;                                \
248             }                                                                 \
249         }                                                                     \
250         i_scale_count += p_vout->render.i_height;                             \
251         break;                                                                \
252     case 1:                              /* vertical scaling factor is > 1 */ \
253         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
254         {                                                                     \
255             /* Height increment: copy previous picture line */                \
256             FAST_MEMCPY( p_pic, p_pic_start, p_vout->output.i_width * BPP );  \
257             (u8*)p_pic += p_dest->p->i_pitch;                                 \
258         }                                                                     \
259         i_scale_count += p_vout->output.i_height;                             \
260         break;                                                                \
261     }                                                                         \
262
263 /*****************************************************************************
264  * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
265  *****************************************************************************
266  * This macro handles vertical scaling for a picture. CHROMA may be 420,
267  * 422 or 444 for RGB conversion, or 400 for gray conversion.
268  *****************************************************************************/
269 #define SCALE_HEIGHT_DITHER( CHROMA )                                         \
270                                                                               \
271     /* If line is odd, rewind 4:2:0 U and V samples */                        \
272     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
273     {                                                                         \
274         p_u -= i_chroma_width;                                                \
275         p_v -= i_chroma_width;                                                \
276     }                                                                         \
277                                                                               \
278     /*                                                                        \
279      * Handle vertical scaling. The current line can be copied or next one    \
280      * can be ignored.                                                        \
281      */                                                                       \
282                                                                               \
283     switch( i_vscale )                                                        \
284     {                                                                         \
285     case -1:                             /* vertical scaling factor is < 1 */ \
286         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
287         {                                                                     \
288             /* Height reduction: skip next source line */                     \
289             p_y += p_vout->render.i_width;                                    \
290             i_y++;                                                            \
291             if( (CHROMA == 420) || (CHROMA == 422) )                          \
292             {                                                                 \
293                 if( i_y & 0x1 )                                               \
294                 {                                                             \
295                     p_u += i_chroma_width;                                    \
296                     p_v += i_chroma_width;                                    \
297                 }                                                             \
298             }                                                                 \
299             else if( CHROMA == 444 )                                          \
300             {                                                                 \
301                 p_u += p_vout->render.i_width;                                \
302                 p_v += p_vout->render.i_width;                                \
303             }                                                                 \
304         }                                                                     \
305         i_scale_count += p_vout->render.i_height;                             \
306         break;                                                                \
307     case 1:                              /* vertical scaling factor is > 1 */ \
308         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
309         {                                                                     \
310             p_y -= p_vout->render.i_width;                                    \
311             p_u -= i_chroma_width;                                            \
312             p_v -= i_chroma_width;                                            \
313             SCALE_WIDTH_DITHER( CHROMA );                                     \
314         }                                                                     \
315         i_scale_count += p_vout->output.i_height;                             \
316         break;                                                                \
317     }                                                                         \
318