1 /*****************************************************************************
2 * transforms_common.h: Chroma transformation macros
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: transforms.h,v 1.1 2001/12/16 16:18:36 sam Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public
21 * License along with this program; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * CONVERT_*_PIXEL: pixel conversion macros
28 *****************************************************************************
29 * These conversion routines are used by YUV conversion functions.
30 * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
31 * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
32 * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
33 *****************************************************************************/
34 #define CONVERT_Y_PIXEL( BPP ) \
35 /* Only Y sample is present */ \
36 p_ybase = p_yuv + *p_y++; \
37 *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] | \
38 p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT) \
39 + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
41 #define CONVERT_YUV_PIXEL( BPP ) \
42 /* Y, U and V samples are present */ \
45 i_red = (V_RED_COEF * i_vval) >> SHIFT; \
46 i_green = (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT; \
47 i_blue = (U_BLUE_COEF * i_uval) >> SHIFT; \
48 CONVERT_Y_PIXEL( BPP ) \
50 #define CONVERT_4YUV_PIXEL( CHROMA ) \
51 *p_pic++ = p_lookup[ \
52 (((*p_y++ + dither10[i_real_y]) >> 4) << 7) \
53 + ((*p_u + dither20[i_real_y]) >> 5) * 9 \
54 + ((*p_v + dither20[i_real_y]) >> 5) ]; \
55 *p_pic++ = p_lookup[ \
56 (((*p_y++ + dither11[i_real_y]) >> 4) << 7) \
57 + ((*p_u++ + dither21[i_real_y]) >> 5) * 9 \
58 + ((*p_v++ + dither21[i_real_y]) >> 5) ]; \
59 *p_pic++ = p_lookup[ \
60 (((*p_y++ + dither12[i_real_y]) >> 4) << 7) \
61 + ((*p_u + dither22[i_real_y]) >> 5) * 9 \
62 + ((*p_v + dither22[i_real_y]) >> 5) ]; \
63 *p_pic++ = p_lookup[ \
64 (((*p_y++ + dither13[i_real_y]) >> 4) << 7) \
65 + ((*p_u++ + dither23[i_real_y]) >> 5) * 9 \
66 + ((*p_v++ + dither23[i_real_y]) >> 5) ]; \
68 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
69 *p_pic++ = p_lookup[ \
70 ( ((*p_y + dither10[i_real_y]) >> 4) << 7) \
71 + ((*p_u + dither20[i_real_y]) >> 5) * 9 \
72 + ((*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) ]; \
83 *p_pic++ = p_lookup[ \
84 ( ((*p_y + dither12[i_real_y]) >> 4) << 7) \
85 + ((*p_u + dither22[i_real_y]) >> 5) * 9 \
86 + ((*p_v + dither22[i_real_y]) >> 5) ]; \
90 *p_pic++ = p_lookup[ \
91 ( ((*p_y + dither13[i_real_y]) >> 4) << 7) \
92 + ((*p_u + dither23[i_real_y]) >> 5) * 9 \
93 + ((*p_v + dither23[i_real_y]) >> 5) ]; \
98 /*****************************************************************************
99 * SCALE_WIDTH: scale a line horizontally
100 *****************************************************************************
101 * This macro scales a line using rendering buffer and offset array. It works
102 * for 1, 2 and 4 Bpp.
103 *****************************************************************************/
104 #define SCALE_WIDTH \
105 if( b_horizontal_scaling ) \
107 /* Horizontal scaling, conversion has been done to buffer. \
108 * Rewind buffer and offset, then copy and scale line */ \
109 p_buffer = p_buffer_start; \
110 p_offset = p_offset_start; \
111 for( i_x = i_pic_width / 16; i_x--; ) \
113 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
114 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
115 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
116 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
117 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
118 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
119 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
120 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
121 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
122 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
123 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
124 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
125 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
126 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
127 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
128 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
130 p_pic += i_pic_line_width; \
134 /* No scaling, conversion has been done directly in picture memory. \
135 * Increment of picture pointer to end of line is still needed */ \
136 p_pic += i_pic_width + i_pic_line_width; \
139 /*****************************************************************************
140 * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
141 *****************************************************************************
142 * This macro scales a line using an offset array.
143 *****************************************************************************/
144 #define SCALE_WIDTH_DITHER( CHROMA ) \
145 if( b_horizontal_scaling ) \
147 /* Horizontal scaling - we can't use a buffer due to dithering */ \
148 p_offset = p_offset_start; \
149 for( i_x = i_pic_width / 16; i_x--; ) \
151 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
152 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
153 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
154 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
159 for( i_x = i_width / 16; i_x--; ) \
161 CONVERT_4YUV_PIXEL( CHROMA ) \
162 CONVERT_4YUV_PIXEL( CHROMA ) \
163 CONVERT_4YUV_PIXEL( CHROMA ) \
164 CONVERT_4YUV_PIXEL( CHROMA ) \
167 /* Increment of picture pointer to end of line is still needed */ \
168 p_pic += i_pic_line_width; \
170 /* Increment the Y coordinate in the matrix, modulo 4 */ \
171 i_real_y = (i_real_y + 1) & 0x3; \
173 /*****************************************************************************
174 * SCALE_HEIGHT: handle vertical scaling
175 *****************************************************************************
176 * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
177 * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
179 *****************************************************************************/
180 #define SCALE_HEIGHT( CHROMA, BPP ) \
181 /* If line is odd, rewind 4:2:0 U and V samples */ \
182 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
184 p_u -= i_chroma_width; \
185 p_v -= i_chroma_width; \
189 * Handle vertical scaling. The current line can be copied or next one \
192 switch( i_vertical_scaling ) \
194 case -1: /* vertical scaling factor is < 1 */ \
195 while( (i_scale_count -= i_pic_height) > 0 ) \
197 /* Height reduction: skip next source line */ \
200 if( (CHROMA == 420) || (CHROMA == 422) ) \
204 p_u += i_chroma_width; \
205 p_v += i_chroma_width; \
208 else if( CHROMA == 444 ) \
214 i_scale_count += i_height; \
216 case 1: /* vertical scaling factor is > 1 */ \
217 while( (i_scale_count -= i_height) > 0 ) \
219 /* Height increment: copy previous picture line */ \
220 for( i_x = i_pic_width / 16; i_x--; ) \
222 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
223 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
224 if( BPP > 1 ) /* 2, 3, 4 Bpp */ \
226 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
227 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
229 if( BPP > 2 ) /* 3, 4 Bpp */ \
231 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
232 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
234 if( BPP > 3 ) /* 4 Bpp */ \
236 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
237 *(((u64 *) p_pic)++) = *(((u64 *) p_pic_start)++ ); \
240 p_pic += i_pic_line_width; \
241 p_pic_start += i_pic_line_width; \
243 i_scale_count += i_pic_height; \
247 /*****************************************************************************
248 * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
249 *****************************************************************************
250 * This macro handles vertical scaling for a picture. CHROMA may be 420,
251 * 422 or 444 for RGB conversion, or 400 for gray conversion.
252 *****************************************************************************/
253 #define SCALE_HEIGHT_DITHER( CHROMA ) \
255 /* If line is odd, rewind 4:2:0 U and V samples */ \
256 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
258 p_u -= i_chroma_width; \
259 p_v -= i_chroma_width; \
263 * Handle vertical scaling. The current line can be copied or next one \
267 switch( i_vertical_scaling ) \
269 case -1: /* vertical scaling factor is < 1 */ \
270 while( (i_scale_count -= i_pic_height) > 0 ) \
272 /* Height reduction: skip next source line */ \
275 if( (CHROMA == 420) || (CHROMA == 422) ) \
279 p_u += i_chroma_width; \
280 p_v += i_chroma_width; \
283 else if( CHROMA == 444 ) \
289 i_scale_count += i_height; \
291 case 1: /* vertical scaling factor is > 1 */ \
292 while( (i_scale_count -= i_height) > 0 ) \
295 p_u -= i_chroma_width; \
296 p_v -= i_chroma_width; \
297 SCALE_WIDTH_DITHER( CHROMA ); \
299 i_scale_count += i_pic_height; \