]> git.sesse.net Git - vlc/blob - plugins/yuv/video_yuvmmx.c
cbaf45947304e2fc93284335ef93d9d80aed3be2
[vlc] / plugins / yuv / video_yuvmmx.c
1 /*****************************************************************************
2  * video_yuvmmx.c: MMX YUV transformation functions
3  * Provides functions to perform the YUV conversion.
4  *****************************************************************************
5  * Copyright (C) 1999, 2000 VideoLAN
6  * $Id: video_yuvmmx.c,v 1.10 2001/06/03 12:47:21 sam Exp $
7  *
8  * Authors: Samuel Hocevar <sam@zoy.org>
9  *
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.
14  *
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 GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this program; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *****************************************************************************/
25
26 #define MODULE_NAME yuvmmx
27 #include "modules_inner.h"
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include "defs.h"
33
34 #include <math.h>                                            /* exp(), pow() */
35 #include <errno.h>                                                 /* ENOMEM */
36 #include <stdlib.h>                                                /* free() */
37 #include <string.h>                                            /* strerror() */
38
39 #include "config.h"
40 #include "common.h"
41 #include "threads.h"
42 #include "mtime.h"
43 #include "tests.h"
44
45 #include "video.h"
46 #include "video_output.h"
47
48 #include "video_common.h"
49
50 #include "intf_msg.h"
51
52 #include "modules.h"
53 #include "modules_export.h"
54
55 static int     yuv_Probe      ( probedata_t *p_data );
56 static int     yuv_Init       ( vout_thread_t *p_vout );
57 static int     yuv_Reset      ( vout_thread_t *p_vout );
58 static void    yuv_End        ( vout_thread_t *p_vout );
59
60 static void    SetYUV         ( vout_thread_t *p_vout );
61
62 /*****************************************************************************
63  * Functions exported as capabilities. They are declared as static so that
64  * we don't pollute the namespace too much.
65  *****************************************************************************/
66 void _M( yuv_getfunctions )( function_list_t * p_function_list )
67 {
68     p_function_list->pf_probe = yuv_Probe;
69     p_function_list->functions.yuv.pf_init = yuv_Init;
70     p_function_list->functions.yuv.pf_reset = yuv_Reset;
71     p_function_list->functions.yuv.pf_end = yuv_End;
72 }
73
74 /*****************************************************************************
75  * yuv_Probe: tests probe the audio device and return a score
76  *****************************************************************************
77  * This function tries to open the DSP and returns a score to the plugin
78  * manager so that it can choose the most appropriate one.
79  *****************************************************************************/
80 static int yuv_Probe( probedata_t *p_data )
81 {
82     /* Test for MMX support in the CPU */
83     if( !TestCPU( CPU_CAPABILITY_MMX ) )
84     {
85         return( 0 );
86     }
87
88     if( TestMethod( YUV_METHOD_VAR, "yuvmmx" ) )
89     {
90         return( 999 );
91     }
92
93     return( 100 );
94 }
95
96 /*****************************************************************************
97  * yuv_Init: allocate and initialize translations tables
98  *****************************************************************************
99  * This function will allocate memory to store translation tables, depending
100  * of the screen depth.
101  *****************************************************************************/
102 static int yuv_Init( vout_thread_t *p_vout )
103 {
104     size_t      tables_size;                        /* tables size, in bytes */
105
106     /* Computes tables size for 8bbp only */
107     if( p_vout->i_bytes_per_pixel == 1 )
108     {
109         tables_size = sizeof( u8 )
110                 * (p_vout->b_grayscale ? GRAY_TABLE_SIZE : PALETTE_TABLE_SIZE);
111
112         /* Allocate memory */
113         p_vout->yuv.p_base = malloc( tables_size );
114         if( p_vout->yuv.p_base == NULL )
115         {
116             intf_ErrMsg("error: %s", strerror(ENOMEM));
117             return( 1 );
118         }
119     }
120     else
121     {
122         p_vout->yuv.p_base = NULL;
123     }
124
125     /* Allocate memory for conversion buffer and offset array */
126     p_vout->yuv.p_buffer = malloc( VOUT_MAX_WIDTH * p_vout->i_bytes_per_pixel );
127     if( p_vout->yuv.p_buffer == NULL )
128     {
129         intf_ErrMsg("error: %s", strerror(ENOMEM));
130         free( p_vout->yuv.p_base );
131         return( 1 );
132     }
133     p_vout->yuv.p_offset = malloc( p_vout->i_width * sizeof( int ) );
134     if( p_vout->yuv.p_offset == NULL )
135     {
136         intf_ErrMsg("error: %s", strerror(ENOMEM));
137         free( p_vout->yuv.p_base );
138         free( p_vout->yuv.p_buffer );
139         return( 1 );
140     }
141
142     /* Initialize tables */
143     SetYUV( p_vout );
144     return( 0 );
145 }
146
147 /*****************************************************************************
148  * yuv_End: destroy translations tables
149  *****************************************************************************
150  * Free memory allocated by yuv_CCreate.
151  *****************************************************************************/
152 static void yuv_End( vout_thread_t *p_vout )
153 {
154     free( p_vout->yuv.p_base );
155     free( p_vout->yuv.p_buffer );
156     free( p_vout->yuv.p_offset );
157 }
158
159 /*****************************************************************************
160  * yuv_Reset: re-initialize translations tables
161  *****************************************************************************
162  * This function will initialize the tables allocated by vout_CreateTables and
163  * set functions pointers.
164  *****************************************************************************/
165 static int yuv_Reset( vout_thread_t *p_vout )
166 {
167     yuv_End( p_vout );
168     return( yuv_Init( p_vout ) );
169 }
170
171 /*****************************************************************************
172  * SetYUV: compute tables and set function pointers
173  *****************************************************************************/
174 static void SetYUV( vout_thread_t *p_vout )
175 {
176     int         i_index;                                  /* index in tables */
177
178     /*
179      * Set pointers and build YUV tables
180      */
181     if( p_vout->b_grayscale )
182     {
183         /* Grayscale: build gray table */
184         if( p_vout->i_bytes_per_pixel == 1 )
185         {
186             u16 bright[256], transp[256];
187
188             for( i_index = 0; i_index < 256; i_index++)
189             {
190                 bright[ i_index ] = i_index << 8;
191                 transp[ i_index ] = 0;
192             }
193             /* the colors have been allocated, we can set the palette */
194             p_vout->pf_setpalette( p_vout, bright, bright, bright, transp );
195             p_vout->i_white_pixel = 0xff;
196             p_vout->i_black_pixel = 0x00;
197             p_vout->i_gray_pixel = 0x44;
198             p_vout->i_blue_pixel = 0x3b;
199         }
200     }
201     else
202     {
203         /* Color: build red, green and blue tables */
204         if( p_vout->i_bytes_per_pixel == 1 )
205         {
206             #define RGB_MIN 0
207             #define RGB_MAX 255
208             #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
209             #define SHIFT 20
210             #define U_GREEN_COEF    ((int)(-0.391 * (1<<SHIFT) / 1.164))
211             #define U_BLUE_COEF     ((int)(2.018 * (1<<SHIFT) / 1.164))
212             #define V_RED_COEF      ((int)(1.596 * (1<<SHIFT) / 1.164))
213             #define V_GREEN_COEF    ((int)(-0.813 * (1<<SHIFT) / 1.164))
214
215             int y,u,v;
216             int r,g,b;
217             int uvr, uvg, uvb;
218             int i = 0, j = 0;
219             u16 red[256], green[256], blue[256], transp[256];
220             unsigned char lookup[PALETTE_TABLE_SIZE];
221
222             p_vout->yuv.yuv.p_rgb8 = (u8 *)p_vout->yuv.p_base;
223
224             /* this loop calculates the intersection of an YUV box
225              * and the RGB cube. */
226             for ( y = 0; y <= 256; y += 16 )
227             {
228                 for ( u = 0; u <= 256; u += 32 )
229                 for ( v = 0; v <= 256; v += 32 )
230                 {
231                     uvr = (V_RED_COEF*(v-128)) >> SHIFT;
232                     uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT;
233                     uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
234                     r = y + uvr;
235                     g = y + uvg;
236                     b = y + uvb;
237
238                     if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN
239                             && r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
240                     {
241                         /* this one should never happen unless someone fscked up my code */
242                         if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette" ); break; }
243
244                         /* clip the colors */
245                         red[j] = CLIP( r );
246                         green[j] = CLIP( g );
247                         blue[j] = CLIP( b );
248                         transp[j] = 0;
249
250                         /* allocate color */
251                         lookup[i] = 1;
252                         p_vout->yuv.yuv.p_rgb8[i++] = j;
253                         j++;
254                     }
255                     else
256                     {
257                         lookup[i] = 0;
258                         p_vout->yuv.yuv.p_rgb8[i++] = 0;
259                     }
260                 }
261                 i += 128-81;
262             }
263
264             /* the colors have been allocated, we can set the palette */
265             /* there will eventually be a way to know which colors
266              * couldn't be allocated and try to find a replacement */
267             p_vout->pf_setpalette( p_vout, red, green, blue, transp );
268
269             p_vout->i_white_pixel = 0xff;
270             p_vout->i_black_pixel = 0x00;
271             p_vout->i_gray_pixel = 0x44;
272             p_vout->i_blue_pixel = 0x3b;
273
274             i = 0;
275             /* this loop allocates colors that got outside
276              * the RGB cube */
277             for ( y = 0; y <= 256; y += 16 )
278             {
279                 for ( u = 0; u <= 256; u += 32 )
280                 {
281                     for ( v = 0; v <= 256; v += 32 )
282                     {
283                         int u2, v2;
284                         int dist, mindist = 100000000;
285
286                         if( lookup[i] || y==0)
287                         {
288                             i++;
289                             continue;
290                         }
291
292                         /* heavy. yeah. */
293                         for( u2 = 0; u2 <= 256; u2 += 32 )
294                         for( v2 = 0; v2 <= 256; v2 += 32 )
295                         {
296                             j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5);
297                             dist = (u-u2)*(u-u2) + (v-v2)*(v-v2);
298                             if( lookup[j] )
299                             /* find the nearest color */
300                             if( dist < mindist )
301                             {
302                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
303                                 mindist = dist;
304                             }
305                             j -= 128;
306                             if( lookup[j] )
307                             /* find the nearest color */
308                             if( dist + 128 < mindist )
309                             {
310                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
311                                 mindist = dist + 128;
312                             }
313                         }
314                         i++;
315                     }
316                 }
317                 i += 128-81;
318             }
319         }
320     }
321
322     /*
323      * Set functions pointers
324      */
325     if( p_vout->b_YCbr)
326     {
327         switch( p_vout->i_bytes_per_pixel)
328         {
329 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
330         case 1:
331             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr8 );
332             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr8 );
333             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr8 );
334             break;
335         
336         case 2:
337             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr16 );
338             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr16 );
339             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr16 );
340             break;
341         
342         case 3:
343             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr24 );
344             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr24 );
345             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr24 );
346             break;
347         
348         case 4:
349             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr32 );
350             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr32 );
351             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr32 );
352             break;
353 #undef _X
354         }
355     }    
356     else if( p_vout->b_grayscale )
357     {
358         /* Grayscale */
359         switch( p_vout->i_bytes_per_pixel )
360         {
361 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
362         case 1:
363             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray8 );
364             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray8 );
365             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray8 );
366             break;
367         case 2:
368             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray16 );
369             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray16 );
370             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray16 );
371             break;
372         case 3:
373             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB24 );
374             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray24 );
375             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray24 );
376             break;
377         case 4:
378             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB32 );
379             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray32 );
380             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray32 );
381             break;
382 #undef _X
383         }
384     }
385     else
386     {
387         /* Color */
388         switch( p_vout->i_bytes_per_pixel )
389         {
390 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
391         case 1:
392             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB8 );
393             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB8 );
394             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB8 );
395             break;
396         case 2:
397             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB16 );
398             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB16 );
399             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB16 );
400             break;
401         case 3:
402             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB24 );
403             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB24 );
404             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB24 );
405             break;
406         case 4:
407             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB32 );
408             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB32 );
409             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB32 );
410             break;
411 #undef _X
412         }
413     }
414 }
415
416 /*****************************************************************************
417  * SetOffset: build offset array for conversion functions
418  *****************************************************************************
419  * This function will build an offset array used in later conversion functions.
420  * It will also set horizontal and vertical scaling indicators. If b_double
421  * is set, the p_offset structure has interleaved Y and U/V offsets.
422  *****************************************************************************/
423 void _M( SetOffset )( int i_width, int i_height, int i_pic_width,
424                       int i_pic_height, boolean_t *pb_h_scaling,
425                       int *pi_v_scaling, int *p_offset, boolean_t b_double )
426 {
427     int i_x;                                    /* x position in destination */
428     int i_scale_count;                                     /* modulo counter */
429
430     /*
431      * Prepare horizontal offset array
432      */
433     if( i_pic_width - i_width == 0 )
434     {
435         /* No horizontal scaling: YUV conversion is done directly to picture */
436         *pb_h_scaling = 0;
437     }
438     else if( i_pic_width - i_width > 0 )
439     {
440         /* Prepare scaling array for horizontal extension */
441         *pb_h_scaling =  1;
442         i_scale_count =  i_pic_width;
443         for( i_x = i_width; i_x--; )
444         {
445             while( (i_scale_count -= i_width) > 0 )
446             {
447                 *p_offset++ = 0;
448             }
449             *p_offset++ = 1;
450             i_scale_count += i_pic_width;
451         }
452     }
453     else /* if( i_pic_width - i_width < 0 ) */
454     {
455         /* Prepare scaling array for horizontal reduction */
456         *pb_h_scaling =  1;
457         i_scale_count =  i_width;
458         for( i_x = i_pic_width; i_x--; )
459         {
460             *p_offset = 1;
461             while( (i_scale_count -= i_pic_width) > 0 )
462             {
463                 *p_offset += 1;
464             }
465             p_offset++;
466             i_scale_count += i_width;
467         }
468     }
469
470     /*
471      * Set vertical scaling indicator
472      */
473     if( i_pic_height - i_height == 0 )
474     {
475         *pi_v_scaling = 0;
476     }
477     else if( i_pic_height - i_height > 0 )
478     {
479         *pi_v_scaling = 1;
480     }
481     else /* if( i_pic_height - i_height < 0 ) */
482     {
483         *pi_v_scaling = -1;
484     }
485 }
486