demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / video_chroma / i420_rgb.h
blobf9dfaad14e52b69aa5ff7c1e82a5550690f4730f
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$
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
24 #if !defined (SSE2) && !defined (MMX)
25 # define PLAIN
26 #endif
28 /** Number of entries in RGB palette/colormap */
29 #define CMAP_RGB2_SIZE 256
31 /**
32 * filter_sys_t: chroma method descriptor
34 * This structure is part of the chroma transformation descriptor, it
35 * describes the yuv2rgb specific properties.
37 struct filter_sys_t
39 uint8_t *p_buffer;
40 int *p_offset;
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 */
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.
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
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
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];
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 ) \
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];
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 ) \
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) ]; \
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++; \
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 ) \
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_x_offset + p_filter->fmt_out.video.i_visible_width) / 16; i_x--; ) \
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++; \
195 for( i_x = (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) & 15; i_x--; ) \
197 *p_pic++ = *p_buffer; p_buffer += *p_offset++; \
199 p_pic = (void*)((uint8_t*)p_pic + i_right_margin ); \
201 else \
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 ); \
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 ) \
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_x_offset + p_filter->fmt_out.video.i_visible_width) / 16; i_x--; ) \
220 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
221 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
222 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
223 CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \
226 else \
228 for( i_x = (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width) / 16; i_x--; ) \
230 CONVERT_4YUV_PIXEL( CHROMA ) \
231 CONVERT_4YUV_PIXEL( CHROMA ) \
232 CONVERT_4YUV_PIXEL( CHROMA ) \
233 CONVERT_4YUV_PIXEL( CHROMA ) \
236 /* Increment of picture pointer to end of line is still needed */ \
237 p_pic = (void*)((uint8_t*)p_pic + i_right_margin ); \
239 /* Increment the Y coordinate in the matrix, modulo 4 */ \
240 i_real_y = (i_real_y + 1) & 0x3; \
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) ) \
253 p_u -= i_chroma_width; \
254 p_v -= i_chroma_width; \
257 /* \
258 * Handle vertical scaling. The current line can be copied or next one \
259 * can be ignored. \
260 */ \
261 switch( i_vscale ) \
263 case -1: /* vertical scaling factor is < 1 */ \
264 while( (i_scale_count -= (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height)) > 0 ) \
266 /* Height reduction: skip next source line */ \
267 p_y += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
268 i_y++; \
269 if( (CHROMA == 420) || (CHROMA == 422) ) \
271 if( i_y & 0x1 ) \
273 p_u += i_chroma_width; \
274 p_v += i_chroma_width; \
277 else if( CHROMA == 444 ) \
279 p_u += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
280 p_v += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
283 i_scale_count += (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height); \
284 break; \
285 case 1: /* vertical scaling factor is > 1 */ \
286 while( (i_scale_count -= (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height)) > 0 ) \
288 /* Height increment: copy previous picture line */ \
289 memcpy( p_pic, p_pic_start, (p_filter->fmt_out.video.i_x_offset + p_filter->fmt_out.video.i_visible_width) * BPP ); \
290 p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch ); \
292 i_scale_count += (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height); \
293 break; \
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 ) \
304 /* If line is odd, rewind 4:2:0 U and V samples */ \
305 if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \
307 p_u -= i_chroma_width; \
308 p_v -= i_chroma_width; \
311 /* \
312 * Handle vertical scaling. The current line can be copied or next one \
313 * can be ignored. \
314 */ \
316 switch( i_vscale ) \
318 case -1: /* vertical scaling factor is < 1 */ \
319 while( (i_scale_count -= (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height)) > 0 ) \
321 /* Height reduction: skip next source line */ \
322 p_y += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
323 i_y++; \
324 if( (CHROMA == 420) || (CHROMA == 422) ) \
326 if( i_y & 0x1 ) \
328 p_u += i_chroma_width; \
329 p_v += i_chroma_width; \
332 else if( CHROMA == 444 ) \
334 p_u += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
335 p_v += (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
338 i_scale_count += (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height); \
339 break; \
340 case 1: /* vertical scaling factor is > 1 */ \
341 while( (i_scale_count -= (p_filter->fmt_in.video.i_y_offset + p_filter->fmt_in.video.i_visible_height)) > 0 ) \
343 p_y -= (p_filter->fmt_in.video.i_x_offset + p_filter->fmt_in.video.i_visible_width); \
344 p_u -= i_chroma_width; \
345 p_v -= i_chroma_width; \
346 SCALE_WIDTH_DITHER( CHROMA ); \
348 i_scale_count += (p_filter->fmt_out.video.i_y_offset + p_filter->fmt_out.video.i_visible_height); \
349 break; \