* modules/video_chroma/i420_rgb_mmx.h: wrote an MMX intrinsics version of
[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                 INTRINSICS_INIT_16
287                 INTRINSICS_YUV_MUL
288                 INTRINSICS_YUV_ADD
289                 INTRINSICS_UNPACK_15
290 #   else
291                 __asm__( MMX_INIT_16
292                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
293
294                 __asm__( ".align 8"
295                          MMX_YUV_MUL
296                          MMX_YUV_ADD
297                          MMX_UNPACK_15
298                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
299 #   endif
300
301                 p_y += 8;
302                 p_u += 4;
303                 p_v += 4;
304                 p_buffer += 8;
305             }
306         }
307         else
308         {
309             /* 16bpp 5/6/5 */
310             for ( i_x = p_vout->render.i_width / 8; i_x--; )
311             {
312 #   if defined (HAVE_MMX_INTRINSICS)
313                 __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
314                 INTRINSICS_INIT_16
315                 INTRINSICS_YUV_MUL
316                 INTRINSICS_YUV_ADD
317                 INTRINSICS_UNPACK_16
318 #   else
319                 __asm__( MMX_INIT_16
320                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
321
322                 __asm__( ".align 8"
323                          MMX_YUV_MUL
324                          MMX_YUV_ADD
325                          MMX_UNPACK_16
326                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
327 #   endif
328
329                 p_y += 8;
330                 p_u += 4;
331                 p_v += 4;
332                 p_buffer += 8;
333             }
334         }
335 #endif
336
337         /* Here we do some unaligned reads and duplicate conversions, but
338          * at least we have all the pixels */
339         if( i_rewind )
340         {
341 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
342 #   if defined (HAVE_MMX_INTRINSICS)
343             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
344 #   endif
345 #endif
346             p_y -= i_rewind;
347             p_u -= i_rewind >> 1;
348             p_v -= i_rewind >> 1;
349             p_buffer -= i_rewind;
350 #if defined (MODULE_NAME_IS_i420_rgb)
351             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
352             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
353             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
354             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
355 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
356
357 #   if defined (HAVE_MMX_INTRINSICS)
358             INTRINSICS_INIT_16
359 #   else
360             __asm__( MMX_INIT_16
361                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
362 #   endif
363
364             if( p_vout->output.i_rmask == 0x7c00 )
365             {
366                 /* 15bpp 5/5/5 */
367 #   if defined (HAVE_MMX_INTRINSICS)
368                 INTRINSICS_YUV_MUL
369                 INTRINSICS_YUV_ADD
370                 INTRINSICS_UNPACK_15
371 #   else
372                 __asm__( ".align 8"
373                          MMX_YUV_MUL
374                          MMX_YUV_ADD
375                          MMX_UNPACK_15
376                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
377 #   endif
378             }
379             else
380             {
381 #   if defined (HAVE_MMX_INTRINSICS)
382                 INTRINSICS_YUV_MUL
383                 INTRINSICS_YUV_ADD
384                 INTRINSICS_UNPACK_16
385 #   else
386                 /* 16bpp 5/6/5 */
387                 __asm__( ".align 8"
388                          MMX_YUV_MUL
389                          MMX_YUV_ADD
390                          MMX_UNPACK_16
391                          : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
392 #   endif
393             }
394
395             p_y += 8;
396             p_u += 4;
397             p_v += 4;
398             p_buffer += 8;
399 #endif
400         }
401         SCALE_WIDTH;
402         SCALE_HEIGHT( 420, 2 );
403
404         p_y += i_source_margin;
405         if( i_y % 2 )
406         {
407             p_u += i_source_margin_c;
408             p_v += i_source_margin_c;
409         }
410     }
411 }
412
413 /*****************************************************************************
414  * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
415  *****************************************************************************
416  * Horizontal alignment needed:
417  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
418  *  - output: 1 pixel (2 bytes), margins allowed
419  * Vertical alignment needed:
420  *  - input: 2 lines (2 Y lines, 1 U/V line)
421  *  - output: 1 line
422  *****************************************************************************/
423 void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src,
424                                             picture_t *p_dest )
425 {
426     /* We got this one from the old arguments */
427     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
428     uint8_t  *p_y   = p_src->Y_PIXELS;
429     uint8_t  *p_u   = p_src->U_PIXELS;
430     uint8_t  *p_v   = p_src->V_PIXELS;
431
432     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
433     unsigned int i_vscale;                          /* vertical scaling type */
434     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
435
436     int         i_right_margin;
437     int         i_rewind;
438     int         i_scale_count;                       /* scale modulo counter */
439     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
440     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
441 #if defined (MODULE_NAME_IS_i420_rgb)
442     int         i_uval, i_vval;                           /* U and V samples */
443     int         i_red, i_green, i_blue;          /* U and V modified samples */
444     uint32_t *  p_yuv = p_vout->chroma.p_sys->p_rgb32;
445     uint32_t *  p_ybase;                     /* Y dependant conversion table */
446 #endif
447
448     /* Conversion buffer pointer */
449     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
450     uint32_t *  p_buffer;
451
452     /* Offset array pointer */
453     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
454     int *       p_offset;
455
456     const int i_source_margin = p_src->p[0].i_pitch
457                                  - p_src->p[0].i_visible_pitch;
458     const int i_source_margin_c = p_src->p[1].i_pitch
459                                  - p_src->p[1].i_visible_pitch;
460
461     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
462
463     if( p_vout->render.i_width & 7 )
464     {
465         i_rewind = 8 - ( p_vout->render.i_width & 7 );
466     }
467     else
468     {
469         i_rewind = 0;
470     }
471
472     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
473      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
474      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
475     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
476                p_vout->output.i_width, p_vout->output.i_height,
477                &b_hscale, &i_vscale, p_offset_start );
478
479     /*
480      * Perform conversion
481      */
482     i_scale_count = ( i_vscale == 1 ) ?
483                     p_vout->output.i_height : p_vout->render.i_height;
484     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
485     {
486         p_pic_start = p_pic;
487         p_buffer = b_hscale ? p_buffer_start : p_pic;
488
489         for ( i_x = p_vout->render.i_width / 8; i_x--; )
490         {
491 #if defined (MODULE_NAME_IS_i420_rgb)
492             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
493             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
494             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
495             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
496 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
497 #   if defined (HAVE_MMX_INTRINSICS)
498             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
499             INTRINSICS_INIT_32
500             INTRINSICS_YUV_MUL
501             INTRINSICS_YUV_ADD
502             INTRINSICS_UNPACK_32
503 #   else
504             __asm__( MMX_INIT_32
505                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
506
507             __asm__( ".align 8"
508                      MMX_YUV_MUL
509                      MMX_YUV_ADD
510                      MMX_UNPACK_32
511                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
512 #   endif
513
514             p_y += 8;
515             p_u += 4;
516             p_v += 4;
517             p_buffer += 8;
518 #endif
519         }
520
521         /* Here we do some unaligned reads and duplicate conversions, but
522          * at least we have all the pixels */
523         if( i_rewind )
524         {
525 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
526 #   if defined (HAVE_MMX_INTRINSICS)
527             __m64 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
528 #   endif
529 #endif
530             p_y -= i_rewind;
531             p_u -= i_rewind >> 1;
532             p_v -= i_rewind >> 1;
533             p_buffer -= i_rewind;
534 #if defined (MODULE_NAME_IS_i420_rgb)
535             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
536             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
537             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
538             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
539 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
540 #   if defined (HAVE_MMX_INTRINSICS)
541             INTRINSICS_INIT_32
542             INTRINSICS_YUV_MUL
543             INTRINSICS_YUV_ADD
544             INTRINSICS_UNPACK_32
545 #   else
546             __asm__( MMX_INIT_32
547                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
548
549             __asm__( ".align 8"
550                      MMX_YUV_MUL
551                      MMX_YUV_ADD
552                      MMX_UNPACK_32
553                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
554 #   endif
555
556             p_y += 8;
557             p_u += 4;
558             p_v += 4;
559             p_buffer += 8;
560 #endif
561         }
562         SCALE_WIDTH;
563         SCALE_HEIGHT( 420, 4 );
564
565         p_y += i_source_margin;
566         if( i_y % 2 )
567         {
568             p_u += i_source_margin_c;
569             p_v += i_source_margin_c;
570         }
571     }
572 }
573
574 /* Following functions are local */
575
576 /*****************************************************************************
577  * SetOffset: build offset array for conversion functions
578  *****************************************************************************
579  * This function will build an offset array used in later conversion functions.
580  * It will also set horizontal and vertical scaling indicators.
581  *****************************************************************************/
582 static void SetOffset( int i_width, int i_height, int i_pic_width,
583                        int i_pic_height, vlc_bool_t *pb_hscale,
584                        int *pi_vscale, int *p_offset )
585 {
586     int i_x;                                    /* x position in destination */
587     int i_scale_count;                                     /* modulo counter */
588
589     /*
590      * Prepare horizontal offset array
591      */
592     if( i_pic_width - i_width == 0 )
593     {
594         /* No horizontal scaling: YUV conversion is done directly to picture */
595         *pb_hscale = 0;
596     }
597     else if( i_pic_width - i_width > 0 )
598     {
599         /* Prepare scaling array for horizontal extension */
600         *pb_hscale = 1;
601         i_scale_count = i_pic_width;
602         for( i_x = i_width; i_x--; )
603         {
604             while( (i_scale_count -= i_width) > 0 )
605             {
606                 *p_offset++ = 0;
607             }
608             *p_offset++ = 1;
609             i_scale_count += i_pic_width;
610         }
611     }
612     else /* if( i_pic_width - i_width < 0 ) */
613     {
614         /* Prepare scaling array for horizontal reduction */
615         *pb_hscale = 1;
616         i_scale_count = i_width;
617         for( i_x = i_pic_width; i_x--; )
618         {
619             *p_offset = 1;
620             while( (i_scale_count -= i_pic_width) > 0 )
621             {
622                 *p_offset += 1;
623             }
624             p_offset++;
625             i_scale_count += i_width;
626         }
627     }
628
629     /*
630      * Set vertical scaling indicator
631      */
632     if( i_pic_height - i_height == 0 )
633     {
634         *pi_vscale = 0;
635     }
636     else if( i_pic_height - i_height > 0 )
637     {
638         *pi_vscale = 1;
639     }
640     else /* if( i_pic_height - i_height < 0 ) */
641     {
642         *pi_vscale = -1;
643     }
644 }
645