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 2003/08/29 18:58:05 fenrir Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
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 *****************************************************************************/
35 #ifdef MODULE_NAME_IS_i420_rgb
36 /* Pre-calculated conversion tables */
37 void *p_base; /* base for all conversion tables */
38 uint8_t *p_rgb8; /* RGB 8 bits table */
39 uint16_t *p_rgb16; /* RGB 16 bits table */
40 uint32_t *p_rgb32; /* RGB 32 bits table */
44 /*****************************************************************************
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 * );
51 void E_(I420_RGB16) ( vout_thread_t *, picture_t *, picture_t * );
52 void E_(I420_RGB32) ( vout_thread_t *, picture_t *, picture_t * );
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];
69 #define CONVERT_YUV_PIXEL( BPP ) \
70 /* Y, U and V samples are present */ \
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 ) \
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];
85 #define CONVERT_YUV_PIXEL_DITHER( BPP ) \
86 /* Y, U and V samples are present */ \
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 ) \
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) ]; \
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++; \
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++; \
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++; \
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++; \
140 p_v += *p_offset++; \
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 \
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--; ) \
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++; \
174 for( i_x = p_vout->output.i_width & 15; i_x--; ) \
176 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
178 (uint8_t*)p_pic += i_right_margin; \
182 /* No scaling, conversion has been done directly in picture memory. \
183 * Increment of picture pointer to end of line is still needed */ \
184 (uint8_t*)p_pic += p_dest->p->i_pitch; \
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 ) \
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--; ) \
199 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
200 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
201 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
202 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
207 for( i_x = p_vout->render.i_width / 16; i_x--; ) \
209 CONVERT_4YUV_PIXEL( CHROMA ) \
210 CONVERT_4YUV_PIXEL( CHROMA ) \
211 CONVERT_4YUV_PIXEL( CHROMA ) \
212 CONVERT_4YUV_PIXEL( CHROMA ) \
215 /* Increment of picture pointer to end of line is still needed */ \
216 (uint8_t*)p_pic += i_right_margin; \
218 /* Increment the Y coordinate in the matrix, modulo 4 */ \
219 i_real_y = (i_real_y + 1) & 0x3; \
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
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) ) \
232 p_u -= i_chroma_width; \
233 p_v -= i_chroma_width; \
237 * Handle vertical scaling. The current line can be copied or next one \
242 case -1: /* vertical scaling factor is < 1 */ \
243 while( (i_scale_count -= p_vout->output.i_height) > 0 ) \
245 /* Height reduction: skip next source line */ \
246 p_y += p_vout->render.i_width; \
248 if( (CHROMA == 420) || (CHROMA == 422) ) \
252 p_u += i_chroma_width; \
253 p_v += i_chroma_width; \
256 else if( CHROMA == 444 ) \
258 p_u += p_vout->render.i_width; \
259 p_v += p_vout->render.i_width; \
262 i_scale_count += p_vout->render.i_height; \
264 case 1: /* vertical scaling factor is > 1 */ \
265 while( (i_scale_count -= p_vout->render.i_height) > 0 ) \
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 (uint8_t*)p_pic += p_dest->p->i_pitch; \
272 i_scale_count += p_vout->output.i_height; \
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 ) \
284 /* If line is odd, rewind 4:2:0 U and V samples */ \
285 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
287 p_u -= i_chroma_width; \
288 p_v -= i_chroma_width; \
292 * Handle vertical scaling. The current line can be copied or next one \
298 case -1: /* vertical scaling factor is < 1 */ \
299 while( (i_scale_count -= p_vout->output.i_height) > 0 ) \
301 /* Height reduction: skip next source line */ \
302 p_y += p_vout->render.i_width; \
304 if( (CHROMA == 420) || (CHROMA == 422) ) \
308 p_u += i_chroma_width; \
309 p_v += i_chroma_width; \
312 else if( CHROMA == 444 ) \
314 p_u += p_vout->render.i_width; \
315 p_v += p_vout->render.i_width; \
318 i_scale_count += p_vout->render.i_height; \
320 case 1: /* vertical scaling factor is > 1 */ \
321 while( (i_scale_count -= p_vout->render.i_height) > 0 ) \
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 ); \
328 i_scale_count += p_vout->output.i_height; \