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.10 2002/07/31 20:56:51 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 <errno.h> /* ENOMEM */
28 #include <string.h> /* strerror() */
29 #include <stdlib.h> /* malloc(), free() */
35 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
36 # include "i420_rgb_c.h"
37 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
38 # include "i420_rgb_mmx.h"
41 static void SetOffset( int, int, int, int, vlc_bool_t *, int *, int * );
43 /*****************************************************************************
44 * I420_RGB15: color YUV 4:2:0 to RGB 15 bpp
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_RGB15)( 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 int i_x, i_y; /* horizontal and vertical indexes */
67 int i_scale_count; /* scale modulo counter */
68 int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
69 u16 * p_pic_start; /* beginning of the current line for copy */
70 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
71 int i_uval, i_vval; /* U and V samples */
72 int i_red, i_green, i_blue; /* U and V modified samples */
73 u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16;
74 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 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
87 if( p_vout->render.i_width & 7 )
89 i_rewind = 8 - ( p_vout->render.i_width & 7 );
96 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
97 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
98 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
99 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
100 p_vout->output.i_width, p_vout->output.i_height,
101 &b_hscale, &i_vscale, p_offset_start );
106 i_scale_count = ( i_vscale == 1 ) ?
107 p_vout->output.i_height : p_vout->render.i_height;
108 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
111 p_buffer = b_hscale ? p_buffer_start : p_pic;
113 for ( i_x = p_vout->render.i_width / 8; i_x--; )
115 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
116 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
117 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
118 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
119 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
120 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
122 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
128 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
137 /* Here we do some unaligned reads and duplicate conversions, but
138 * at least we have all the pixels */
142 p_u -= i_rewind >> 1;
143 p_v -= i_rewind >> 1;
144 p_buffer -= i_rewind;
145 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
146 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
147 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
148 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
149 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
150 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
152 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
158 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
167 SCALE_HEIGHT( 420, 2 );
171 /*****************************************************************************
172 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
173 *****************************************************************************
174 * Horizontal alignment needed:
175 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
176 * - output: 1 pixel (2 bytes), margins allowed
177 * Vertical alignment needed:
178 * - input: 2 lines (2 Y lines, 1 U/V line)
180 *****************************************************************************/
181 void E_(I420_RGB16)( vout_thread_t *p_vout, picture_t *p_src,
184 /* We got this one from the old arguments */
185 u16 *p_pic = (u16*)p_dest->p->p_pixels;
186 u8 *p_y = p_src->Y_PIXELS;
187 u8 *p_u = p_src->U_PIXELS;
188 u8 *p_v = p_src->V_PIXELS;
190 vlc_bool_t b_hscale; /* horizontal scaling type */
191 int i_vscale; /* vertical scaling type */
192 int i_x, i_y; /* horizontal and vertical indexes */
195 int i_scale_count; /* scale modulo counter */
196 int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
197 u16 * p_pic_start; /* beginning of the current line for copy */
198 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
199 int i_uval, i_vval; /* U and V samples */
200 int i_red, i_green, i_blue; /* U and V modified samples */
201 u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16;
202 u16 * p_ybase; /* Y dependant conversion table */
205 /* Conversion buffer pointer */
206 u16 * p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer;
209 /* Offset array pointer */
210 int * p_offset_start = p_vout->chroma.p_sys->p_offset;
213 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
215 if( p_vout->render.i_width & 7 )
217 i_rewind = 8 - ( p_vout->render.i_width & 7 );
224 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
225 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
226 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
227 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
228 p_vout->output.i_width, p_vout->output.i_height,
229 &b_hscale, &i_vscale, p_offset_start );
234 i_scale_count = ( i_vscale == 1 ) ?
235 p_vout->output.i_height : p_vout->render.i_height;
236 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
239 p_buffer = b_hscale ? p_buffer_start : p_pic;
241 for ( i_x = p_vout->render.i_width / 8; i_x--; )
243 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
244 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
245 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
246 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
247 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
248 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
250 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
256 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
265 /* Here we do some unaligned reads and duplicate conversions, but
266 * at least we have all the pixels */
270 p_u -= i_rewind >> 1;
271 p_v -= i_rewind >> 1;
272 p_buffer -= i_rewind;
273 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
274 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
275 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
276 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
277 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
278 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
280 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
286 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
295 SCALE_HEIGHT( 420, 2 );
299 /*****************************************************************************
300 * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
301 *****************************************************************************
302 * Horizontal alignment needed:
303 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
304 * - output: 1 pixel (2 bytes), margins allowed
305 * Vertical alignment needed:
306 * - input: 2 lines (2 Y lines, 1 U/V line)
308 *****************************************************************************/
309 void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src,
312 /* We got this one from the old arguments */
313 u32 *p_pic = (u32*)p_dest->p->p_pixels;
314 u8 *p_y = p_src->Y_PIXELS;
315 u8 *p_u = p_src->U_PIXELS;
316 u8 *p_v = p_src->V_PIXELS;
318 vlc_bool_t b_hscale; /* horizontal scaling type */
319 int i_vscale; /* vertical scaling type */
320 int i_x, i_y; /* horizontal and vertical indexes */
323 int i_scale_count; /* scale modulo counter */
324 int i_chroma_width = p_vout->render.i_width / 4; /* chroma width */
325 u32 * p_pic_start; /* beginning of the current line for copy */
326 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
327 int i_uval, i_vval; /* U and V samples */
328 int i_red, i_green, i_blue; /* U and V modified samples */
329 u32 * p_yuv = p_vout->chroma.p_sys->p_rgb32;
330 u32 * p_ybase; /* Y dependant conversion table */
333 /* Conversion buffer pointer */
334 u32 * p_buffer_start = (u32*)p_vout->chroma.p_sys->p_buffer;
337 /* Offset array pointer */
338 int * p_offset_start = p_vout->chroma.p_sys->p_offset;
341 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
343 if( p_vout->render.i_width & 7 )
345 i_rewind = 8 - ( p_vout->render.i_width & 7 );
352 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
353 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
354 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
355 SetOffset( p_vout->render.i_width, p_vout->render.i_height,
356 p_vout->output.i_width, p_vout->output.i_height,
357 &b_hscale, &i_vscale, p_offset_start );
362 i_scale_count = ( i_vscale == 1 ) ?
363 p_vout->output.i_height : p_vout->render.i_height;
364 for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
367 p_buffer = b_hscale ? p_buffer_start : p_pic;
369 for ( i_x = p_vout->render.i_width / 8; i_x--; )
371 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
372 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
373 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
374 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
375 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
376 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
378 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
384 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
393 /* Here we do some unaligned reads and duplicate conversions, but
394 * at least we have all the pixels */
398 p_u -= i_rewind >> 1;
399 p_v -= i_rewind >> 1;
400 p_buffer -= i_rewind;
401 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
402 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
403 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
404 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
405 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
406 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
408 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
414 : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
423 SCALE_HEIGHT( 420, 4 );
427 /* Following functions are local */
429 /*****************************************************************************
430 * SetOffset: build offset array for conversion functions
431 *****************************************************************************
432 * This function will build an offset array used in later conversion functions.
433 * It will also set horizontal and vertical scaling indicators.
434 *****************************************************************************/
435 static void SetOffset( int i_width, int i_height, int i_pic_width,
436 int i_pic_height, vlc_bool_t *pb_hscale,
437 int *pi_vscale, int *p_offset )
439 int i_x; /* x position in destination */
440 int i_scale_count; /* modulo counter */
443 * Prepare horizontal offset array
445 if( i_pic_width - i_width == 0 )
447 /* No horizontal scaling: YUV conversion is done directly to picture */
450 else if( i_pic_width - i_width > 0 )
452 /* Prepare scaling array for horizontal extension */
454 i_scale_count = i_pic_width;
455 for( i_x = i_width; i_x--; )
457 while( (i_scale_count -= i_width) > 0 )
462 i_scale_count += i_pic_width;
465 else /* if( i_pic_width - i_width < 0 ) */
467 /* Prepare scaling array for horizontal reduction */
469 i_scale_count = i_width;
470 for( i_x = i_pic_width; i_x--; )
473 while( (i_scale_count -= i_pic_width) > 0 )
478 i_scale_count += i_width;
483 * Set vertical scaling indicator
485 if( i_pic_height - i_height == 0 )
489 else if( i_pic_height - i_height > 0 )
493 else /* if( i_pic_height - i_height < 0 ) */