1 /*****************************************************************************
2 * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000 VideoLAN
5 * $Id: i420_rgb16.c,v 1.4 2002/11/25 19:29:10 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <string.h> /* strerror() */
28 #include <stdlib.h> /* malloc(), free() */
34 #if defined (MODULE_NAME_IS_i420_rgb)
35 # include "i420_rgb_c.h"
36 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
37 # include "i420_rgb_mmx.h"
40 static void SetOffset( int, int, int, int, vlc_bool_t *, int *, int * );
42 #if defined (MODULE_NAME_IS_i420_rgb)
43 /*****************************************************************************
44 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp with dithering
45 *****************************************************************************
46 * Horizontal alignment needed:
47 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
48 * - output: 1 pixel (2 bytes), margins allowed
49 * Vertical alignment needed:
50 * - input: 2 lines (2 Y lines, 1 U/V line)
52 *****************************************************************************/
53 void E_(I420_RGB16_dithering)( vout_thread_t *p_vout, picture_t *p_src,
56 /* We got this one from the old arguments */
57 u16 *p_pic = (u16*)p_dest->p->p_pixels;
58 u8 *p_y = p_src->Y_PIXELS;
59 u8 *p_u = p_src->U_PIXELS;
60 u8 *p_v = p_src->V_PIXELS;
62 vlc_bool_t b_hscale; /* horizontal scaling type */
63 int i_vscale; /* vertical scaling type */
64 unsigned int i_x, i_y; /* horizontal and vertical indexes */
65 unsigned int i_real_y; /* y % 4 */
69 int i_scale_count; /* scale modulo counter */
70 int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
71 u16 * p_pic_start; /* beginning of the current line for copy */
72 int i_uval, i_vval; /* U and V samples */
73 int i_red, i_green, i_blue; /* U and V modified samples */
74 u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16;
75 u16 * p_ybase; /* Y dependant conversion table */
77 /* Conversion buffer pointer */
78 u16 * p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer;
81 /* Offset array pointer */
82 int * p_offset_start = p_vout->chroma.p_sys->p_offset;
85 /* The dithering matrices */
86 int dither10[4] = { 0x0, 0x8, 0x2, 0xa };
87 int dither11[4] = { 0xc, 0x4, 0xe, 0x6 };
88 int dither12[4] = { 0x3, 0xb, 0x1, 0x9 };
89 int dither13[4] = { 0xf, 0x7, 0xd, 0x5 };
91 for(i_x = 0; i_x < 4; i_x++)
93 dither10[i_x] = dither10[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
94 dither11[i_x] = dither11[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
95 dither12[i_x] = dither12[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
96 dither13[i_x] = dither13[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
99 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
101 if( p_vout->render.i_width & 7 )
103 i_rewind = 8 - ( p_vout->render.i_width & 7 );
110 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
111 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
112 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
113 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
114 p_vout->output.i_width, p_vout->output.i_height,
115 &b_hscale, &i_vscale, p_offset_start );
120 i_scale_count = ( i_vscale == 1 ) ?
121 p_vout->output.i_height : p_vout->render.i_height;
122 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
124 i_real_y = i_y & 0x3;
126 p_buffer = b_hscale ? p_buffer_start : p_pic;
128 for ( i_x = p_vout->render.i_width / 8; i_x--; )
130 int *p_dither = dither10;
131 CONVERT_YUV_PIXEL_DITHER(2);
133 CONVERT_Y_PIXEL_DITHER(2);
135 CONVERT_YUV_PIXEL_DITHER(2);
137 CONVERT_Y_PIXEL_DITHER(2);
139 CONVERT_YUV_PIXEL_DITHER(2);
141 CONVERT_Y_PIXEL_DITHER(2);
143 CONVERT_YUV_PIXEL_DITHER(2);
145 CONVERT_Y_PIXEL_DITHER(2);
148 /* Here we do some unaligned reads and duplicate conversions, but
149 * at least we have all the pixels */
152 int *p_dither = dither10;
154 p_u -= i_rewind >> 1;
155 p_v -= i_rewind >> 1;
156 p_buffer -= i_rewind;
157 CONVERT_YUV_PIXEL_DITHER(2);
159 CONVERT_Y_PIXEL_DITHER(2);
161 CONVERT_YUV_PIXEL_DITHER(2);
163 CONVERT_Y_PIXEL_DITHER(2);
165 CONVERT_YUV_PIXEL_DITHER(2);
167 CONVERT_Y_PIXEL_DITHER(2);
169 CONVERT_YUV_PIXEL_DITHER(2);
171 CONVERT_Y_PIXEL_DITHER(2);
174 SCALE_HEIGHT( 420, 2 );
179 /*****************************************************************************
180 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
181 *****************************************************************************
182 * Horizontal alignment needed:
183 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
184 * - output: 1 pixel (2 bytes), margins allowed
185 * Vertical alignment needed:
186 * - input: 2 lines (2 Y lines, 1 U/V line)
188 *****************************************************************************/
189 void E_(I420_RGB16)( vout_thread_t *p_vout, picture_t *p_src,
192 /* We got this one from the old arguments */
193 u16 *p_pic = (u16*)p_dest->p->p_pixels;
194 u8 *p_y = p_src->Y_PIXELS;
195 u8 *p_u = p_src->U_PIXELS;
196 u8 *p_v = p_src->V_PIXELS;
198 vlc_bool_t b_hscale; /* horizontal scaling type */
199 unsigned int i_vscale; /* vertical scaling type */
200 unsigned int i_x, i_y; /* horizontal and vertical indexes */
204 int i_scale_count; /* scale modulo counter */
205 int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
206 u16 * p_pic_start; /* beginning of the current line for copy */
207 #if defined (MODULE_NAME_IS_i420_rgb)
208 int i_uval, i_vval; /* U and V samples */
209 int i_red, i_green, i_blue; /* U and V modified samples */
210 u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16;
211 u16 * p_ybase; /* Y dependant conversion table */
214 /* Conversion buffer pointer */
215 u16 * p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer;
218 /* Offset array pointer */
219 int * p_offset_start = p_vout->chroma.p_sys->p_offset;
222 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
224 if( p_vout->render.i_width & 7 )
226 i_rewind = 8 - ( p_vout->render.i_width & 7 );
233 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
234 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
235 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
236 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
237 p_vout->output.i_width, p_vout->output.i_height,
238 &b_hscale, &i_vscale, p_offset_start );
243 i_scale_count = ( i_vscale == 1 ) ?
244 p_vout->output.i_height : p_vout->render.i_height;
245 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
248 p_buffer = b_hscale ? p_buffer_start : p_pic;
250 #if defined (MODULE_NAME_IS_i420_rgb)
251 for ( i_x = p_vout->render.i_width / 8; i_x--; )
253 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
254 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
255 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
256 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
258 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
259 if( p_vout->output.i_rmask == 0x7c00 )
262 for ( i_x = p_vout->render.i_width / 8; i_x--; )
265 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
271 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
282 for ( i_x = p_vout->render.i_width / 8; i_x--; )
285 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
291 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
301 /* Here we do some unaligned reads and duplicate conversions, but
302 * at least we have all the pixels */
306 p_u -= i_rewind >> 1;
307 p_v -= i_rewind >> 1;
308 p_buffer -= i_rewind;
309 #if defined (MODULE_NAME_IS_i420_rgb)
310 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
311 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
312 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
313 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
314 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
316 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
318 if( p_vout->output.i_rmask == 0x7c00 )
325 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
334 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
344 SCALE_HEIGHT( 420, 2 );
348 /*****************************************************************************
349 * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
350 *****************************************************************************
351 * Horizontal alignment needed:
352 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
353 * - output: 1 pixel (2 bytes), margins allowed
354 * Vertical alignment needed:
355 * - input: 2 lines (2 Y lines, 1 U/V line)
357 *****************************************************************************/
358 void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src,
361 /* We got this one from the old arguments */
362 u32 *p_pic = (u32*)p_dest->p->p_pixels;
363 u8 *p_y = p_src->Y_PIXELS;
364 u8 *p_u = p_src->U_PIXELS;
365 u8 *p_v = p_src->V_PIXELS;
367 vlc_bool_t b_hscale; /* horizontal scaling type */
368 unsigned int i_vscale; /* vertical scaling type */
369 unsigned int i_x, i_y; /* horizontal and vertical indexes */
373 int i_scale_count; /* scale modulo counter */
374 int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
375 u32 * p_pic_start; /* beginning of the current line for copy */
376 #if defined (MODULE_NAME_IS_i420_rgb)
377 int i_uval, i_vval; /* U and V samples */
378 int i_red, i_green, i_blue; /* U and V modified samples */
379 u32 * p_yuv = p_vout->chroma.p_sys->p_rgb32;
380 u32 * p_ybase; /* Y dependant conversion table */
383 /* Conversion buffer pointer */
384 u32 * p_buffer_start = (u32*)p_vout->chroma.p_sys->p_buffer;
387 /* Offset array pointer */
388 int * p_offset_start = p_vout->chroma.p_sys->p_offset;
391 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
393 if( p_vout->render.i_width & 7 )
395 i_rewind = 8 - ( p_vout->render.i_width & 7 );
402 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
403 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
404 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
405 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
406 p_vout->output.i_width, p_vout->output.i_height,
407 &b_hscale, &i_vscale, p_offset_start );
412 i_scale_count = ( i_vscale == 1 ) ?
413 p_vout->output.i_height : p_vout->render.i_height;
414 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
417 p_buffer = b_hscale ? p_buffer_start : p_pic;
419 for ( i_x = p_vout->render.i_width / 8; i_x--; )
421 #if defined (MODULE_NAME_IS_i420_rgb)
422 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
423 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
424 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
425 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
426 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
428 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
434 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
443 /* Here we do some unaligned reads and duplicate conversions, but
444 * at least we have all the pixels */
448 p_u -= i_rewind >> 1;
449 p_v -= i_rewind >> 1;
450 p_buffer -= i_rewind;
451 #if defined (MODULE_NAME_IS_i420_rgb)
452 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
453 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
454 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
455 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
456 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
458 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
464 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
473 SCALE_HEIGHT( 420, 4 );
477 /* Following functions are local */
479 /*****************************************************************************
480 * SetOffset: build offset array for conversion functions
481 *****************************************************************************
482 * This function will build an offset array used in later conversion functions.
483 * It will also set horizontal and vertical scaling indicators.
484 *****************************************************************************/
485 static void SetOffset( int i_width, int i_height, int i_pic_width,
486 int i_pic_height, vlc_bool_t *pb_hscale,
487 int *pi_vscale, int *p_offset )
489 int i_x; /* x position in destination */
490 int i_scale_count; /* modulo counter */
493 * Prepare horizontal offset array
495 if( i_pic_width - i_width == 0 )
497 /* No horizontal scaling: YUV conversion is done directly to picture */
500 else if( i_pic_width - i_width > 0 )
502 /* Prepare scaling array for horizontal extension */
504 i_scale_count = i_pic_width;
505 for( i_x = i_width; i_x--; )
507 while( (i_scale_count -= i_width) > 0 )
512 i_scale_count += i_pic_width;
515 else /* if( i_pic_width - i_width < 0 ) */
517 /* Prepare scaling array for horizontal reduction */
519 i_scale_count = i_width;
520 for( i_x = i_pic_width; i_x--; )
523 while( (i_scale_count -= i_pic_width) > 0 )
528 i_scale_count += i_width;
533 * Set vertical scaling indicator
535 if( i_pic_height - i_height == 0 )
539 else if( i_pic_height - i_height > 0 )
543 else /* if( i_pic_height - i_height < 0 ) */