* modules/video_chroma/i420_rgb_mmx.h: work around a GCC 3.4.x bug.
[vlc.git] / modules / video_chroma / i420_rgb16.c
1 /*****************************************************************************
2  * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <string.h>                                            /* strerror() */
28 #include <stdlib.h>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32
33 #include "i420_rgb.h"
34 #if defined (MODULE_NAME_IS_i420_rgb)
35 #   include "i420_rgb_c.h"
36 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
37 #   if defined(HAVE_MMX_INTRINSICS)
38 #       include <mmintrin.h>
39 #   endif
40 #   include "i420_rgb_mmx.h"
41 #endif
42
43 static void SetOffset( int, int, int, int, vlc_bool_t *, int *, int * );
44
45 #if defined (MODULE_NAME_IS_i420_rgb)
46 /*****************************************************************************
47  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp with dithering
48  *****************************************************************************
49  * Horizontal alignment needed:
50  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
51  *  - output: 1 pixel (2 bytes), margins allowed
52  * Vertical alignment needed:
53  *  - input: 2 lines (2 Y lines, 1 U/V line)
54  *  - output: 1 line
55  *****************************************************************************/
56 void E_(I420_RGB16_dithering)( vout_thread_t *p_vout, picture_t *p_src,
57                                                       picture_t *p_dest )
58 {
59     /* We got this one from the old arguments */
60     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
61     uint8_t  *p_y   = p_src->Y_PIXELS;
62     uint8_t  *p_u   = p_src->U_PIXELS;
63     uint8_t  *p_v   = p_src->V_PIXELS;
64
65     vlc_bool_t   b_hscale;                        /* horizontal scaling type */
66     int          i_vscale;                          /* vertical scaling type */
67     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
68     unsigned int i_real_y;                                          /* y % 4 */
69
70     int         i_right_margin;
71     int         i_rewind;
72     int         i_scale_count;                       /* scale modulo counter */
73     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
74     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
75     int         i_uval, i_vval;                           /* U and V samples */
76     int         i_red, i_green, i_blue;          /* U and V modified samples */
77     uint16_t *  p_yuv = p_vout->chroma.p_sys->p_rgb16;
78     uint16_t *  p_ybase;                     /* Y dependant conversion table */
79
80     /* Conversion buffer pointer */
81     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
82     uint16_t *  p_buffer;
83
84     /* Offset array pointer */
85     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
86     int *       p_offset;
87
88     const int i_source_margin = p_src->p[0].i_pitch
89                                  - p_src->p[0].i_visible_pitch;
90     const int i_source_margin_c = p_src->p[1].i_pitch
91                                  - p_src->p[1].i_visible_pitch;
92
93     /* The dithering matrices */
94     int dither10[4] = {  0x0,  0x8,  0x2,  0xa };
95     int dither11[4] = {  0xc,  0x4,  0xe,  0x6 };
96     int dither12[4] = {  0x3,  0xb,  0x1,  0x9 };
97     int dither13[4] = {  0xf,  0x7,  0xd,  0x5 };
98
99     for(i_x = 0; i_x < 4; i_x++)
100     {
101         dither10[i_x] = dither10[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
102         dither11[i_x] = dither11[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
103         dither12[i_x] = dither12[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
104         dither13[i_x] = dither13[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
105     }
106
107     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
108
109     if( p_vout->render.i_width & 7 )
110     {
111         i_rewind = 8 - ( p_vout->render.i_width & 7 );
112     }
113     else
114     {
115         i_rewind = 0;
116     }
117
118     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
119      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
120      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
121     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
122                p_vout->output.i_width, p_vout->output.i_height,
123                &b_hscale, &i_vscale, p_offset_start );
124
125     /*
126      * Perform conversion
127      */
128     i_scale_count = ( i_vscale == 1 ) ?
129                     p_vout->output.i_height : p_vout->render.i_height;
130     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
131     {
132         i_real_y = i_y & 0x3;
133         p_pic_start = p_pic;
134         p_buffer = b_hscale ? p_buffer_start : p_pic;
135
136         for ( i_x = p_vout->render.i_width / 8; i_x--; )
137         {
138             int *p_dither = dither10;
139             CONVERT_YUV_PIXEL_DITHER(2);
140             p_dither = dither11;
141             CONVERT_Y_PIXEL_DITHER(2);
142             p_dither = dither12;
143             CONVERT_YUV_PIXEL_DITHER(2);
144             p_dither = dither13;
145             CONVERT_Y_PIXEL_DITHER(2);
146             p_dither = dither10;
147             CONVERT_YUV_PIXEL_DITHER(2);
148             p_dither = dither11;
149             CONVERT_Y_PIXEL_DITHER(2);
150             p_dither = dither12;
151             CONVERT_YUV_PIXEL_DITHER(2);
152             p_dither = dither13;
153             CONVERT_Y_PIXEL_DITHER(2);
154         }
155
156         /* Here we do some unaligned reads and duplicate conversions, but
157          * at least we have all the pixels */
158         if( i_rewind )
159         {
160             int *p_dither = dither10;
161             p_y -= i_rewind;
162             p_u -= i_rewind >> 1;
163             p_v -= i_rewind >> 1;
164             p_buffer -= i_rewind;
165             CONVERT_YUV_PIXEL_DITHER(2);
166             p_dither = dither11;
167             CONVERT_Y_PIXEL_DITHER(2);
168             p_dither = dither12;
169             CONVERT_YUV_PIXEL_DITHER(2);
170             p_dither = dither13;
171             CONVERT_Y_PIXEL_DITHER(2);
172             p_dither = dither10;
173             CONVERT_YUV_PIXEL_DITHER(2);
174             p_dither = dither11;
175             CONVERT_Y_PIXEL_DITHER(2);
176             p_dither = dither12;
177             CONVERT_YUV_PIXEL_DITHER(2);
178             p_dither = dither13;
179             CONVERT_Y_PIXEL_DITHER(2);
180         }
181         SCALE_WIDTH;
182         SCALE_HEIGHT( 420, 2 );
183
184         p_y += i_source_margin;
185         if( i_y % 2 )
186         {
187             p_u += i_source_margin_c;
188             p_v += i_source_margin_c;
189         }
190     }
191 }
192 #endif
193
194 /*****************************************************************************
195  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
196  *****************************************************************************
197  * Horizontal alignment needed:
198  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
199  *  - output: 1 pixel (2 bytes), margins allowed
200  * Vertical alignment needed:
201  *  - input: 2 lines (2 Y lines, 1 U/V line)
202  *  - output: 1 line
203  *****************************************************************************/
204 void E_(I420_RGB16)( vout_thread_t *p_vout, picture_t *p_src,
205                                             picture_t *p_dest )
206 {
207     /* We got this one from the old arguments */
208     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
209     uint8_t  *p_y   = p_src->Y_PIXELS;
210     uint8_t  *p_u   = p_src->U_PIXELS;
211     uint8_t  *p_v   = p_src->V_PIXELS;
212
213     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
214     unsigned int i_vscale;                          /* vertical scaling type */
215     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
216
217     int         i_right_margin;
218     int         i_rewind;
219     int         i_scale_count;                       /* scale modulo counter */
220     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
221     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
222 #if defined (MODULE_NAME_IS_i420_rgb)
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_vout->chroma.p_sys->p_rgb16;
226     uint16_t *  p_ybase;                     /* Y dependant conversion table */
227 #endif
228
229     /* Conversion buffer pointer */
230     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
231     uint16_t *  p_buffer;
232
233     /* Offset array pointer */
234     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
235     int *       p_offset;
236
237     const int i_source_margin = p_src->p[0].i_pitch
238                                  - p_src->p[0].i_visible_pitch;
239     const int i_source_margin_c = p_src->p[1].i_pitch
240                                  - p_src->p[1].i_visible_pitch;
241
242     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
243
244     if( p_vout->render.i_width & 7 )
245     {
246         i_rewind = 8 - ( p_vout->render.i_width & 7 );
247     }
248     else
249     {
250         i_rewind = 0;
251     }
252
253     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
254      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
255      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
256     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
257                p_vout->output.i_width, p_vout->output.i_height,
258                &b_hscale, &i_vscale, p_offset_start );
259
260     /*
261      * Perform conversion
262      */
263     i_scale_count = ( i_vscale == 1 ) ?
264                     p_vout->output.i_height : p_vout->render.i_height;
265     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
266     {
267         p_pic_start = p_pic;
268         p_buffer = b_hscale ? p_buffer_start : p_pic;
269
270 #if defined (MODULE_NAME_IS_i420_rgb)
271         for ( i_x = p_vout->render.i_width / 8; i_x--; )
272         {
273             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
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         }
278 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
279         if( p_vout->output.i_rmask == 0x7c00 )
280         {
281             /* 15bpp 5/5/5 */
282             for ( i_x = p_vout->render.i_width / 8; i_x--; )
283             {
284 #   if defined (HAVE_MMX_INTRINSICS)
285                 __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
286                 uint64_t tmp64;
287                 INTRINSICS_INIT_16
288                 INTRINSICS_YUV_MUL
289                 INTRINSICS_YUV_ADD
290                 INTRINSICS_UNPACK_15
291 #   else
292                 __asm__( MMX_INIT_16
293                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
294
295                 __asm__( ".align 8"
296                          MMX_YUV_MUL
297                          MMX_YUV_ADD
298                          MMX_UNPACK_15
299                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
300 #   endif
301
302                 p_y += 8;
303                 p_u += 4;
304                 p_v += 4;
305                 p_buffer += 8;
306             }
307         }
308         else
309         {
310             /* 16bpp 5/6/5 */
311             for ( i_x = p_vout->render.i_width / 8; i_x--; )
312             {
313 #   if defined (HAVE_MMX_INTRINSICS)
314                 __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
315                 uint64_t tmp64;
316                 INTRINSICS_INIT_16
317                 INTRINSICS_YUV_MUL
318                 INTRINSICS_YUV_ADD
319                 INTRINSICS_UNPACK_16
320 #   else
321                 __asm__( MMX_INIT_16
322                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
323
324                 __asm__( ".align 8"
325                          MMX_YUV_MUL
326                          MMX_YUV_ADD
327                          MMX_UNPACK_16
328                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
329 #   endif
330
331                 p_y += 8;
332                 p_u += 4;
333                 p_v += 4;
334                 p_buffer += 8;
335             }
336         }
337 #endif
338
339         /* Here we do some unaligned reads and duplicate conversions, but
340          * at least we have all the pixels */
341         if( i_rewind )
342         {
343 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
344 #   if defined (HAVE_MMX_INTRINSICS)
345             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
346             uint64_t tmp64;
347 #   endif
348 #endif
349             p_y -= i_rewind;
350             p_u -= i_rewind >> 1;
351             p_v -= i_rewind >> 1;
352             p_buffer -= i_rewind;
353 #if defined (MODULE_NAME_IS_i420_rgb)
354             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
355             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
356             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
357             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
358 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
359
360 #   if defined (HAVE_MMX_INTRINSICS)
361             INTRINSICS_INIT_16
362 #   else
363             __asm__( MMX_INIT_16
364                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
365 #   endif
366
367             if( p_vout->output.i_rmask == 0x7c00 )
368             {
369                 /* 15bpp 5/5/5 */
370 #   if defined (HAVE_MMX_INTRINSICS)
371                 INTRINSICS_YUV_MUL
372                 INTRINSICS_YUV_ADD
373                 INTRINSICS_UNPACK_15
374 #   else
375                 __asm__( ".align 8"
376                          MMX_YUV_MUL
377                          MMX_YUV_ADD
378                          MMX_UNPACK_15
379                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
380 #   endif
381             }
382             else
383             {
384 #   if defined (HAVE_MMX_INTRINSICS)
385                 INTRINSICS_YUV_MUL
386                 INTRINSICS_YUV_ADD
387                 INTRINSICS_UNPACK_16
388 #   else
389                 /* 16bpp 5/6/5 */
390                 __asm__( ".align 8"
391                          MMX_YUV_MUL
392                          MMX_YUV_ADD
393                          MMX_UNPACK_16
394                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
395 #   endif
396             }
397
398             p_y += 8;
399             p_u += 4;
400             p_v += 4;
401             p_buffer += 8;
402 #endif
403         }
404         SCALE_WIDTH;
405         SCALE_HEIGHT( 420, 2 );
406
407         p_y += i_source_margin;
408         if( i_y % 2 )
409         {
410             p_u += i_source_margin_c;
411             p_v += i_source_margin_c;
412         }
413     }
414 }
415
416 /*****************************************************************************
417  * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
418  *****************************************************************************
419  * Horizontal alignment needed:
420  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
421  *  - output: 1 pixel (2 bytes), margins allowed
422  * Vertical alignment needed:
423  *  - input: 2 lines (2 Y lines, 1 U/V line)
424  *  - output: 1 line
425  *****************************************************************************/
426 void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src,
427                                             picture_t *p_dest )
428 {
429     /* We got this one from the old arguments */
430     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
431     uint8_t  *p_y   = p_src->Y_PIXELS;
432     uint8_t  *p_u   = p_src->U_PIXELS;
433     uint8_t  *p_v   = p_src->V_PIXELS;
434
435     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
436     unsigned int i_vscale;                          /* vertical scaling type */
437     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
438
439     int         i_right_margin;
440     int         i_rewind;
441     int         i_scale_count;                       /* scale modulo counter */
442     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
443     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
444 #if defined (MODULE_NAME_IS_i420_rgb)
445     int         i_uval, i_vval;                           /* U and V samples */
446     int         i_red, i_green, i_blue;          /* U and V modified samples */
447     uint32_t *  p_yuv = p_vout->chroma.p_sys->p_rgb32;
448     uint32_t *  p_ybase;                     /* Y dependant conversion table */
449 #endif
450
451     /* Conversion buffer pointer */
452     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
453     uint32_t *  p_buffer;
454
455     /* Offset array pointer */
456     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
457     int *       p_offset;
458
459     const int i_source_margin = p_src->p[0].i_pitch
460                                  - p_src->p[0].i_visible_pitch;
461     const int i_source_margin_c = p_src->p[1].i_pitch
462                                  - p_src->p[1].i_visible_pitch;
463
464     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
465
466     if( p_vout->render.i_width & 7 )
467     {
468         i_rewind = 8 - ( p_vout->render.i_width & 7 );
469     }
470     else
471     {
472         i_rewind = 0;
473     }
474
475     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
476      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
477      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
478     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
479                p_vout->output.i_width, p_vout->output.i_height,
480                &b_hscale, &i_vscale, p_offset_start );
481
482     /*
483      * Perform conversion
484      */
485     i_scale_count = ( i_vscale == 1 ) ?
486                     p_vout->output.i_height : p_vout->render.i_height;
487     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
488     {
489         p_pic_start = p_pic;
490         p_buffer = b_hscale ? p_buffer_start : p_pic;
491
492         for ( i_x = p_vout->render.i_width / 8; i_x--; )
493         {
494 #if defined (MODULE_NAME_IS_i420_rgb)
495             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
496             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
497             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
498             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
499 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
500 #   if defined (HAVE_MMX_INTRINSICS)
501             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
502             uint64_t tmp64;
503             INTRINSICS_INIT_32
504             INTRINSICS_YUV_MUL
505             INTRINSICS_YUV_ADD
506             INTRINSICS_UNPACK_32
507 #   else
508             __asm__( MMX_INIT_32
509                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
510
511             __asm__( ".align 8"
512                      MMX_YUV_MUL
513                      MMX_YUV_ADD
514                      MMX_UNPACK_32
515                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
516 #   endif
517
518             p_y += 8;
519             p_u += 4;
520             p_v += 4;
521             p_buffer += 8;
522 #endif
523         }
524
525         /* Here we do some unaligned reads and duplicate conversions, but
526          * at least we have all the pixels */
527         if( i_rewind )
528         {
529 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
530 #   if defined (HAVE_MMX_INTRINSICS)
531             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
532             uint64_t tmp64;
533 #   endif
534 #endif
535             p_y -= i_rewind;
536             p_u -= i_rewind >> 1;
537             p_v -= i_rewind >> 1;
538             p_buffer -= i_rewind;
539 #if defined (MODULE_NAME_IS_i420_rgb)
540             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
541             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
542             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
543             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
544 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
545 #   if defined (HAVE_MMX_INTRINSICS)
546             INTRINSICS_INIT_32
547             INTRINSICS_YUV_MUL
548             INTRINSICS_YUV_ADD
549             INTRINSICS_UNPACK_32
550 #   else
551             __asm__( MMX_INIT_32
552                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
553
554             __asm__( ".align 8"
555                      MMX_YUV_MUL
556                      MMX_YUV_ADD
557                      MMX_UNPACK_32
558                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
559 #   endif
560
561             p_y += 8;
562             p_u += 4;
563             p_v += 4;
564             p_buffer += 8;
565 #endif
566         }
567         SCALE_WIDTH;
568         SCALE_HEIGHT( 420, 4 );
569
570         p_y += i_source_margin;
571         if( i_y % 2 )
572         {
573             p_u += i_source_margin_c;
574             p_v += i_source_margin_c;
575         }
576     }
577 }
578
579 /* Following functions are local */
580
581 /*****************************************************************************
582  * SetOffset: build offset array for conversion functions
583  *****************************************************************************
584  * This function will build an offset array used in later conversion functions.
585  * It will also set horizontal and vertical scaling indicators.
586  *****************************************************************************/
587 static void SetOffset( int i_width, int i_height, int i_pic_width,
588                        int i_pic_height, vlc_bool_t *pb_hscale,
589                        int *pi_vscale, int *p_offset )
590 {
591     int i_x;                                    /* x position in destination */
592     int i_scale_count;                                     /* modulo counter */
593
594     /*
595      * Prepare horizontal offset array
596      */
597     if( i_pic_width - i_width == 0 )
598     {
599         /* No horizontal scaling: YUV conversion is done directly to picture */
600         *pb_hscale = 0;
601     }
602     else if( i_pic_width - i_width > 0 )
603     {
604         /* Prepare scaling array for horizontal extension */
605         *pb_hscale = 1;
606         i_scale_count = i_pic_width;
607         for( i_x = i_width; i_x--; )
608         {
609             while( (i_scale_count -= i_width) > 0 )
610             {
611                 *p_offset++ = 0;
612             }
613             *p_offset++ = 1;
614             i_scale_count += i_pic_width;
615         }
616     }
617     else /* if( i_pic_width - i_width < 0 ) */
618     {
619         /* Prepare scaling array for horizontal reduction */
620         *pb_hscale = 1;
621         i_scale_count = i_width;
622         for( i_x = i_pic_width; i_x--; )
623         {
624             *p_offset = 1;
625             while( (i_scale_count -= i_pic_width) > 0 )
626             {
627                 *p_offset += 1;
628             }
629             p_offset++;
630             i_scale_count += i_width;
631         }
632     }
633
634     /*
635      * Set vertical scaling indicator
636      */
637     if( i_pic_height - i_height == 0 )
638     {
639         *pi_vscale = 0;
640     }
641     else if( i_pic_height - i_height > 0 )
642     {
643         *pi_vscale = 1;
644     }
645     else /* if( i_pic_height - i_height < 0 ) */
646     {
647         *pi_vscale = -1;
648     }
649 }
650