]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_rgb.h
Merge branch 'df-for-upstream' of git://repo.or.cz/vlc/davidf-public
[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  * filter_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 filter_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 I420_RGB8         ( filter_t *, picture_t *, picture_t * );
60 void I420_RGB16_dither ( filter_t *, picture_t *, picture_t * );
61 void I420_RGB16        ( filter_t *, picture_t *, picture_t * );
62 void I420_RGB32        ( filter_t *, picture_t *, picture_t * );
63 static picture_t *I420_RGB8_Filter         ( filter_t *, picture_t * );
64 static picture_t *I420_RGB16_dither_Filter ( filter_t *, picture_t * );
65 static picture_t *I420_RGB16_Filter        ( filter_t *, picture_t * );
66 static picture_t *I420_RGB32_Filter        ( filter_t *, picture_t * );
67 #else // if defined(MODULE_NAME_IS_i420_rgb_mmx)
68 void I420_R5G5B5       ( filter_t *, picture_t *, picture_t * );
69 void I420_R5G6B5       ( filter_t *, picture_t *, picture_t * );
70 void I420_A8R8G8B8     ( filter_t *, picture_t *, picture_t * );
71 void I420_R8G8B8A8     ( filter_t *, picture_t *, picture_t * );
72 void I420_B8G8R8A8     ( filter_t *, picture_t *, picture_t * );
73 void I420_A8B8G8R8     ( filter_t *, picture_t *, picture_t * );
74 static picture_t *I420_R5G5B5_Filter       ( filter_t *, picture_t * );
75 static picture_t *I420_R5G6B5_Filter       ( filter_t *, picture_t * );
76 static picture_t *I420_A8R8G8B8_Filter     ( filter_t *, picture_t * );
77 static picture_t *I420_R8G8B8A8_Filter     ( filter_t *, picture_t * );
78 static picture_t *I420_B8G8R8A8_Filter     ( filter_t *, picture_t * );
79 static picture_t *I420_A8B8G8R8_Filter     ( filter_t *, picture_t * );
80 #endif
81
82 /*****************************************************************************
83  * CONVERT_*_PIXEL: pixel conversion macros
84  *****************************************************************************
85  * These conversion routines are used by YUV conversion functions.
86  * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
87  * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
88  * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
89  *****************************************************************************/
90 #define CONVERT_Y_PIXEL( BPP )                                                \
91     /* Only Y sample is present */                                            \
92     p_ybase = p_yuv + *p_y++;                                                 \
93     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] |     \
94         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT)       \
95         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
96
97 #define CONVERT_YUV_PIXEL( BPP )                                              \
98     /* Y, U and V samples are present */                                      \
99     i_uval =    *p_u++;                                                       \
100     i_vval =    *p_v++;                                                       \
101     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
102     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
103     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
104     CONVERT_Y_PIXEL( BPP )                                                    \
105
106 #define CONVERT_Y_PIXEL_DITHER( BPP )                                         \
107     /* Only Y sample is present */                                            \
108     p_ybase = p_yuv + *p_y++;                                                 \
109     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128+p_dither[i_real_y])>>SHIFT) + i_red] |     \
110         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128+p_dither[i_real_y])>>SHIFT)       \
111         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128+p_dither[i_real_y])>>SHIFT) + i_blue];
112
113 #define CONVERT_YUV_PIXEL_DITHER( BPP )                                       \
114     /* Y, U and V samples are present */                                      \
115     i_uval =    *p_u++;                                                       \
116     i_vval =    *p_v++;                                                       \
117     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
118     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
119     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
120     CONVERT_Y_PIXEL_DITHER( BPP )                                             \
121
122 #define CONVERT_4YUV_PIXEL( CHROMA )                                          \
123     *p_pic++ = p_lookup[                                                      \
124         (((*p_y++ + dither10[i_real_y]) >> 4) << 7)                           \
125       + ((*p_u + dither20[i_real_y]) >> 5) * 9                                \
126       + ((*p_v + dither20[i_real_y]) >> 5) ];                                 \
127     *p_pic++ = p_lookup[                                                      \
128         (((*p_y++ + dither11[i_real_y]) >> 4) << 7)                           \
129       + ((*p_u++ + dither21[i_real_y]) >> 5) * 9                              \
130       + ((*p_v++ + dither21[i_real_y]) >> 5) ];                               \
131     *p_pic++ = p_lookup[                                                      \
132         (((*p_y++ + dither12[i_real_y]) >> 4) << 7)                           \
133       + ((*p_u + dither22[i_real_y]) >> 5) * 9                                \
134       + ((*p_v + dither22[i_real_y]) >> 5) ];                                 \
135     *p_pic++ = p_lookup[                                                      \
136         (((*p_y++ + dither13[i_real_y]) >> 4) << 7)                           \
137       + ((*p_u++ + dither23[i_real_y]) >> 5) * 9                              \
138       + ((*p_v++ + dither23[i_real_y]) >> 5) ];                               \
139
140 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                    \
141     *p_pic++ = p_lookup[                                                      \
142         ( ((*p_y + dither10[i_real_y]) >> 4) << 7)                            \
143         + ((*p_u + dither20[i_real_y]) >> 5) * 9                              \
144         + ((*p_v + dither20[i_real_y]) >> 5) ];                               \
145     p_y += *p_offset++;                                                       \
146     p_u += *p_offset;                                                         \
147     p_v += *p_offset++;                                                       \
148     *p_pic++ = p_lookup[                                                      \
149         ( ((*p_y + dither11[i_real_y]) >> 4) << 7)                            \
150         + ((*p_u + dither21[i_real_y]) >> 5) * 9                              \
151         + ((*p_v + dither21[i_real_y]) >> 5) ];                               \
152     p_y += *p_offset++;                                                       \
153     p_u += *p_offset;                                                         \
154     p_v += *p_offset++;                                                       \
155     *p_pic++ = p_lookup[                                                      \
156         ( ((*p_y + dither12[i_real_y]) >> 4) << 7)                            \
157         + ((*p_u + dither22[i_real_y]) >> 5) * 9                              \
158         + ((*p_v + dither22[i_real_y]) >> 5) ];                               \
159     p_y += *p_offset++;                                                       \
160     p_u += *p_offset;                                                         \
161     p_v += *p_offset++;                                                       \
162     *p_pic++ = p_lookup[                                                      \
163         ( ((*p_y + dither13[i_real_y]) >> 4) << 7)                            \
164         + ((*p_u + dither23[i_real_y]) >> 5) * 9                              \
165         + ((*p_v + dither23[i_real_y]) >> 5) ];                               \
166     p_y += *p_offset++;                                                       \
167     p_u += *p_offset;                                                         \
168     p_v += *p_offset++;                                                       \
169
170 /*****************************************************************************
171  * SCALE_WIDTH: scale a line horizontally
172  *****************************************************************************
173  * This macro scales a line using rendering buffer and offset array. It works
174  * for 1, 2 and 4 Bpp.
175  *****************************************************************************/
176 #define SCALE_WIDTH                                                           \
177     if( b_hscale )                                                            \
178     {                                                                         \
179         /* Horizontal scaling, conversion has been done to buffer.            \
180          * Rewind buffer and offset, then copy and scale line */              \
181         p_buffer = p_buffer_start;                                            \
182         p_offset = p_offset_start;                                            \
183         for( i_x = p_filter->fmt_out.video.i_width / 16; i_x--; )             \
184         {                                                                     \
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             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
192             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
193             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
194             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
195             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
196             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
197             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
198             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
199             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
200             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
201         }                                                                     \
202         for( i_x = p_filter->fmt_out.video.i_width & 15; i_x--; )             \
203         {                                                                     \
204             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
205         }                                                                     \
206         p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                   \
207     }                                                                         \
208     else                                                                      \
209     {                                                                         \
210         /* No scaling, conversion has been done directly in picture memory.   \
211          * Increment of picture pointer to end of line is still needed */     \
212         p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );               \
213     }                                                                         \
214
215 /*****************************************************************************
216  * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
217  *****************************************************************************
218  * This macro scales a line using an offset array.
219  *****************************************************************************/
220 #define SCALE_WIDTH_DITHER( CHROMA )                                          \
221     if( b_hscale )                                                            \
222     {                                                                         \
223         /* Horizontal scaling - we can't use a buffer due to dithering */     \
224         p_offset = p_offset_start;                                            \
225         for( i_x = p_filter->fmt_out.video.i_width / 16; i_x--; )             \
226         {                                                                     \
227             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
228             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
229             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
230             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
231         }                                                                     \
232     }                                                                         \
233     else                                                                      \
234     {                                                                         \
235         for( i_x = p_filter->fmt_in.video.i_width / 16; i_x--;  )             \
236         {                                                                     \
237             CONVERT_4YUV_PIXEL( CHROMA )                                      \
238             CONVERT_4YUV_PIXEL( CHROMA )                                      \
239             CONVERT_4YUV_PIXEL( CHROMA )                                      \
240             CONVERT_4YUV_PIXEL( CHROMA )                                      \
241         }                                                                     \
242     }                                                                         \
243     /* Increment of picture pointer to end of line is still needed */         \
244     p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                       \
245                                                                               \
246     /* Increment the Y coordinate in the matrix, modulo 4 */                  \
247     i_real_y = (i_real_y + 1) & 0x3;                                          \
248
249 /*****************************************************************************
250  * SCALE_HEIGHT: handle vertical scaling
251  *****************************************************************************
252  * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
253  * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
254  * and 4 Bpp.
255  *****************************************************************************/
256 #define SCALE_HEIGHT( CHROMA, BPP )                                           \
257     /* If line is odd, rewind 4:2:0 U and V samples */                        \
258     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
259     {                                                                         \
260         p_u -= i_chroma_width;                                                \
261         p_v -= i_chroma_width;                                                \
262     }                                                                         \
263                                                                               \
264     /*                                                                        \
265      * Handle vertical scaling. The current line can be copied or next one    \
266      * can be ignored.                                                        \
267      */                                                                       \
268     switch( i_vscale )                                                        \
269     {                                                                         \
270     case -1:                             /* vertical scaling factor is < 1 */ \
271         while( (i_scale_count -= p_filter->fmt_out.video.i_height) > 0 )      \
272         {                                                                     \
273             /* Height reduction: skip next source line */                     \
274             p_y += p_filter->fmt_in.video.i_width;                            \
275             i_y++;                                                            \
276             if( (CHROMA == 420) || (CHROMA == 422) )                          \
277             {                                                                 \
278                 if( i_y & 0x1 )                                               \
279                 {                                                             \
280                     p_u += i_chroma_width;                                    \
281                     p_v += i_chroma_width;                                    \
282                 }                                                             \
283             }                                                                 \
284             else if( CHROMA == 444 )                                          \
285             {                                                                 \
286                 p_u += p_filter->fmt_in.video.i_width;                        \
287                 p_v += p_filter->fmt_in.video.i_width;                        \
288             }                                                                 \
289         }                                                                     \
290         i_scale_count += p_filter->fmt_in.video.i_height;                     \
291         break;                                                                \
292     case 1:                              /* vertical scaling factor is > 1 */ \
293         while( (i_scale_count -= p_filter->fmt_in.video.i_height) > 0 )       \
294         {                                                                     \
295             /* Height increment: copy previous picture line */                \
296             vlc_memcpy( p_pic, p_pic_start, p_filter->fmt_out.video.i_width * BPP ); \
297             p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );           \
298         }                                                                     \
299         i_scale_count += p_filter->fmt_out.video.i_height;                    \
300         break;                                                                \
301     }                                                                         \
302
303 /*****************************************************************************
304  * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
305  *****************************************************************************
306  * This macro handles vertical scaling for a picture. CHROMA may be 420,
307  * 422 or 444 for RGB conversion, or 400 for gray conversion.
308  *****************************************************************************/
309 #define SCALE_HEIGHT_DITHER( CHROMA )                                         \
310                                                                               \
311     /* If line is odd, rewind 4:2:0 U and V samples */                        \
312     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
313     {                                                                         \
314         p_u -= i_chroma_width;                                                \
315         p_v -= i_chroma_width;                                                \
316     }                                                                         \
317                                                                               \
318     /*                                                                        \
319      * Handle vertical scaling. The current line can be copied or next one    \
320      * can be ignored.                                                        \
321      */                                                                       \
322                                                                               \
323     switch( i_vscale )                                                        \
324     {                                                                         \
325     case -1:                             /* vertical scaling factor is < 1 */ \
326         while( (i_scale_count -= p_filter->fmt_out.video.i_height) > 0 )      \
327         {                                                                     \
328             /* Height reduction: skip next source line */                     \
329             p_y += p_filter->fmt_in.video.i_width;                            \
330             i_y++;                                                            \
331             if( (CHROMA == 420) || (CHROMA == 422) )                          \
332             {                                                                 \
333                 if( i_y & 0x1 )                                               \
334                 {                                                             \
335                     p_u += i_chroma_width;                                    \
336                     p_v += i_chroma_width;                                    \
337                 }                                                             \
338             }                                                                 \
339             else if( CHROMA == 444 )                                          \
340             {                                                                 \
341                 p_u += p_filter->fmt_in.video.i_width;                        \
342                 p_v += p_filter->fmt_in.video.i_width;                        \
343             }                                                                 \
344         }                                                                     \
345         i_scale_count += p_filter->fmt_in.video.i_height;                     \
346         break;                                                                \
347     case 1:                              /* vertical scaling factor is > 1 */ \
348         while( (i_scale_count -= p_filter->fmt_in.video.i_height) > 0 )       \
349         {                                                                     \
350             p_y -= p_filter->fmt_in.video.i_width;                            \
351             p_u -= i_chroma_width;                                            \
352             p_v -= i_chroma_width;                                            \
353             SCALE_WIDTH_DITHER( CHROMA );                                     \
354         }                                                                     \
355         i_scale_count += p_filter->fmt_out.video.i_height;                    \
356         break;                                                                \
357     }                                                                         \
358