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