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