1 /*****************************************************************************
2 * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000 the VideoLAN team
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
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_filter.h>
37 #if defined (MODULE_NAME_IS_i420_rgb)
38 # include "i420_rgb_c.h"
39 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
40 # include "../mmx/i420_rgb_mmx.h"
41 #elif defined (MODULE_NAME_IS_i420_rgb_sse2)
42 # include "../mmx/i420_rgb_mmx.h"
45 static void SetOffset( int, int, int, int, bool *,
46 unsigned int *, int * );
48 #if defined (MODULE_NAME_IS_i420_rgb)
49 /*****************************************************************************
50 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp with dithering
51 *****************************************************************************
52 * Horizontal alignment needed:
53 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
54 * - output: 1 pixel (2 bytes), margins allowed
55 * Vertical alignment needed:
56 * - input: 2 lines (2 Y lines, 1 U/V line)
58 *****************************************************************************/
59 void I420_RGB16_dither( filter_t *p_filter, picture_t *p_src,
62 /* We got this one from the old arguments */
63 uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
64 uint8_t *p_y = p_src->Y_PIXELS;
65 uint8_t *p_u = p_src->U_PIXELS;
66 uint8_t *p_v = p_src->V_PIXELS;
68 bool b_hscale; /* horizontal scaling type */
69 unsigned int i_vscale; /* vertical scaling type */
70 unsigned int i_x, i_y; /* horizontal and vertical indexes */
71 unsigned int i_real_y; /* y % 4 */
75 int i_scale_count; /* scale modulo counter */
76 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
77 uint16_t * p_pic_start; /* beginning of the current line for copy */
78 int i_uval, i_vval; /* U and V samples */
79 int i_red, i_green, i_blue; /* U and V modified samples */
80 uint16_t * p_yuv = p_filter->p_sys->p_rgb16;
81 uint16_t * p_ybase; /* Y dependant conversion table */
83 /* Conversion buffer pointer */
84 uint16_t * p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
87 /* Offset array pointer */
88 int * p_offset_start = p_filter->p_sys->p_offset;
91 const int i_source_margin = p_src->p[0].i_pitch
92 - p_src->p[0].i_visible_pitch;
93 const int i_source_margin_c = p_src->p[1].i_pitch
94 - p_src->p[1].i_visible_pitch;
96 /* The dithering matrices */
97 int dither10[4] = { 0x0, 0x8, 0x2, 0xa };
98 int dither11[4] = { 0xc, 0x4, 0xe, 0x6 };
99 int dither12[4] = { 0x3, 0xb, 0x1, 0x9 };
100 int dither13[4] = { 0xf, 0x7, 0xd, 0x5 };
102 for(i_x = 0; i_x < 4; i_x++)
104 dither10[i_x] = dither10[i_x] << (SHIFT - 4 + p_filter->fmt_out.video.i_rrshift);
105 dither11[i_x] = dither11[i_x] << (SHIFT - 4 + p_filter->fmt_out.video.i_rrshift);
106 dither12[i_x] = dither12[i_x] << (SHIFT - 4 + p_filter->fmt_out.video.i_rrshift);
107 dither13[i_x] = dither13[i_x] << (SHIFT - 4 + p_filter->fmt_out.video.i_rrshift);
110 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
111 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
113 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
114 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
115 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
116 SetOffset( p_filter->fmt_in.video.i_width,
117 p_filter->fmt_in.video.i_height,
118 p_filter->fmt_out.video.i_width,
119 p_filter->fmt_out.video.i_height,
120 &b_hscale, &i_vscale, p_offset_start );
125 i_scale_count = ( i_vscale == 1 ) ?
126 p_filter->fmt_out.video.i_height :
127 p_filter->fmt_in.video.i_height;
128 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
130 i_real_y = i_y & 0x3;
132 p_buffer = b_hscale ? p_buffer_start : p_pic;
134 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
136 int *p_dither = dither10;
137 CONVERT_YUV_PIXEL_DITHER(2);
139 CONVERT_Y_PIXEL_DITHER(2);
141 CONVERT_YUV_PIXEL_DITHER(2);
143 CONVERT_Y_PIXEL_DITHER(2);
145 CONVERT_YUV_PIXEL_DITHER(2);
147 CONVERT_Y_PIXEL_DITHER(2);
149 CONVERT_YUV_PIXEL_DITHER(2);
151 CONVERT_Y_PIXEL_DITHER(2);
154 /* Here we do some unaligned reads and duplicate conversions, but
155 * at least we have all the pixels */
158 int *p_dither = dither10;
160 p_u -= i_rewind >> 1;
161 p_v -= i_rewind >> 1;
162 p_buffer -= i_rewind;
163 CONVERT_YUV_PIXEL_DITHER(2);
165 CONVERT_Y_PIXEL_DITHER(2);
167 CONVERT_YUV_PIXEL_DITHER(2);
169 CONVERT_Y_PIXEL_DITHER(2);
171 CONVERT_YUV_PIXEL_DITHER(2);
173 CONVERT_Y_PIXEL_DITHER(2);
175 CONVERT_YUV_PIXEL_DITHER(2);
177 CONVERT_Y_PIXEL_DITHER(2);
180 SCALE_HEIGHT( 420, 2 );
182 p_y += i_source_margin;
185 p_u += i_source_margin_c;
186 p_v += i_source_margin_c;
192 /*****************************************************************************
193 * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
194 *****************************************************************************
195 * Horizontal alignment needed:
196 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
197 * - output: 1 pixel (2 bytes), margins allowed
198 * Vertical alignment needed:
199 * - input: 2 lines (2 Y lines, 1 U/V line)
201 *****************************************************************************/
203 #if defined (MODULE_NAME_IS_i420_rgb)
205 void I420_RGB16( filter_t *p_filter, picture_t *p_src,
208 /* We got this one from the old arguments */
209 uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
210 uint8_t *p_y = p_src->Y_PIXELS;
211 uint8_t *p_u = p_src->U_PIXELS;
212 uint8_t *p_v = p_src->V_PIXELS;
214 bool b_hscale; /* horizontal scaling type */
215 unsigned int i_vscale; /* vertical scaling type */
216 unsigned int i_x, i_y; /* horizontal and vertical indexes */
220 int i_scale_count; /* scale modulo counter */
221 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
222 uint16_t * p_pic_start; /* beginning of the current line for copy */
223 int i_uval, i_vval; /* U and V samples */
224 int i_red, i_green, i_blue; /* U and V modified samples */
225 uint16_t * p_yuv = p_filter->p_sys->p_rgb16;
226 uint16_t * p_ybase; /* Y dependant conversion table */
228 /* Conversion buffer pointer */
229 uint16_t * p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
232 /* Offset array pointer */
233 int * p_offset_start = p_filter->p_sys->p_offset;
236 const int i_source_margin = p_src->p[0].i_pitch
237 - p_src->p[0].i_visible_pitch;
238 const int i_source_margin_c = p_src->p[1].i_pitch
239 - p_src->p[1].i_visible_pitch;
241 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
242 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
244 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
245 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
246 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
247 SetOffset( p_filter->fmt_in.video.i_width,
248 p_filter->fmt_in.video.i_height,
249 p_filter->fmt_out.video.i_width,
250 p_filter->fmt_out.video.i_height,
251 &b_hscale, &i_vscale, p_offset_start );
256 i_scale_count = ( i_vscale == 1 ) ?
257 p_filter->fmt_out.video.i_height :
258 p_filter->fmt_in.video.i_height;
259 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
262 p_buffer = b_hscale ? p_buffer_start : p_pic;
264 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
266 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
267 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
268 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
269 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
272 /* Here we do some unaligned reads and duplicate conversions, but
273 * at least we have all the pixels */
277 p_u -= i_rewind >> 1;
278 p_v -= i_rewind >> 1;
279 p_buffer -= i_rewind;
281 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
282 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
283 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
284 CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2);
287 SCALE_HEIGHT( 420, 2 );
289 p_y += i_source_margin;
292 p_u += i_source_margin_c;
293 p_v += i_source_margin_c;
298 #else // ! defined (MODULE_NAME_IS_i420_rgb)
300 void I420_R5G5B5( filter_t *p_filter, picture_t *p_src,
303 /* We got this one from the old arguments */
304 uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
305 uint8_t *p_y = p_src->Y_PIXELS;
306 uint8_t *p_u = p_src->U_PIXELS;
307 uint8_t *p_v = p_src->V_PIXELS;
309 bool b_hscale; /* horizontal scaling type */
310 unsigned int i_vscale; /* vertical scaling type */
311 unsigned int i_x, i_y; /* horizontal and vertical indexes */
315 int i_scale_count; /* scale modulo counter */
316 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
317 uint16_t * p_pic_start; /* beginning of the current line for copy */
319 /* Conversion buffer pointer */
320 uint16_t * p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
323 /* Offset array pointer */
324 int * p_offset_start = p_filter->p_sys->p_offset;
327 const int i_source_margin = p_src->p[0].i_pitch
328 - p_src->p[0].i_visible_pitch;
329 const int i_source_margin_c = p_src->p[1].i_pitch
330 - p_src->p[1].i_visible_pitch;
332 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
334 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
335 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
336 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
337 SetOffset( p_filter->fmt_in.video.i_width,
338 p_filter->fmt_in.video.i_height,
339 p_filter->fmt_out.video.i_width,
340 p_filter->fmt_out.video.i_height,
341 &b_hscale, &i_vscale, p_offset_start );
347 i_scale_count = ( i_vscale == 1 ) ?
348 p_filter->fmt_out.video.i_height :
349 p_filter->fmt_in.video.i_height;
351 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
353 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
356 ** SSE2 128 bits fetch/store instructions are faster
357 ** if memory access is 16 bytes aligned
360 p_buffer = b_hscale ? p_buffer_start : p_pic;
361 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
364 ((intptr_t)p_buffer))) )
366 /* use faster SSE2 aligned fetch and store */
367 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
371 for ( i_x = p_filter->fmt_in.video.i_width/16; i_x--; )
377 SSE2_UNPACK_15_ALIGNED
384 /* Here we do some unaligned reads and duplicate conversions, but
385 * at least we have all the pixels */
389 p_u -= i_rewind >> 1;
390 p_v -= i_rewind >> 1;
391 p_buffer -= i_rewind;
394 SSE2_INIT_16_UNALIGNED
397 SSE2_UNPACK_15_UNALIGNED
404 SCALE_HEIGHT( 420, 2 );
406 p_y += i_source_margin;
409 p_u += i_source_margin_c;
410 p_v += i_source_margin_c;
412 p_buffer = b_hscale ? p_buffer_start : p_pic;
417 /* use slower SSE2 unaligned fetch and store */
418 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
421 p_buffer = b_hscale ? p_buffer_start : p_pic;
423 for ( i_x = p_filter->fmt_in.video.i_width/16; i_x--; )
426 SSE2_INIT_16_UNALIGNED
429 SSE2_UNPACK_15_UNALIGNED
436 /* Here we do some unaligned reads and duplicate conversions, but
437 * at least we have all the pixels */
441 p_u -= i_rewind >> 1;
442 p_v -= i_rewind >> 1;
443 p_buffer -= i_rewind;
446 SSE2_INIT_16_UNALIGNED
449 SSE2_UNPACK_15_UNALIGNED
456 SCALE_HEIGHT( 420, 2 );
458 p_y += i_source_margin;
461 p_u += i_source_margin_c;
462 p_v += i_source_margin_c;
464 p_buffer = b_hscale ? p_buffer_start : p_pic;
468 /* make sure all SSE2 stores are visible thereafter */
471 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
473 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
475 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
478 p_buffer = b_hscale ? p_buffer_start : p_pic;
480 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
494 /* Here we do some unaligned reads and duplicate conversions, but
495 * at least we have all the pixels */
499 p_u -= i_rewind >> 1;
500 p_v -= i_rewind >> 1;
501 p_buffer -= i_rewind;
515 SCALE_HEIGHT( 420, 2 );
517 p_y += i_source_margin;
520 p_u += i_source_margin_c;
521 p_v += i_source_margin_c;
524 /* re-enable FPU registers */
530 void I420_R5G6B5( filter_t *p_filter, picture_t *p_src,
533 /* We got this one from the old arguments */
534 uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
535 uint8_t *p_y = p_src->Y_PIXELS;
536 uint8_t *p_u = p_src->U_PIXELS;
537 uint8_t *p_v = p_src->V_PIXELS;
539 bool b_hscale; /* horizontal scaling type */
540 unsigned int i_vscale; /* vertical scaling type */
541 unsigned int i_x, i_y; /* horizontal and vertical indexes */
545 int i_scale_count; /* scale modulo counter */
546 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
547 uint16_t * p_pic_start; /* beginning of the current line for copy */
549 /* Conversion buffer pointer */
550 uint16_t * p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
553 /* Offset array pointer */
554 int * p_offset_start = p_filter->p_sys->p_offset;
557 const int i_source_margin = p_src->p[0].i_pitch
558 - p_src->p[0].i_visible_pitch;
559 const int i_source_margin_c = p_src->p[1].i_pitch
560 - p_src->p[1].i_visible_pitch;
562 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
564 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
565 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
566 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
567 SetOffset( p_filter->fmt_in.video.i_width,
568 p_filter->fmt_in.video.i_height,
569 p_filter->fmt_out.video.i_width,
570 p_filter->fmt_out.video.i_height,
571 &b_hscale, &i_vscale, p_offset_start );
577 i_scale_count = ( i_vscale == 1 ) ?
578 p_filter->fmt_out.video.i_height :
579 p_filter->fmt_in.video.i_height;
581 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
583 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
586 ** SSE2 128 bits fetch/store instructions are faster
587 ** if memory access is 16 bytes aligned
590 p_buffer = b_hscale ? p_buffer_start : p_pic;
591 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
594 ((intptr_t)p_buffer))) )
596 /* use faster SSE2 aligned fetch and store */
597 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
601 for ( i_x = p_filter->fmt_in.video.i_width/16; i_x--; )
607 SSE2_UNPACK_16_ALIGNED
614 /* Here we do some unaligned reads and duplicate conversions, but
615 * at least we have all the pixels */
619 p_u -= i_rewind >> 1;
620 p_v -= i_rewind >> 1;
621 p_buffer -= i_rewind;
624 SSE2_INIT_16_UNALIGNED
627 SSE2_UNPACK_16_UNALIGNED
634 SCALE_HEIGHT( 420, 2 );
636 p_y += i_source_margin;
639 p_u += i_source_margin_c;
640 p_v += i_source_margin_c;
642 p_buffer = b_hscale ? p_buffer_start : p_pic;
647 /* use slower SSE2 unaligned fetch and store */
648 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
651 p_buffer = b_hscale ? p_buffer_start : p_pic;
653 for ( i_x = p_filter->fmt_in.video.i_width/16; i_x--; )
656 SSE2_INIT_16_UNALIGNED
659 SSE2_UNPACK_16_UNALIGNED
666 /* Here we do some unaligned reads and duplicate conversions, but
667 * at least we have all the pixels */
671 p_u -= i_rewind >> 1;
672 p_v -= i_rewind >> 1;
673 p_buffer -= i_rewind;
676 SSE2_INIT_16_UNALIGNED
679 SSE2_UNPACK_16_UNALIGNED
686 SCALE_HEIGHT( 420, 2 );
688 p_y += i_source_margin;
691 p_u += i_source_margin_c;
692 p_v += i_source_margin_c;
694 p_buffer = b_hscale ? p_buffer_start : p_pic;
698 /* make sure all SSE2 stores are visible thereafter */
701 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
703 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
705 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
708 p_buffer = b_hscale ? p_buffer_start : p_pic;
710 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
724 /* Here we do some unaligned reads and duplicate conversions, but
725 * at least we have all the pixels */
729 p_u -= i_rewind >> 1;
730 p_v -= i_rewind >> 1;
731 p_buffer -= i_rewind;
745 SCALE_HEIGHT( 420, 2 );
747 p_y += i_source_margin;
750 p_u += i_source_margin_c;
751 p_v += i_source_margin_c;
754 /* re-enable FPU registers */
762 /*****************************************************************************
763 * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
764 *****************************************************************************
765 * Horizontal alignment needed:
766 * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
767 * - output: 1 pixel (2 bytes), margins allowed
768 * Vertical alignment needed:
769 * - input: 2 lines (2 Y lines, 1 U/V line)
771 *****************************************************************************/
773 #if defined (MODULE_NAME_IS_i420_rgb)
775 void I420_RGB32( filter_t *p_filter, picture_t *p_src,
778 /* We got this one from the old arguments */
779 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
780 uint8_t *p_y = p_src->Y_PIXELS;
781 uint8_t *p_u = p_src->U_PIXELS;
782 uint8_t *p_v = p_src->V_PIXELS;
784 bool b_hscale; /* horizontal scaling type */
785 unsigned int i_vscale; /* vertical scaling type */
786 unsigned int i_x, i_y; /* horizontal and vertical indexes */
790 int i_scale_count; /* scale modulo counter */
791 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
792 uint32_t * p_pic_start; /* beginning of the current line for copy */
793 int i_uval, i_vval; /* U and V samples */
794 int i_red, i_green, i_blue; /* U and V modified samples */
795 uint32_t * p_yuv = p_filter->p_sys->p_rgb32;
796 uint32_t * p_ybase; /* Y dependant conversion table */
798 /* Conversion buffer pointer */
799 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
802 /* Offset array pointer */
803 int * p_offset_start = p_filter->p_sys->p_offset;
806 const int i_source_margin = p_src->p[0].i_pitch
807 - p_src->p[0].i_visible_pitch;
808 const int i_source_margin_c = p_src->p[1].i_pitch
809 - p_src->p[1].i_visible_pitch;
811 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
812 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
814 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
815 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
816 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
817 SetOffset( p_filter->fmt_in.video.i_width,
818 p_filter->fmt_in.video.i_height,
819 p_filter->fmt_out.video.i_width,
820 p_filter->fmt_out.video.i_height,
821 &b_hscale, &i_vscale, p_offset_start );
826 i_scale_count = ( i_vscale == 1 ) ?
827 p_filter->fmt_out.video.i_height :
828 p_filter->fmt_in.video.i_height;
829 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
832 p_buffer = b_hscale ? p_buffer_start : p_pic;
834 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
836 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
837 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
838 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
839 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
842 /* Here we do some unaligned reads and duplicate conversions, but
843 * at least we have all the pixels */
847 p_u -= i_rewind >> 1;
848 p_v -= i_rewind >> 1;
849 p_buffer -= i_rewind;
850 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
851 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
852 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
853 CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4);
856 SCALE_HEIGHT( 420, 4 );
858 p_y += i_source_margin;
861 p_u += i_source_margin_c;
862 p_v += i_source_margin_c;
867 #else // defined (MODULE_NAME_IS_i420_rgb_mmx) || defined (MODULE_NAME_IS_i420_rgb_sse2)
869 void I420_A8R8G8B8( filter_t *p_filter, picture_t *p_src,
872 /* We got this one from the old arguments */
873 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
874 uint8_t *p_y = p_src->Y_PIXELS;
875 uint8_t *p_u = p_src->U_PIXELS;
876 uint8_t *p_v = p_src->V_PIXELS;
878 bool b_hscale; /* horizontal scaling type */
879 unsigned int i_vscale; /* vertical scaling type */
880 unsigned int i_x, i_y; /* horizontal and vertical indexes */
884 int i_scale_count; /* scale modulo counter */
885 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
886 uint32_t * p_pic_start; /* beginning of the current line for copy */
887 /* Conversion buffer pointer */
888 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
891 /* Offset array pointer */
892 int * p_offset_start = p_filter->p_sys->p_offset;
895 const int i_source_margin = p_src->p[0].i_pitch
896 - p_src->p[0].i_visible_pitch;
897 const int i_source_margin_c = p_src->p[1].i_pitch
898 - p_src->p[1].i_visible_pitch;
900 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
902 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
903 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
904 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
905 SetOffset( p_filter->fmt_in.video.i_width,
906 p_filter->fmt_in.video.i_height,
907 p_filter->fmt_out.video.i_width,
908 p_filter->fmt_out.video.i_height,
909 &b_hscale, &i_vscale, p_offset_start );
914 i_scale_count = ( i_vscale == 1 ) ?
915 p_filter->fmt_out.video.i_height :
916 p_filter->fmt_in.video.i_height;
918 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
920 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
923 ** SSE2 128 bits fetch/store instructions are faster
924 ** if memory access is 16 bytes aligned
927 p_buffer = b_hscale ? p_buffer_start : p_pic;
928 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
931 ((intptr_t)p_buffer))) )
933 /* use faster SSE2 aligned fetch and store */
934 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
938 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
944 SSE2_UNPACK_32_ARGB_ALIGNED
952 /* Here we do some unaligned reads and duplicate conversions, but
953 * at least we have all the pixels */
957 p_u -= i_rewind >> 1;
958 p_v -= i_rewind >> 1;
959 p_buffer -= i_rewind;
961 SSE2_INIT_32_UNALIGNED
964 SSE2_UNPACK_32_ARGB_UNALIGNED
971 SCALE_HEIGHT( 420, 4 );
973 p_y += i_source_margin;
976 p_u += i_source_margin_c;
977 p_v += i_source_margin_c;
979 p_buffer = b_hscale ? p_buffer_start : p_pic;
984 /* use slower SSE2 unaligned fetch and store */
985 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
988 p_buffer = b_hscale ? p_buffer_start : p_pic;
990 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
993 SSE2_INIT_32_UNALIGNED
996 SSE2_UNPACK_32_ARGB_UNALIGNED
1004 /* Here we do some unaligned reads and duplicate conversions, but
1005 * at least we have all the pixels */
1009 p_u -= i_rewind >> 1;
1010 p_v -= i_rewind >> 1;
1011 p_buffer -= i_rewind;
1013 SSE2_INIT_32_UNALIGNED
1016 SSE2_UNPACK_32_ARGB_UNALIGNED
1023 SCALE_HEIGHT( 420, 4 );
1025 p_y += i_source_margin;
1028 p_u += i_source_margin_c;
1029 p_v += i_source_margin_c;
1031 p_buffer = b_hscale ? p_buffer_start : p_pic;
1035 /* make sure all SSE2 stores are visible thereafter */
1038 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
1040 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
1042 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1044 p_pic_start = p_pic;
1045 p_buffer = b_hscale ? p_buffer_start : p_pic;
1047 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
1061 /* Here we do some unaligned reads and duplicate conversions, but
1062 * at least we have all the pixels */
1066 p_u -= i_rewind >> 1;
1067 p_v -= i_rewind >> 1;
1068 p_buffer -= i_rewind;
1081 SCALE_HEIGHT( 420, 4 );
1083 p_y += i_source_margin;
1086 p_u += i_source_margin_c;
1087 p_v += i_source_margin_c;
1091 /* re-enable FPU registers */
1097 void I420_R8G8B8A8( filter_t *p_filter, picture_t *p_src,
1100 /* We got this one from the old arguments */
1101 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1102 uint8_t *p_y = p_src->Y_PIXELS;
1103 uint8_t *p_u = p_src->U_PIXELS;
1104 uint8_t *p_v = p_src->V_PIXELS;
1106 bool b_hscale; /* horizontal scaling type */
1107 unsigned int i_vscale; /* vertical scaling type */
1108 unsigned int i_x, i_y; /* horizontal and vertical indexes */
1112 int i_scale_count; /* scale modulo counter */
1113 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
1114 uint32_t * p_pic_start; /* beginning of the current line for copy */
1115 /* Conversion buffer pointer */
1116 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
1117 uint32_t * p_buffer;
1119 /* Offset array pointer */
1120 int * p_offset_start = p_filter->p_sys->p_offset;
1123 const int i_source_margin = p_src->p[0].i_pitch
1124 - p_src->p[0].i_visible_pitch;
1125 const int i_source_margin_c = p_src->p[1].i_pitch
1126 - p_src->p[1].i_visible_pitch;
1128 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1130 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1131 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1132 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1133 SetOffset( p_filter->fmt_in.video.i_width,
1134 p_filter->fmt_in.video.i_height,
1135 p_filter->fmt_out.video.i_width,
1136 p_filter->fmt_out.video.i_height,
1137 &b_hscale, &i_vscale, p_offset_start );
1140 * Perform conversion
1142 i_scale_count = ( i_vscale == 1 ) ?
1143 p_filter->fmt_out.video.i_height :
1144 p_filter->fmt_in.video.i_height;
1146 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1148 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
1151 ** SSE2 128 bits fetch/store instructions are faster
1152 ** if memory access is 16 bytes aligned
1155 p_buffer = b_hscale ? p_buffer_start : p_pic;
1156 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1159 ((intptr_t)p_buffer))) )
1161 /* use faster SSE2 aligned fetch and store */
1162 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1164 p_pic_start = p_pic;
1166 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1169 SSE2_INIT_32_ALIGNED
1172 SSE2_UNPACK_32_RGBA_ALIGNED
1180 /* Here we do some unaligned reads and duplicate conversions, but
1181 * at least we have all the pixels */
1185 p_u -= i_rewind >> 1;
1186 p_v -= i_rewind >> 1;
1187 p_buffer -= i_rewind;
1189 SSE2_INIT_32_UNALIGNED
1192 SSE2_UNPACK_32_RGBA_UNALIGNED
1199 SCALE_HEIGHT( 420, 4 );
1201 p_y += i_source_margin;
1204 p_u += i_source_margin_c;
1205 p_v += i_source_margin_c;
1207 p_buffer = b_hscale ? p_buffer_start : p_pic;
1212 /* use slower SSE2 unaligned fetch and store */
1213 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1215 p_pic_start = p_pic;
1216 p_buffer = b_hscale ? p_buffer_start : p_pic;
1218 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1221 SSE2_INIT_32_UNALIGNED
1224 SSE2_UNPACK_32_RGBA_UNALIGNED
1232 /* Here we do some unaligned reads and duplicate conversions, but
1233 * at least we have all the pixels */
1237 p_u -= i_rewind >> 1;
1238 p_v -= i_rewind >> 1;
1239 p_buffer -= i_rewind;
1241 SSE2_INIT_32_UNALIGNED
1244 SSE2_UNPACK_32_RGBA_UNALIGNED
1251 SCALE_HEIGHT( 420, 4 );
1253 p_y += i_source_margin;
1256 p_u += i_source_margin_c;
1257 p_v += i_source_margin_c;
1259 p_buffer = b_hscale ? p_buffer_start : p_pic;
1263 /* make sure all SSE2 stores are visible thereafter */
1266 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
1268 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
1270 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1272 p_pic_start = p_pic;
1273 p_buffer = b_hscale ? p_buffer_start : p_pic;
1275 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
1289 /* Here we do some unaligned reads and duplicate conversions, but
1290 * at least we have all the pixels */
1294 p_u -= i_rewind >> 1;
1295 p_v -= i_rewind >> 1;
1296 p_buffer -= i_rewind;
1309 SCALE_HEIGHT( 420, 4 );
1311 p_y += i_source_margin;
1314 p_u += i_source_margin_c;
1315 p_v += i_source_margin_c;
1319 /* re-enable FPU registers */
1325 void I420_B8G8R8A8( filter_t *p_filter, picture_t *p_src,
1328 /* We got this one from the old arguments */
1329 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1330 uint8_t *p_y = p_src->Y_PIXELS;
1331 uint8_t *p_u = p_src->U_PIXELS;
1332 uint8_t *p_v = p_src->V_PIXELS;
1334 bool b_hscale; /* horizontal scaling type */
1335 unsigned int i_vscale; /* vertical scaling type */
1336 unsigned int i_x, i_y; /* horizontal and vertical indexes */
1340 int i_scale_count; /* scale modulo counter */
1341 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
1342 uint32_t * p_pic_start; /* beginning of the current line for copy */
1343 /* Conversion buffer pointer */
1344 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
1345 uint32_t * p_buffer;
1347 /* Offset array pointer */
1348 int * p_offset_start = p_filter->p_sys->p_offset;
1351 const int i_source_margin = p_src->p[0].i_pitch
1352 - p_src->p[0].i_visible_pitch;
1353 const int i_source_margin_c = p_src->p[1].i_pitch
1354 - p_src->p[1].i_visible_pitch;
1356 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1358 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1359 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1360 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1361 SetOffset( p_filter->fmt_in.video.i_width,
1362 p_filter->fmt_in.video.i_height,
1363 p_filter->fmt_out.video.i_width,
1364 p_filter->fmt_out.video.i_height,
1365 &b_hscale, &i_vscale, p_offset_start );
1368 * Perform conversion
1370 i_scale_count = ( i_vscale == 1 ) ?
1371 p_filter->fmt_out.video.i_height :
1372 p_filter->fmt_in.video.i_height;
1374 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1376 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
1379 ** SSE2 128 bits fetch/store instructions are faster
1380 ** if memory access is 16 bytes aligned
1383 p_buffer = b_hscale ? p_buffer_start : p_pic;
1384 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1387 ((intptr_t)p_buffer))) )
1389 /* use faster SSE2 aligned fetch and store */
1390 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1392 p_pic_start = p_pic;
1394 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1397 SSE2_INIT_32_ALIGNED
1400 SSE2_UNPACK_32_BGRA_ALIGNED
1408 /* Here we do some unaligned reads and duplicate conversions, but
1409 * at least we have all the pixels */
1413 p_u -= i_rewind >> 1;
1414 p_v -= i_rewind >> 1;
1415 p_buffer -= i_rewind;
1417 SSE2_INIT_32_UNALIGNED
1420 SSE2_UNPACK_32_BGRA_UNALIGNED
1427 SCALE_HEIGHT( 420, 4 );
1429 p_y += i_source_margin;
1432 p_u += i_source_margin_c;
1433 p_v += i_source_margin_c;
1435 p_buffer = b_hscale ? p_buffer_start : p_pic;
1440 /* use slower SSE2 unaligned fetch and store */
1441 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1443 p_pic_start = p_pic;
1444 p_buffer = b_hscale ? p_buffer_start : p_pic;
1446 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1449 SSE2_INIT_32_UNALIGNED
1452 SSE2_UNPACK_32_BGRA_UNALIGNED
1460 /* Here we do some unaligned reads and duplicate conversions, but
1461 * at least we have all the pixels */
1465 p_u -= i_rewind >> 1;
1466 p_v -= i_rewind >> 1;
1467 p_buffer -= i_rewind;
1469 SSE2_INIT_32_UNALIGNED
1472 SSE2_UNPACK_32_BGRA_UNALIGNED
1479 SCALE_HEIGHT( 420, 4 );
1481 p_y += i_source_margin;
1484 p_u += i_source_margin_c;
1485 p_v += i_source_margin_c;
1487 p_buffer = b_hscale ? p_buffer_start : p_pic;
1493 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
1495 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1497 p_pic_start = p_pic;
1498 p_buffer = b_hscale ? p_buffer_start : p_pic;
1500 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
1514 /* Here we do some unaligned reads and duplicate conversions, but
1515 * at least we have all the pixels */
1519 p_u -= i_rewind >> 1;
1520 p_v -= i_rewind >> 1;
1521 p_buffer -= i_rewind;
1534 SCALE_HEIGHT( 420, 4 );
1536 p_y += i_source_margin;
1539 p_u += i_source_margin_c;
1540 p_v += i_source_margin_c;
1544 /* re-enable FPU registers */
1550 void I420_A8B8G8R8( filter_t *p_filter, picture_t *p_src,
1553 /* We got this one from the old arguments */
1554 uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1555 uint8_t *p_y = p_src->Y_PIXELS;
1556 uint8_t *p_u = p_src->U_PIXELS;
1557 uint8_t *p_v = p_src->V_PIXELS;
1559 bool b_hscale; /* horizontal scaling type */
1560 unsigned int i_vscale; /* vertical scaling type */
1561 unsigned int i_x, i_y; /* horizontal and vertical indexes */
1565 int i_scale_count; /* scale modulo counter */
1566 int i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
1567 uint32_t * p_pic_start; /* beginning of the current line for copy */
1568 /* Conversion buffer pointer */
1569 uint32_t * p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
1570 uint32_t * p_buffer;
1572 /* Offset array pointer */
1573 int * p_offset_start = p_filter->p_sys->p_offset;
1576 const int i_source_margin = p_src->p[0].i_pitch
1577 - p_src->p[0].i_visible_pitch;
1578 const int i_source_margin_c = p_src->p[1].i_pitch
1579 - p_src->p[1].i_visible_pitch;
1581 i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1583 /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1584 * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1585 * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1586 SetOffset( p_filter->fmt_in.video.i_width,
1587 p_filter->fmt_in.video.i_height,
1588 p_filter->fmt_out.video.i_width,
1589 p_filter->fmt_out.video.i_height,
1590 &b_hscale, &i_vscale, p_offset_start );
1593 * Perform conversion
1595 i_scale_count = ( i_vscale == 1 ) ?
1596 p_filter->fmt_out.video.i_height :
1597 p_filter->fmt_in.video.i_height;
1599 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1601 i_rewind = (-p_filter->fmt_in.video.i_width) & 15;
1604 ** SSE2 128 bits fetch/store instructions are faster
1605 ** if memory access is 16 bytes aligned
1608 p_buffer = b_hscale ? p_buffer_start : p_pic;
1609 if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1612 ((intptr_t)p_buffer))) )
1614 /* use faster SSE2 aligned fetch and store */
1615 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1617 p_pic_start = p_pic;
1619 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1622 SSE2_INIT_32_ALIGNED
1625 SSE2_UNPACK_32_ABGR_ALIGNED
1633 /* Here we do some unaligned reads and duplicate conversions, but
1634 * at least we have all the pixels */
1638 p_u -= i_rewind >> 1;
1639 p_v -= i_rewind >> 1;
1640 p_buffer -= i_rewind;
1642 SSE2_INIT_32_UNALIGNED
1645 SSE2_UNPACK_32_ABGR_UNALIGNED
1652 SCALE_HEIGHT( 420, 4 );
1654 p_y += i_source_margin;
1657 p_u += i_source_margin_c;
1658 p_v += i_source_margin_c;
1660 p_buffer = b_hscale ? p_buffer_start : p_pic;
1665 /* use slower SSE2 unaligned fetch and store */
1666 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1668 p_pic_start = p_pic;
1669 p_buffer = b_hscale ? p_buffer_start : p_pic;
1671 for ( i_x = p_filter->fmt_in.video.i_width / 16; i_x--; )
1674 SSE2_INIT_32_UNALIGNED
1677 SSE2_UNPACK_32_ABGR_UNALIGNED
1685 /* Here we do some unaligned reads and duplicate conversions, but
1686 * at least we have all the pixels */
1690 p_u -= i_rewind >> 1;
1691 p_v -= i_rewind >> 1;
1692 p_buffer -= i_rewind;
1694 SSE2_INIT_32_UNALIGNED
1697 SSE2_UNPACK_32_ABGR_UNALIGNED
1704 SCALE_HEIGHT( 420, 4 );
1706 p_y += i_source_margin;
1709 p_u += i_source_margin_c;
1710 p_v += i_source_margin_c;
1712 p_buffer = b_hscale ? p_buffer_start : p_pic;
1718 i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
1720 for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
1722 p_pic_start = p_pic;
1723 p_buffer = b_hscale ? p_buffer_start : p_pic;
1725 for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
1739 /* Here we do some unaligned reads and duplicate conversions, but
1740 * at least we have all the pixels */
1744 p_u -= i_rewind >> 1;
1745 p_v -= i_rewind >> 1;
1746 p_buffer -= i_rewind;
1759 SCALE_HEIGHT( 420, 4 );
1761 p_y += i_source_margin;
1764 p_u += i_source_margin_c;
1765 p_v += i_source_margin_c;
1769 /* re-enable FPU registers */
1777 /* Following functions are local */
1779 /*****************************************************************************
1780 * SetOffset: build offset array for conversion functions
1781 *****************************************************************************
1782 * This function will build an offset array used in later conversion functions.
1783 * It will also set horizontal and vertical scaling indicators.
1784 *****************************************************************************/
1785 static void SetOffset( int i_width, int i_height, int i_pic_width,
1786 int i_pic_height, bool *pb_hscale,
1787 unsigned int *pi_vscale, int *p_offset )
1789 int i_x; /* x position in destination */
1790 int i_scale_count; /* modulo counter */
1793 * Prepare horizontal offset array
1795 if( i_pic_width - i_width == 0 )
1797 /* No horizontal scaling: YUV conversion is done directly to picture */
1800 else if( i_pic_width - i_width > 0 )
1802 /* Prepare scaling array for horizontal extension */
1804 i_scale_count = i_pic_width;
1805 for( i_x = i_width; i_x--; )
1807 while( (i_scale_count -= i_width) > 0 )
1812 i_scale_count += i_pic_width;
1815 else /* if( i_pic_width - i_width < 0 ) */
1817 /* Prepare scaling array for horizontal reduction */
1819 i_scale_count = i_width;
1820 for( i_x = i_pic_width; i_x--; )
1823 while( (i_scale_count -= i_pic_width) > 0 )
1828 i_scale_count += i_width;
1833 * Set vertical scaling indicator
1835 if( i_pic_height - i_height == 0 )
1839 else if( i_pic_height - i_height > 0 )
1843 else /* if( i_pic_height - i_height < 0 ) */