]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_rgb.h
5573ccee51b6194271c520726b283b94bd0f6f64
[vlc] / modules / video_chroma / i420_rgb.h
1 /*****************************************************************************
2  * i420_rgb.h : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2004 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /** Number of entries in RGB palette/colormap */
25 #define CMAP_RGB2_SIZE 256
26
27 /**
28  * chroma_sys_t: chroma method descriptor
29
30  * This structure is part of the chroma transformation descriptor, it
31  * describes the yuv2rgb specific properties.
32  */
33 struct chroma_sys_t
34 {
35     uint8_t  *p_buffer;
36     int *p_offset;
37
38 #ifdef MODULE_NAME_IS_i420_rgb
39     /**< Pre-calculated conversion tables */
40     void *p_base;                      /**< base for all conversion tables */
41     uint8_t   *p_rgb8;                 /**< RGB 8 bits table */
42     uint16_t  *p_rgb16;                /**< RGB 16 bits table */
43     uint32_t  *p_rgb32;                /**< RGB 32 bits table */
44
45     /**< To get RGB value for palette entry i, use (p_rgb_r[i], p_rgb_g[i],
46        p_rgb_b[i]). Note these are 16 bits per pixel. For 8bpp entries,
47        shift right 8 bits.
48     */
49     uint16_t  p_rgb_r[CMAP_RGB2_SIZE];  /**< Red values of palette */
50     uint16_t  p_rgb_g[CMAP_RGB2_SIZE];  /**< Green values of palette */
51     uint16_t  p_rgb_b[CMAP_RGB2_SIZE];  /**< Blue values of palette */
52 #endif
53 };
54
55 /*****************************************************************************
56  * Prototypes
57  *****************************************************************************/
58 #ifdef MODULE_NAME_IS_i420_rgb
59 void E_(I420_RGB8)         ( vout_thread_t *, picture_t *, picture_t * );
60 void E_(I420_RGB16_dither) ( vout_thread_t *, picture_t *, picture_t * );
61 void E_(I420_RGB16)        ( vout_thread_t *, picture_t *, picture_t * );
62 void E_(I420_RGB32)        ( vout_thread_t *, picture_t *, picture_t * );
63 #else // if defined(MODULE_NAME_IS_i420_rgb_mmx)
64 void E_(I420_R5G5B5)       ( vout_thread_t *, picture_t *, picture_t * );
65 void E_(I420_R5G6B5)       ( vout_thread_t *, picture_t *, picture_t * );
66 void E_(I420_A8R8G8B8)     ( vout_thread_t *, picture_t *, picture_t * );
67 void E_(I420_R8G8B8A8)     ( vout_thread_t *, picture_t *, picture_t * );
68 void E_(I420_B8G8R8A8)     ( vout_thread_t *, picture_t *, picture_t * );
69 void E_(I420_A8B8G8R8)     ( vout_thread_t *, picture_t *, picture_t * );
70 #endif
71
72 /*****************************************************************************
73  * CONVERT_*_PIXEL: pixel conversion macros
74  *****************************************************************************
75  * These conversion routines are used by YUV conversion functions.
76  * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
77  * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
78  * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
79  *****************************************************************************/
80 #define CONVERT_Y_PIXEL( BPP )                                                \
81     /* Only Y sample is present */                                            \
82     p_ybase = p_yuv + *p_y++;                                                 \
83     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] |     \
84         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT)       \
85         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
86
87 #define CONVERT_YUV_PIXEL( BPP )                                              \
88     /* Y, U and V samples are present */                                      \
89     i_uval =    *p_u++;                                                       \
90     i_vval =    *p_v++;                                                       \
91     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
92     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
93     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
94     CONVERT_Y_PIXEL( BPP )                                                    \
95
96 #define CONVERT_Y_PIXEL_DITHER( BPP )                                         \
97     /* Only Y sample is present */                                            \
98     p_ybase = p_yuv + *p_y++;                                                 \
99     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128+p_dither[i_real_y])>>SHIFT) + i_red] |     \
100         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128+p_dither[i_real_y])>>SHIFT)       \
101         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128+p_dither[i_real_y])>>SHIFT) + i_blue];
102
103 #define CONVERT_YUV_PIXEL_DITHER( BPP )                                       \
104     /* Y, U and V samples are present */                                      \
105     i_uval =    *p_u++;                                                       \
106     i_vval =    *p_v++;                                                       \
107     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
108     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
109     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
110     CONVERT_Y_PIXEL_DITHER( BPP )                                             \
111
112 #define CONVERT_4YUV_PIXEL( 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_pic++ = p_lookup[                                                      \
118         (((*p_y++ + dither11[i_real_y]) >> 4) << 7)                           \
119       + ((*p_u++ + dither21[i_real_y]) >> 5) * 9                              \
120       + ((*p_v++ + dither21[i_real_y]) >> 5) ];                               \
121     *p_pic++ = p_lookup[                                                      \
122         (((*p_y++ + dither12[i_real_y]) >> 4) << 7)                           \
123       + ((*p_u + dither22[i_real_y]) >> 5) * 9                                \
124       + ((*p_v + dither22[i_real_y]) >> 5) ];                                 \
125     *p_pic++ = p_lookup[                                                      \
126         (((*p_y++ + dither13[i_real_y]) >> 4) << 7)                           \
127       + ((*p_u++ + dither23[i_real_y]) >> 5) * 9                              \
128       + ((*p_v++ + dither23[i_real_y]) >> 5) ];                               \
129
130 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                    \
131     *p_pic++ = p_lookup[                                                      \
132         ( ((*p_y + dither10[i_real_y]) >> 4) << 7)                            \
133         + ((*p_u + dither20[i_real_y]) >> 5) * 9                              \
134         + ((*p_v + dither20[i_real_y]) >> 5) ];                               \
135     p_y += *p_offset++;                                                       \
136     p_u += *p_offset;                                                         \
137     p_v += *p_offset++;                                                       \
138     *p_pic++ = p_lookup[                                                      \
139         ( ((*p_y + dither11[i_real_y]) >> 4) << 7)                            \
140         + ((*p_u + dither21[i_real_y]) >> 5) * 9                              \
141         + ((*p_v + dither21[i_real_y]) >> 5) ];                               \
142     p_y += *p_offset++;                                                       \
143     p_u += *p_offset;                                                         \
144     p_v += *p_offset++;                                                       \
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_y += *p_offset++;                                                       \
150     p_u += *p_offset;                                                         \
151     p_v += *p_offset++;                                                       \
152     *p_pic++ = p_lookup[                                                      \
153         ( ((*p_y + dither13[i_real_y]) >> 4) << 7)                            \
154         + ((*p_u + dither23[i_real_y]) >> 5) * 9                              \
155         + ((*p_v + dither23[i_real_y]) >> 5) ];                               \
156     p_y += *p_offset++;                                                       \
157     p_u += *p_offset;                                                         \
158     p_v += *p_offset++;                                                       \
159
160 /*****************************************************************************
161  * SCALE_WIDTH: scale a line horizontally
162  *****************************************************************************
163  * This macro scales a line using rendering buffer and offset array. It works
164  * for 1, 2 and 4 Bpp.
165  *****************************************************************************/
166 #define SCALE_WIDTH                                                           \
167     if( b_hscale )                                                            \
168     {                                                                         \
169         /* Horizontal scaling, conversion has been done to buffer.            \
170          * Rewind buffer and offset, then copy and scale line */              \
171         p_buffer = p_buffer_start;                                            \
172         p_offset = p_offset_start;                                            \
173         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
174         {                                                                     \
175             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
176             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
177             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
178             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
179             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
180             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
181             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
182             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
183             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
184             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
185             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
186             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
187             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
188             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
189             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
190             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
191         }                                                                     \
192         for( i_x = p_vout->output.i_width & 15; i_x--; )                      \
193         {                                                                     \
194             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
195         }                                                                     \
196         p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                   \
197     }                                                                         \
198     else                                                                      \
199     {                                                                         \
200         /* No scaling, conversion has been done directly in picture memory.   \
201          * Increment of picture pointer to end of line is still needed */     \
202         p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );               \
203     }                                                                         \
204
205 /*****************************************************************************
206  * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
207  *****************************************************************************
208  * This macro scales a line using an offset array.
209  *****************************************************************************/
210 #define SCALE_WIDTH_DITHER( CHROMA )                                          \
211     if( b_hscale )                                                            \
212     {                                                                         \
213         /* Horizontal scaling - we can't use a buffer due to dithering */     \
214         p_offset = p_offset_start;                                            \
215         for( i_x = p_vout->output.i_width / 16; i_x--; )                      \
216         {                                                                     \
217             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
218             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
219             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
220             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
221         }                                                                     \
222     }                                                                         \
223     else                                                                      \
224     {                                                                         \
225         for( i_x = p_vout->render.i_width / 16; i_x--;  )                     \
226         {                                                                     \
227             CONVERT_4YUV_PIXEL( CHROMA )                                      \
228             CONVERT_4YUV_PIXEL( CHROMA )                                      \
229             CONVERT_4YUV_PIXEL( CHROMA )                                      \
230             CONVERT_4YUV_PIXEL( CHROMA )                                      \
231         }                                                                     \
232     }                                                                         \
233     /* Increment of picture pointer to end of line is still needed */         \
234     p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                       \
235                                                                               \
236     /* Increment the Y coordinate in the matrix, modulo 4 */                  \
237     i_real_y = (i_real_y + 1) & 0x3;                                          \
238
239 /*****************************************************************************
240  * SCALE_HEIGHT: handle vertical scaling
241  *****************************************************************************
242  * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
243  * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
244  * and 4 Bpp.
245  *****************************************************************************/
246 #define SCALE_HEIGHT( CHROMA, BPP )                                           \
247     /* If line is odd, rewind 4:2:0 U and V samples */                        \
248     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
249     {                                                                         \
250         p_u -= i_chroma_width;                                                \
251         p_v -= i_chroma_width;                                                \
252     }                                                                         \
253                                                                               \
254     /*                                                                        \
255      * Handle vertical scaling. The current line can be copied or next one    \
256      * can be ignored.                                                        \
257      */                                                                       \
258     switch( i_vscale )                                                        \
259     {                                                                         \
260     case -1:                             /* vertical scaling factor is < 1 */ \
261         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
262         {                                                                     \
263             /* Height reduction: skip next source line */                     \
264             p_y += p_vout->render.i_width;                                    \
265             i_y++;                                                            \
266             if( (CHROMA == 420) || (CHROMA == 422) )                          \
267             {                                                                 \
268                 if( i_y & 0x1 )                                               \
269                 {                                                             \
270                     p_u += i_chroma_width;                                    \
271                     p_v += i_chroma_width;                                    \
272                 }                                                             \
273             }                                                                 \
274             else if( CHROMA == 444 )                                          \
275             {                                                                 \
276                 p_u += p_vout->render.i_width;                                \
277                 p_v += p_vout->render.i_width;                                \
278             }                                                                 \
279         }                                                                     \
280         i_scale_count += p_vout->render.i_height;                             \
281         break;                                                                \
282     case 1:                              /* vertical scaling factor is > 1 */ \
283         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
284         {                                                                     \
285             /* Height increment: copy previous picture line */                \
286             p_vout->p_libvlc->pf_memcpy( p_pic, p_pic_start,                     \
287                                       p_vout->output.i_width * BPP );         \
288             p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );           \
289         }                                                                     \
290         i_scale_count += p_vout->output.i_height;                             \
291         break;                                                                \
292     }                                                                         \
293
294 /*****************************************************************************
295  * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
296  *****************************************************************************
297  * This macro handles vertical scaling for a picture. CHROMA may be 420,
298  * 422 or 444 for RGB conversion, or 400 for gray conversion.
299  *****************************************************************************/
300 #define SCALE_HEIGHT_DITHER( CHROMA )                                         \
301                                                                               \
302     /* If line is odd, rewind 4:2:0 U and V samples */                        \
303     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
304     {                                                                         \
305         p_u -= i_chroma_width;                                                \
306         p_v -= i_chroma_width;                                                \
307     }                                                                         \
308                                                                               \
309     /*                                                                        \
310      * Handle vertical scaling. The current line can be copied or next one    \
311      * can be ignored.                                                        \
312      */                                                                       \
313                                                                               \
314     switch( i_vscale )                                                        \
315     {                                                                         \
316     case -1:                             /* vertical scaling factor is < 1 */ \
317         while( (i_scale_count -= p_vout->output.i_height) > 0 )               \
318         {                                                                     \
319             /* Height reduction: skip next source line */                     \
320             p_y += p_vout->render.i_width;                                    \
321             i_y++;                                                            \
322             if( (CHROMA == 420) || (CHROMA == 422) )                          \
323             {                                                                 \
324                 if( i_y & 0x1 )                                               \
325                 {                                                             \
326                     p_u += i_chroma_width;                                    \
327                     p_v += i_chroma_width;                                    \
328                 }                                                             \
329             }                                                                 \
330             else if( CHROMA == 444 )                                          \
331             {                                                                 \
332                 p_u += p_vout->render.i_width;                                \
333                 p_v += p_vout->render.i_width;                                \
334             }                                                                 \
335         }                                                                     \
336         i_scale_count += p_vout->render.i_height;                             \
337         break;                                                                \
338     case 1:                              /* vertical scaling factor is > 1 */ \
339         while( (i_scale_count -= p_vout->render.i_height) > 0 )               \
340         {                                                                     \
341             p_y -= p_vout->render.i_width;                                    \
342             p_u -= i_chroma_width;                                            \
343             p_v -= i_chroma_width;                                            \
344             SCALE_WIDTH_DITHER( CHROMA );                                     \
345         }                                                                     \
346         i_scale_count += p_vout->output.i_height;                             \
347         break;                                                                \
348     }                                                                         \
349