1 /*****************************************************************************
2 * i420_rgb.h : YUV to bitmap RGB conversion module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2004 VLC authors and VideoLAN
6 * Authors: Samuel Hocevar <sam@zoy.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
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 Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
24 #if !defined (SSE2) && !defined (MMX)
28 /** Number of entries in RGB palette/colormap */
29 #define CMAP_RGB2_SIZE 256
32 * filter_sys_t: chroma method descriptor
34 * This structure is part of the chroma transformation descriptor, it
35 * describes the yuv2rgb specific properties.
45 /**< Pre-calculated conversion tables */
46 void *p_base
; /**< base for all conversion tables */
47 uint8_t *p_rgb8
; /**< RGB 8 bits table */
48 uint16_t *p_rgb16
; /**< RGB 16 bits table */
49 uint32_t *p_rgb32
; /**< RGB 32 bits table */
51 /**< To get RGB value for palette entry i, use (p_rgb_r[i], p_rgb_g[i],
52 p_rgb_b[i]). Note these are 16 bits per pixel. For 8bpp entries,
55 uint16_t p_rgb_r
[CMAP_RGB2_SIZE
]; /**< Red values of palette */
56 uint16_t p_rgb_g
[CMAP_RGB2_SIZE
]; /**< Green values of palette */
57 uint16_t p_rgb_b
[CMAP_RGB2_SIZE
]; /**< Blue values of palette */
61 /*****************************************************************************
62 * Conversion buffer helper
63 *****************************************************************************/
64 static inline int AllocateOrGrow( uint8_t **pp_buffer
, size_t *pi_buffer
,
65 unsigned i_width
, uint8_t bytespp
)
67 if(UINT_MAX
/ bytespp
< i_width
)
69 const size_t i_realloc
= i_width
* bytespp
;
70 if(*pi_buffer
>= i_realloc
)
72 uint8_t *p_realloc
= realloc(*pp_buffer
, i_realloc
);
75 *pp_buffer
= p_realloc
;
76 *pi_buffer
= i_realloc
;
80 /*****************************************************************************
82 *****************************************************************************/
84 void I420_RGB8 ( filter_t
*, picture_t
*, picture_t
* );
85 void I420_RGB16 ( filter_t
*, picture_t
*, picture_t
* );
86 void I420_RGB32 ( filter_t
*, picture_t
*, picture_t
* );
88 void I420_R5G5B5 ( filter_t
*, picture_t
*, picture_t
* );
89 void I420_R5G6B5 ( filter_t
*, picture_t
*, picture_t
* );
90 void I420_A8R8G8B8 ( filter_t
*, picture_t
*, picture_t
* );
91 void I420_R8G8B8A8 ( filter_t
*, picture_t
*, picture_t
* );
92 void I420_B8G8R8A8 ( filter_t
*, picture_t
*, picture_t
* );
93 void I420_A8B8G8R8 ( filter_t
*, picture_t
*, picture_t
* );
96 /*****************************************************************************
97 * CONVERT_*_PIXEL: pixel conversion macros
98 *****************************************************************************
99 * These conversion routines are used by YUV conversion functions.
100 * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
101 * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
102 * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
103 *****************************************************************************/
104 #define CONVERT_Y_PIXEL( BPP ) \
105 /* Only Y sample is present */ \
106 p_ybase = p_yuv + *p_y++; \
107 *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] | \
108 p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT) \
109 + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
111 #define CONVERT_YUV_PIXEL( BPP ) \
112 /* Y, U and V samples are present */ \
115 i_red = (V_RED_COEF * i_vval) >> SHIFT; \
116 i_green = (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT; \
117 i_blue = (U_BLUE_COEF * i_uval) >> SHIFT; \
118 CONVERT_Y_PIXEL( BPP ) \
120 #define CONVERT_Y_PIXEL_DITHER( BPP ) \
121 /* Only Y sample is present */ \
122 p_ybase = p_yuv + *p_y++; \
123 *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128+p_dither[i_real_y])>>SHIFT) + i_red] | \
124 p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128+p_dither[i_real_y])>>SHIFT) \
125 + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128+p_dither[i_real_y])>>SHIFT) + i_blue];
127 #define CONVERT_YUV_PIXEL_DITHER( BPP ) \
128 /* Y, U and V samples are present */ \
131 i_red = (V_RED_COEF * i_vval) >> SHIFT; \
132 i_green = (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT; \
133 i_blue = (U_BLUE_COEF * i_uval) >> SHIFT; \
134 CONVERT_Y_PIXEL_DITHER( BPP ) \
136 #define CONVERT_4YUV_PIXEL( CHROMA ) \
137 *p_pic++ = p_lookup[ \
138 (((*p_y++ + dither10[i_real_y]) >> 4) << 7) \
139 + ((*p_u + dither20[i_real_y]) >> 5) * 9 \
140 + ((*p_v + dither20[i_real_y]) >> 5) ]; \
141 *p_pic++ = p_lookup[ \
142 (((*p_y++ + dither11[i_real_y]) >> 4) << 7) \
143 + ((*p_u++ + dither21[i_real_y]) >> 5) * 9 \
144 + ((*p_v++ + dither21[i_real_y]) >> 5) ]; \
145 *p_pic++ = p_lookup[ \
146 (((*p_y++ + dither12[i_real_y]) >> 4) << 7) \
147 + ((*p_u + dither22[i_real_y]) >> 5) * 9 \
148 + ((*p_v + dither22[i_real_y]) >> 5) ]; \
149 *p_pic++ = p_lookup[ \
150 (((*p_y++ + dither13[i_real_y]) >> 4) << 7) \
151 + ((*p_u++ + dither23[i_real_y]) >> 5) * 9 \
152 + ((*p_v++ + dither23[i_real_y]) >> 5) ]; \
154 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
155 *p_pic++ = p_lookup[ \
156 ( ((*p_y + dither10[i_real_y]) >> 4) << 7) \
157 + ((*p_u + dither20[i_real_y]) >> 5) * 9 \
158 + ((*p_v + dither20[i_real_y]) >> 5) ]; \
159 p_y += *p_offset++; \
161 p_v += *p_offset++; \
162 *p_pic++ = p_lookup[ \
163 ( ((*p_y + dither11[i_real_y]) >> 4) << 7) \
164 + ((*p_u + dither21[i_real_y]) >> 5) * 9 \
165 + ((*p_v + dither21[i_real_y]) >> 5) ]; \
166 p_y += *p_offset++; \
168 p_v += *p_offset++; \
169 *p_pic++ = p_lookup[ \
170 ( ((*p_y + dither12[i_real_y]) >> 4) << 7) \
171 + ((*p_u + dither22[i_real_y]) >> 5) * 9 \
172 + ((*p_v + dither22[i_real_y]) >> 5) ]; \
173 p_y += *p_offset++; \
175 p_v += *p_offset++; \
176 *p_pic++ = p_lookup[ \
177 ( ((*p_y + dither13[i_real_y]) >> 4) << 7) \
178 + ((*p_u + dither23[i_real_y]) >> 5) * 9 \
179 + ((*p_v + dither23[i_real_y]) >> 5) ]; \
180 p_y += *p_offset++; \
182 p_v += *p_offset++; \
184 /*****************************************************************************
185 * SCALE_WIDTH: scale a line horizontally
186 *****************************************************************************
187 * This macro scales a line using rendering buffer and offset array. It works
188 * for 1, 2 and 4 Bpp.
189 *****************************************************************************/
190 #define SCALE_WIDTH \
193 /* Horizontal scaling, conversion has been done to buffer. \
194 * Rewind buffer and offset, then copy and scale line */ \
195 p_buffer = p_buffer_start; \
196 p_offset = p_offset_start; \
197 for( i_x = (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) / 16; i_x--; ) \
199 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
200 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
201 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
202 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
203 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
204 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
205 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
206 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
207 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
208 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
209 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
210 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
211 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
212 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
213 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
214 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
216 for( i_x = (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) & 15; i_x--; ) \
218 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
220 p_pic = (void*)((uint8_t*)p_pic + i_right_margin ); \
224 /* No scaling, conversion has been done directly in picture memory. \
225 * Increment of picture pointer to end of line is still needed */ \
226 p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch ); \
229 /*****************************************************************************
230 * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
231 *****************************************************************************
232 * This macro scales a line using an offset array.
233 *****************************************************************************/
234 #define SCALE_WIDTH_DITHER( CHROMA ) \
237 /* Horizontal scaling - we can't use a buffer due to dithering */ \
238 p_offset = p_offset_start; \
239 for( i_x = (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) / 16; i_x--; ) \
241 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
242 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
243 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
244 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
249 for( i_x = (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width) / 16; i_x--; ) \
251 CONVERT_4YUV_PIXEL( CHROMA ) \
252 CONVERT_4YUV_PIXEL( CHROMA ) \
253 CONVERT_4YUV_PIXEL( CHROMA ) \
254 CONVERT_4YUV_PIXEL( CHROMA ) \
257 /* Increment of picture pointer to end of line is still needed */ \
258 p_pic = (void*)((uint8_t*)p_pic + i_right_margin ); \
260 /* Increment the Y coordinate in the matrix, modulo 4 */ \
261 i_real_y = (i_real_y + 1) & 0x3; \
263 /*****************************************************************************
264 * SCALE_HEIGHT: handle vertical scaling
265 *****************************************************************************
266 * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
267 * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
269 *****************************************************************************/
270 #define SCALE_HEIGHT( CHROMA, BPP ) \
271 /* If line is odd, rewind 4:2:0 U and V samples */ \
272 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
274 p_u -= i_chroma_width; \
275 p_v -= i_chroma_width; \
279 * Handle vertical scaling. The current line can be copied or next one \
284 case -1: /* vertical scaling factor is < 1 */ \
285 while( (i_scale_count -= (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height)) > 0 ) \
287 /* Height reduction: skip next source line */ \
288 p_y += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
290 if( (CHROMA == 420) || (CHROMA == 422) ) \
294 p_u += i_chroma_width; \
295 p_v += i_chroma_width; \
298 else if( CHROMA == 444 ) \
300 p_u += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
301 p_v += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
304 i_scale_count += (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height); \
306 case 1: /* vertical scaling factor is > 1 */ \
307 while( (i_scale_count -= (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height)) > 0 ) \
309 /* Height increment: copy previous picture line */ \
310 memcpy( p_pic, p_pic_start, (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) * BPP ); \
311 p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch ); \
313 i_scale_count += (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height); \
317 /*****************************************************************************
318 * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
319 *****************************************************************************
320 * This macro handles vertical scaling for a picture. CHROMA may be 420,
321 * 422 or 444 for RGB conversion, or 400 for gray conversion.
322 *****************************************************************************/
323 #define SCALE_HEIGHT_DITHER( CHROMA ) \
325 /* If line is odd, rewind 4:2:0 U and V samples */ \
326 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
328 p_u -= i_chroma_width; \
329 p_v -= i_chroma_width; \
333 * Handle vertical scaling. The current line can be copied or next one \
339 case -1: /* vertical scaling factor is < 1 */ \
340 while( (i_scale_count -= (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height)) > 0 ) \
342 /* Height reduction: skip next source line */ \
343 p_y += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
345 if( (CHROMA == 420) || (CHROMA == 422) ) \
349 p_u += i_chroma_width; \
350 p_v += i_chroma_width; \
353 else if( CHROMA == 444 ) \
355 p_u += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
356 p_v += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
359 i_scale_count += (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height); \
361 case 1: /* vertical scaling factor is > 1 */ \
362 while( (i_scale_count -= (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height)) > 0 ) \
364 p_y -= (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
365 p_u -= i_chroma_width; \
366 p_v -= i_chroma_width; \
367 SCALE_WIDTH_DITHER( CHROMA ); \
369 i_scale_count += (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height); \