1 /*****************************************************************************
2 * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000 VLC authors and VideoLAN
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Damien Fouilleul <damienf@videolan.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_filter.h>
34 #include "i420_rgb_c.h"
36 /*****************************************************************************
37 * SetOffset: build offset array for conversion functions
38 *****************************************************************************
39 * This function will build an offset array used in later conversion functions.
40 * It will also set horizontal and vertical scaling indicators.
41 *****************************************************************************/
42 static void SetOffset( int i_width, int i_height, int i_pic_width,
43 int i_pic_height, bool *pb_hscale,
44 unsigned int *pi_vscale, int *p_offset )
47 * Prepare horizontal offset array
49 if( i_pic_width - i_width == 0 )
50 { /* No horizontal scaling: YUV conversion is done directly to picture */
53 else if( i_pic_width - i_width > 0 )
54 { /* Prepare scaling array for horizontal extension */
55 int i_scale_count = i_pic_width;
58 for( int i_x = i_width; i_x--; )
60 while( (i_scale_count -= i_width) > 0 )
65 i_scale_count += i_pic_width;
68 else /* if( i_pic_width - i_width < 0 ) */
69 { /* Prepare scaling array for horizontal reduction */
70 int i_scale_count = i_pic_width;
73 for( int i_x = i_pic_width; i_x--; )
76 while( (i_scale_count -= i_pic_width) > 0 )
81 i_scale_count += i_width;
86 * Set vertical scaling indicator
88 if( i_pic_height - i_height == 0 )
90 else if( i_pic_height - i_height > 0 )
92 else /* if( i_pic_height - i_height < 0 ) */
96 /*****************************************************************************
97 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
98 *****************************************************************************
99 * Horizontal alignment needed:
100 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
101 * - output: 1 pixel (2 bytes), margins allowed
102 * Vertical alignment needed:
103 * - input: 2 lines (2 Y lines, 1 U/V line)
105 *****************************************************************************/
107 void I420_RGB16( filter_t *p_filter, picture_t *p_src, picture_t *p_dest )
109 /* We got this one from the old arguments */
110 uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
111 uint8_t *p_y = p_src->Y_PIXELS;
112 uint8_t *p_u = p_src->U_PIXELS;
113 uint8_t *p_v = p_src->V_PIXELS;
115 bool b_hscale; /* horizontal scaling type */
116 unsigned int i_vscale; /* vertical scaling type */
117 unsigned int i_x, i_y; /* horizontal and vertical indexes */
121 int i_scale_count; /* scale modulo counter */
122 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
123 uint16_t * p_pic_start; /* beginning of the current line for copy */
124 int i_uval, i_vval; /* U and V samples */
125 int i_red, i_green, i_blue; /* U and V modified samples */
126 uint16_t * p_yuv = p_filter->p_sys->p_rgb16;
127 uint16_t * p_ybase; /* Y dependant conversion table */
129 /* Conversion buffer pointer */
130 uint16_t * p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
133 /* Offset array pointer */
134 int * p_offset_start = p_filter->p_sys->p_offset;
137 const int i_source_margin = p_src->p[0].i_pitch
138 - p_src->p[0].i_visible_pitch;
139 const int i_source_margin_c = p_src->p[1].i_pitch
140 - p_src->p[1].i_visible_pitch;
142 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
143 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
145 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
146 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
147 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
148 SetOffset( p_filter->fmt_in.video.i_width,
149 p_filter->fmt_in.video.i_height,
150 p_filter->fmt_out.video.i_width,
151 p_filter->fmt_out.video.i_height,
152 &b_hscale, &i_vscale, p_offset_start );
157 i_scale_count = ( i_vscale == 1 ) ?
158 p_filter->fmt_out.video.i_height :
159 p_filter->fmt_in.video.i_height;
160 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
163 p_buffer = b_hscale ? p_buffer_start : p_pic;
165 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
167 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
168 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
169 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
170 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
173 /* Here we do some unaligned reads and duplicate conversions, but
174 * at least we have all the pixels */
178 p_u -= i_rewind >> 1;
179 p_v -= i_rewind >> 1;
180 p_buffer -= i_rewind;
182 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
183 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
184 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
185 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
188 SCALE_HEIGHT( 420, 2 );
190 p_y += i_source_margin;
193 p_u += i_source_margin_c;
194 p_v += i_source_margin_c;
199 /*****************************************************************************
200 * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
201 *****************************************************************************
202 * Horizontal alignment needed:
203 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
204 * - output: 1 pixel (2 bytes), margins allowed
205 * Vertical alignment needed:
206 * - input: 2 lines (2 Y lines, 1 U/V line)
208 *****************************************************************************/
210 void I420_RGB32( filter_t *p_filter, picture_t *p_src, picture_t *p_dest )
212 /* We got this one from the old arguments */
213 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
214 uint8_t *p_y = p_src->Y_PIXELS;
215 uint8_t *p_u = p_src->U_PIXELS;
216 uint8_t *p_v = p_src->V_PIXELS;
218 bool b_hscale; /* horizontal scaling type */
219 unsigned int i_vscale; /* vertical scaling type */
220 unsigned int i_x, i_y; /* horizontal and vertical indexes */
224 int i_scale_count; /* scale modulo counter */
225 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
226 uint32_t * p_pic_start; /* beginning of the current line for copy */
227 int i_uval, i_vval; /* U and V samples */
228 int i_red, i_green, i_blue; /* U and V modified samples */
229 uint32_t * p_yuv = p_filter->p_sys->p_rgb32;
230 uint32_t * p_ybase; /* Y dependant conversion table */
232 /* Conversion buffer pointer */
233 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
236 /* Offset array pointer */
237 int * p_offset_start = p_filter->p_sys->p_offset;
240 const int i_source_margin = p_src->p[0].i_pitch
241 - p_src->p[0].i_visible_pitch;
242 const int i_source_margin_c = p_src->p[1].i_pitch
243 - p_src->p[1].i_visible_pitch;
245 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
246 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
248 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
249 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
250 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
251 SetOffset( p_filter->fmt_in.video.i_width,
252 p_filter->fmt_in.video.i_height,
253 p_filter->fmt_out.video.i_width,
254 p_filter->fmt_out.video.i_height,
255 &b_hscale, &i_vscale, p_offset_start );
260 i_scale_count = ( i_vscale == 1 ) ?
261 p_filter->fmt_out.video.i_height :
262 p_filter->fmt_in.video.i_height;
263 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
266 p_buffer = b_hscale ? p_buffer_start : p_pic;
268 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
270 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
271 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
272 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
273 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
276 /* Here we do some unaligned reads and duplicate conversions, but
277 * at least we have all the pixels */
281 p_u -= i_rewind >> 1;
282 p_v -= i_rewind >> 1;
283 p_buffer -= i_rewind;
284 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
285 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
286 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
287 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
290 SCALE_HEIGHT( 420, 4 );
292 p_y += i_source_margin;
295 p_u += i_source_margin_c;
296 p_v += i_source_margin_c;