]> git.sesse.net Git - vlc/blob - plugins/chroma/common.c
* ./ChangeLog: imported the 0.2.92 changes, unrolled current CVS changes.
[vlc] / plugins / chroma / common.c
1 /*****************************************************************************
2  * common.c: Chroma transformation functions
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: common.c,v 1.2 2001/12/30 07:09:54 sam Exp $
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
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 GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <math.h>                                            /* exp(), pow() */
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <stdlib.h>                                                /* free() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <videolan/vlc.h>
34
35 #include "video.h"
36 #include "video_output.h"
37
38 #include "video_common.h"
39
40 #include "intf_msg.h"
41
42 static int     yuv_Probe      ( probedata_t *p_data );
43 static int     yuv_Init       ( vout_thread_t *p_vout );
44 static int     yuv_Reset      ( vout_thread_t *p_vout );
45 static void    yuv_End        ( vout_thread_t *p_vout );
46
47 static void    SetGammaTable  ( int *pi_table, double f_gamma );
48 static void    SetYUV         ( vout_thread_t *p_vout );
49
50 /*****************************************************************************
51  * Functions exported as capabilities. They are declared as static so that
52  * we don't pollute the namespace too much.
53  *****************************************************************************/
54 void _M( yuv_getfunctions )( function_list_t * p_function_list )
55 {
56     p_function_list->pf_probe = yuv_Probe;
57     p_function_list->functions.yuv.pf_init = yuv_Init;
58     p_function_list->functions.yuv.pf_reset = yuv_Reset;
59     p_function_list->functions.yuv.pf_end = yuv_End;
60 }
61
62 /*****************************************************************************
63  * yuv_Probe: tests probe the audio device and return a score
64  *****************************************************************************
65  * This function tries to open the DSP and returns a score to the plugin
66  * manager so that it can choose the most appropriate one.
67  *****************************************************************************/
68 static int yuv_Probe( probedata_t *p_data )
69 {
70     if( TestMethod( YUV_METHOD_VAR, "yuv" ) )
71     {
72         return( 999 );
73     }
74
75     /* This module always works */
76     return( 50 );
77 }
78
79 /*****************************************************************************
80  * yuv_Init: allocate and initialize translations tables
81  *****************************************************************************
82  * This function will allocate memory to store translation tables, depending
83  * of the screen depth.
84  *****************************************************************************/
85 static int yuv_Init( vout_thread_t *p_vout )
86 {
87     size_t      tables_size;                        /* tables size, in bytes */
88
89     /* Computes tables size - 3 Bpp use 32 bits pixel entries in tables */
90     switch( p_vout->i_bytes_per_pixel )
91     {
92     case 1:
93         tables_size = sizeof( u8 )
94                 * (p_vout->b_grayscale ? GRAY_TABLE_SIZE : PALETTE_TABLE_SIZE);
95         break;
96     case 2:
97         tables_size = sizeof( u16 )
98                 * (p_vout->b_grayscale ? GRAY_TABLE_SIZE : RGB_TABLE_SIZE);
99         break;
100     case 3:
101     case 4:
102     default:
103         tables_size = sizeof( u32 )
104                 * (p_vout->b_grayscale ? GRAY_TABLE_SIZE : RGB_TABLE_SIZE);
105         break;
106     }
107
108     /* Allocate memory */
109     p_vout->yuv.p_base = malloc( tables_size );
110     if( p_vout->yuv.p_base == NULL )
111     {
112         intf_ErrMsg("error: %s", strerror(ENOMEM));
113         return( 1 );
114     }
115
116     /* Allocate memory for conversion buffer and offset array */
117     p_vout->yuv.p_buffer = malloc( VOUT_MAX_WIDTH * p_vout->i_bytes_per_pixel );
118     if( p_vout->yuv.p_buffer == NULL )
119     {
120         intf_ErrMsg("error: %s", strerror(ENOMEM));
121         free( p_vout->yuv.p_base );
122         return( 1 );
123     }
124
125     /* In 8bpp we have a twice as big offset table because we also
126      * need the offsets for U and V (not only Y) */
127     p_vout->yuv.p_offset = malloc( p_vout->i_width * sizeof( int ) *
128                              ( ( p_vout->i_bytes_per_pixel == 1 ) ? 2 : 1 ) );
129     if( p_vout->yuv.p_offset == NULL )
130     {
131         intf_ErrMsg("error: %s", strerror(ENOMEM));
132         free( p_vout->yuv.p_base );
133         free( p_vout->yuv.p_buffer );
134         return( 1 );
135     }
136
137     /* Initialize tables */
138     SetYUV( p_vout );
139     return( 0 );
140 }
141
142 /*****************************************************************************
143  * yuv_End: destroy translations tables
144  *****************************************************************************
145  * Free memory allocated by yuv_CCreate.
146  *****************************************************************************/
147 static void yuv_End( vout_thread_t *p_vout )
148 {
149     free( p_vout->yuv.p_base );
150     free( p_vout->yuv.p_buffer );
151     free( p_vout->yuv.p_offset );
152 }
153
154 /*****************************************************************************
155  * yuv_Reset: re-initialize translations tables
156  *****************************************************************************
157  * This function will initialize the tables allocated by vout_CreateTables and
158  * set functions pointers.
159  *****************************************************************************/
160 static int yuv_Reset( vout_thread_t *p_vout )
161 {
162     yuv_End( p_vout );
163     return( yuv_Init( p_vout ) );
164 }
165
166 /*****************************************************************************
167  * SetGammaTable: return intensity table transformed by gamma curve.
168  *****************************************************************************
169  * pi_table is a table of 256 entries from 0 to 255.
170  *****************************************************************************/
171 static void SetGammaTable( int *pi_table, double f_gamma )
172 {
173     int         i_y;                                       /* base intensity */
174
175     /* Use exp(gamma) instead of gamma */
176     f_gamma = exp( f_gamma );
177
178     /* Build gamma table */
179     for( i_y = 0; i_y < 256; i_y++ )
180     {
181         pi_table[ i_y ] = pow( (double)i_y / 256, f_gamma ) * 256;
182     }
183  }
184
185 /*****************************************************************************
186  * SetYUV: compute tables and set function pointers
187  *****************************************************************************/
188 static void SetYUV( vout_thread_t *p_vout )
189 {
190     int         pi_gamma[256];                                /* gamma table */
191     int         i_index;                                  /* index in tables */
192
193     /* Build gamma table */
194     SetGammaTable( pi_gamma, p_vout->f_gamma );
195
196     /*
197      * Set pointers and build YUV tables
198      */
199     if( p_vout->b_grayscale )
200     {
201         /* Grayscale: build gray table */
202         switch( p_vout->i_bytes_per_pixel )
203         {
204         case 1:
205             {
206                 u16 bright[256], transp[256];
207
208                 p_vout->yuv.yuv.p_gray8 =  (u8 *)p_vout->yuv.p_base + GRAY_MARGIN;
209                 for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
210                 {
211                     p_vout->yuv.yuv.p_gray8[ -i_index ] =      RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
212                     p_vout->yuv.yuv.p_gray8[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
213                 }
214                 for( i_index = 0; i_index < 256; i_index++)
215                 {
216                     p_vout->yuv.yuv.p_gray8[ i_index ] = pi_gamma[ i_index ];
217                     bright[ i_index ] = i_index << 8;
218                     transp[ i_index ] = 0;
219                 }
220                 /* the colors have been allocated, we can set the palette */
221                 p_vout->pf_setpalette( p_vout, bright, bright, bright, transp );
222                 p_vout->i_white_pixel = 0xff;
223                 p_vout->i_black_pixel = 0x00;
224                 p_vout->i_gray_pixel = 0x44;
225                 p_vout->i_blue_pixel = 0x3b;
226
227                 break;
228             }
229         case 2:
230             p_vout->yuv.yuv.p_gray16 =  (u16 *)p_vout->yuv.p_base + GRAY_MARGIN;
231             for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
232             {
233                 p_vout->yuv.yuv.p_gray16[ -i_index ] =      RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
234                 p_vout->yuv.yuv.p_gray16[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
235             }
236             for( i_index = 0; i_index < 256; i_index++)
237             {
238                 p_vout->yuv.yuv.p_gray16[ i_index ] = RGB2PIXEL( p_vout, pi_gamma[i_index], pi_gamma[i_index], pi_gamma[i_index] );
239             }
240             break;
241         case 3:
242         case 4:
243             p_vout->yuv.yuv.p_gray32 =  (u32 *)p_vout->yuv.p_base + GRAY_MARGIN;
244             for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
245             {
246                 p_vout->yuv.yuv.p_gray32[ -i_index ] =      RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
247                 p_vout->yuv.yuv.p_gray32[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
248             }
249             for( i_index = 0; i_index < 256; i_index++)
250             {
251                 p_vout->yuv.yuv.p_gray32[ i_index ] = RGB2PIXEL( p_vout, pi_gamma[i_index], pi_gamma[i_index], pi_gamma[i_index] );
252             }
253             break;
254          }
255     }
256     else
257     {
258         /* Color: build red, green and blue tables */
259         switch( p_vout->i_bytes_per_pixel )
260         {
261         case 1:
262             {
263                 #define RGB_MIN 0
264                 #define RGB_MAX 255
265                 #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
266
267                 int y,u,v;
268                 int r,g,b;
269                 int uvr, uvg, uvb;
270                 int i = 0, j = 0;
271                 u16 red[256], green[256], blue[256], transp[256];
272                 unsigned char lookup[PALETTE_TABLE_SIZE];
273
274                 p_vout->yuv.yuv.p_rgb8 = (u8 *)p_vout->yuv.p_base;
275
276                 /* this loop calculates the intersection of an YUV box
277                  * and the RGB cube. */
278                 for ( y = 0; y <= 256; y += 16 )
279                 {
280                     for ( u = 0; u <= 256; u += 32 )
281                     for ( v = 0; v <= 256; v += 32 )
282                     {
283                         uvr = (V_RED_COEF*(v-128)) >> SHIFT;
284                         uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT;
285                         uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
286                         r = y + uvr;
287                         g = y + uvg;
288                         b = y + uvb;
289
290                         if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN
291                                 && r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
292                         {
293                             /* this one should never happen unless someone fscked up my code */
294                             if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette" ); break; }
295
296                             /* clip the colors */
297                             red[j] = CLIP( r );
298                             green[j] = CLIP( g );
299                             blue[j] = CLIP( b );
300                             transp[j] = 0;
301
302                             /* allocate color */
303                             lookup[i] = 1;
304                             p_vout->yuv.yuv.p_rgb8[i++] = j;
305                             j++;
306                         }
307                         else
308                         {
309                             lookup[i] = 0;
310                             p_vout->yuv.yuv.p_rgb8[i++] = 0;
311                         }
312                     }
313                     i += 128-81;
314                 }
315
316                 /* the colors have been allocated, we can set the palette */
317                 /* there will eventually be a way to know which colors
318                  * couldn't be allocated and try to find a replacement */
319                 p_vout->pf_setpalette( p_vout, red, green, blue, transp );
320
321                 p_vout->i_white_pixel = 0xff;
322                 p_vout->i_black_pixel = 0x00;
323                 p_vout->i_gray_pixel = 0x44;
324                 p_vout->i_blue_pixel = 0x3b;
325
326                 i = 0;
327                 /* this loop allocates colors that got outside
328                  * the RGB cube */
329                 for ( y = 0; y <= 256; y += 16 )
330                 {
331                     for ( u = 0; u <= 256; u += 32 )
332                     for ( v = 0; v <= 256; v += 32 )
333                     {
334                         int u2, v2;
335                         int dist, mindist = 100000000;
336
337                         if( lookup[i] || y==0)
338                         {
339                             i++;
340                             continue;
341                         }
342
343                         /* heavy. yeah. */
344                         for( u2 = 0; u2 <= 256; u2 += 32 )
345                         for( v2 = 0; v2 <= 256; v2 += 32 )
346                         {
347                             j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5);
348                             dist = (u-u2)*(u-u2) + (v-v2)*(v-v2);
349                             if( lookup[j] )
350                             /* find the nearest color */
351                             if( dist < mindist )
352                             {
353                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
354                                 mindist = dist;
355                             }
356                             j -= 128;
357                             if( lookup[j] )
358                             /* find the nearest color */
359                             if( dist + 128 < mindist )
360                             {
361                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
362                                 mindist = dist + 128;
363                             }
364                         }
365                         i++;
366                     }
367                     i += 128-81;
368                 }
369
370                 break;
371             }
372         case 2:
373             p_vout->yuv.yuv.p_rgb16 = (u16 *)p_vout->yuv.p_base;
374             for( i_index = 0; i_index < RED_MARGIN; i_index++ )
375             {
376                 p_vout->yuv.yuv.p_rgb16[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
377                 p_vout->yuv.yuv.p_rgb16[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
378             }
379             for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
380             {
381                 p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
382                 p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
383             }
384             for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
385             {
386                 p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
387                 p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
388             }
389             for( i_index = 0; i_index < 256; i_index++ )
390             {
391                 p_vout->yuv.yuv.p_rgb16[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
392                 p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
393                 p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
394             }
395             break;
396         case 3:
397         case 4:
398             p_vout->yuv.yuv.p_rgb32 = (u32 *)p_vout->yuv.p_base;
399             for( i_index = 0; i_index < RED_MARGIN; i_index++ )
400             {
401                 p_vout->yuv.yuv.p_rgb32[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
402                 p_vout->yuv.yuv.p_rgb32[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
403             }
404             for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
405             {
406                 p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
407                 p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
408             }
409             for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
410             {
411                 p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
412                 p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
413             }
414             for( i_index = 0; i_index < 256; i_index++ )
415             {
416                 p_vout->yuv.yuv.p_rgb32[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
417                 p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
418                 p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
419             }
420             break;
421         }
422     }
423
424     /*
425      * Set functions pointers
426      */
427     if( p_vout->b_YCbr)
428     {
429         switch( p_vout->i_bytes_per_pixel)
430         {
431 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
432         case 1:
433             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr8 );
434             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr8 );
435             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr8 );
436             break;
437         
438         case 2:
439             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr16 );
440             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr16 );
441             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr16 );
442            break;
443         
444         case 3:
445             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr24 );
446             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr24 );
447             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr24 );
448              break;
449         
450         case 4:
451             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr32 );
452             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr32 );
453             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr32 );
454             break;
455         }
456 #undef _X
457     }    
458     else if( p_vout->b_grayscale )
459     {
460         /* Grayscale */
461         switch( p_vout->i_bytes_per_pixel )
462         {
463 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
464         case 1:
465             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray8 );
466             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray8 );
467             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray8 );
468             break;
469         case 2:
470             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray16 );
471             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray16 );
472             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray16 );
473             break;
474         case 3:
475             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray24 );
476             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray24 );
477             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray24 );
478             break;
479         case 4:
480             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray32 );
481             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray32 );
482             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray32 );
483             break;
484 #undef _X
485         }
486     }
487     else
488     {
489         /* Color */
490         switch( p_vout->i_bytes_per_pixel )
491         {
492 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
493         case 1:
494             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB8 );
495             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB8 );
496             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB8 );
497             break;
498         case 2:
499             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB16 );
500             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB16 );
501             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB16 );
502             break;
503         case 3:
504             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB24 );
505             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB24 );
506             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB24 );
507             break;
508         case 4:
509             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB32 );
510             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB32 );
511             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB32 );
512             break;
513 #undef _X
514       }
515  
516     }
517 }
518
519 /*****************************************************************************
520  * SetOffset: build offset array for conversion functions
521  *****************************************************************************
522  * This function will build an offset array used in later conversion functions.
523  * It will also set horizontal and vertical scaling indicators. If b_double
524  * is set, the p_offset structure has interleaved Y and U/V offsets.
525  *****************************************************************************/
526 void _M( SetOffset )( int i_width, int i_height, int i_pic_width,
527                       int i_pic_height, boolean_t *pb_h_scaling,
528                       int *pi_v_scaling, int *p_offset, boolean_t b_double )
529 {
530     int i_x;                                    /* x position in destination */
531     int i_scale_count;                                     /* modulo counter */
532
533     /*
534      * Prepare horizontal offset array
535      */
536     if( i_pic_width - i_width == 0 )
537     {
538         /* No horizontal scaling: YUV conversion is done directly to picture */
539         *pb_h_scaling = 0;
540     }
541     else if( i_pic_width - i_width > 0 )
542     {
543         /* Prepare scaling array for horizontal extension */
544         *pb_h_scaling = 1;
545         i_scale_count = i_pic_width;
546         if( !b_double )
547         {
548             for( i_x = i_width; i_x--; )
549             {
550                 while( (i_scale_count -= i_width) > 0 )
551                 {
552                     *p_offset++ = 0;
553                 }
554                 *p_offset++ = 1;
555                 i_scale_count += i_pic_width;
556             }
557         }
558         else
559         {
560             int i_dummy = 0;
561             for( i_x = i_width; i_x--; )
562             {
563                 while( (i_scale_count -= i_width) > 0 )
564                 {
565                     *p_offset++ = 0;
566                     *p_offset++ = 0;
567                 }
568                 *p_offset++ = 1;
569                 *p_offset++ = i_dummy;
570                 i_dummy = 1 - i_dummy;
571                 i_scale_count += i_pic_width;
572             }
573         }
574     }
575     else /* if( i_pic_width - i_width < 0 ) */
576     {
577         /* Prepare scaling array for horizontal reduction */
578         *pb_h_scaling = 1;
579         i_scale_count = i_width;
580         if( !b_double )
581         {
582            for( i_x = i_pic_width; i_x--; )
583             {
584                 *p_offset = 1;
585                 while( (i_scale_count -= i_pic_width) > 0 )
586                 {
587                     *p_offset += 1;
588                 }
589                 p_offset++;
590                 i_scale_count += i_width;
591             }
592         }
593         else
594         {
595             int i_remainder = 0;
596             int i_jump;
597             for( i_x = i_pic_width; i_x--; )
598             {
599                 i_jump = 1;
600                 while( (i_scale_count -= i_pic_width) > 0 )
601                 {
602                     i_jump += 1;
603                 }
604                 *p_offset++ = i_jump;
605                 *p_offset++ = ( i_jump += i_remainder ) >> 1;
606                 i_remainder = i_jump & 1;
607                 i_scale_count += i_width;
608             }
609         }
610      }
611
612     /*
613      * Set vertical scaling indicator
614      */
615     if( i_pic_height - i_height == 0 )
616     {
617         *pi_v_scaling = 0;
618     }
619     else if( i_pic_height - i_height > 0 )
620     {
621         *pi_v_scaling = 1;
622     }
623     else /* if( i_pic_height - i_height < 0 ) */
624     {
625         *pi_v_scaling = -1;
626     }
627 }
628