]> git.sesse.net Git - vlc/blob - plugins/yuv/video_yuvmmx.c
* libdvdcss enhancements by Billy Biggs <vektor@dumbterm.net>. This breaks
[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.11 2001/07/11 02:01:05 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          || TestMethod( YUV_METHOD_VAR, "mmx" ) )
90     {
91         return( 999 );
92     }
93
94     return( 100 );
95 }
96
97 /*****************************************************************************
98  * yuv_Init: allocate and initialize translations tables
99  *****************************************************************************
100  * This function will allocate memory to store translation tables, depending
101  * of the screen depth.
102  *****************************************************************************/
103 static int yuv_Init( vout_thread_t *p_vout )
104 {
105     size_t      tables_size;                        /* tables size, in bytes */
106
107     /* Computes tables size for 8bbp only */
108     if( p_vout->i_bytes_per_pixel == 1 )
109     {
110         tables_size = sizeof( u8 )
111                 * (p_vout->b_grayscale ? GRAY_TABLE_SIZE : PALETTE_TABLE_SIZE);
112
113         /* Allocate memory */
114         p_vout->yuv.p_base = malloc( tables_size );
115         if( p_vout->yuv.p_base == NULL )
116         {
117             intf_ErrMsg("error: %s", strerror(ENOMEM));
118             return( 1 );
119         }
120     }
121     else
122     {
123         p_vout->yuv.p_base = NULL;
124     }
125
126     /* Allocate memory for conversion buffer and offset array */
127     p_vout->yuv.p_buffer = malloc( VOUT_MAX_WIDTH * p_vout->i_bytes_per_pixel );
128     if( p_vout->yuv.p_buffer == NULL )
129     {
130         intf_ErrMsg("error: %s", strerror(ENOMEM));
131         free( p_vout->yuv.p_base );
132         return( 1 );
133     }
134     p_vout->yuv.p_offset = malloc( p_vout->i_width * sizeof( int ) );
135     if( p_vout->yuv.p_offset == NULL )
136     {
137         intf_ErrMsg("error: %s", strerror(ENOMEM));
138         free( p_vout->yuv.p_base );
139         free( p_vout->yuv.p_buffer );
140         return( 1 );
141     }
142
143     /* Initialize tables */
144     SetYUV( p_vout );
145     return( 0 );
146 }
147
148 /*****************************************************************************
149  * yuv_End: destroy translations tables
150  *****************************************************************************
151  * Free memory allocated by yuv_CCreate.
152  *****************************************************************************/
153 static void yuv_End( vout_thread_t *p_vout )
154 {
155     free( p_vout->yuv.p_base );
156     free( p_vout->yuv.p_buffer );
157     free( p_vout->yuv.p_offset );
158 }
159
160 /*****************************************************************************
161  * yuv_Reset: re-initialize translations tables
162  *****************************************************************************
163  * This function will initialize the tables allocated by vout_CreateTables and
164  * set functions pointers.
165  *****************************************************************************/
166 static int yuv_Reset( vout_thread_t *p_vout )
167 {
168     yuv_End( p_vout );
169     return( yuv_Init( p_vout ) );
170 }
171
172 /*****************************************************************************
173  * SetYUV: compute tables and set function pointers
174  *****************************************************************************/
175 static void SetYUV( vout_thread_t *p_vout )
176 {
177     int         i_index;                                  /* index in tables */
178
179     /*
180      * Set pointers and build YUV tables
181      */
182     if( p_vout->b_grayscale )
183     {
184         /* Grayscale: build gray table */
185         if( p_vout->i_bytes_per_pixel == 1 )
186         {
187             u16 bright[256], transp[256];
188
189             for( i_index = 0; i_index < 256; i_index++)
190             {
191                 bright[ i_index ] = i_index << 8;
192                 transp[ i_index ] = 0;
193             }
194             /* the colors have been allocated, we can set the palette */
195             p_vout->pf_setpalette( p_vout, bright, bright, bright, transp );
196             p_vout->i_white_pixel = 0xff;
197             p_vout->i_black_pixel = 0x00;
198             p_vout->i_gray_pixel = 0x44;
199             p_vout->i_blue_pixel = 0x3b;
200         }
201     }
202     else
203     {
204         /* Color: build red, green and blue tables */
205         if( p_vout->i_bytes_per_pixel == 1 )
206         {
207             #define RGB_MIN 0
208             #define RGB_MAX 255
209             #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
210             #define SHIFT 20
211             #define U_GREEN_COEF    ((int)(-0.391 * (1<<SHIFT) / 1.164))
212             #define U_BLUE_COEF     ((int)(2.018 * (1<<SHIFT) / 1.164))
213             #define V_RED_COEF      ((int)(1.596 * (1<<SHIFT) / 1.164))
214             #define V_GREEN_COEF    ((int)(-0.813 * (1<<SHIFT) / 1.164))
215
216             int y,u,v;
217             int r,g,b;
218             int uvr, uvg, uvb;
219             int i = 0, j = 0;
220             u16 red[256], green[256], blue[256], transp[256];
221             unsigned char lookup[PALETTE_TABLE_SIZE];
222
223             p_vout->yuv.yuv.p_rgb8 = (u8 *)p_vout->yuv.p_base;
224
225             /* this loop calculates the intersection of an YUV box
226              * and the RGB cube. */
227             for ( y = 0; y <= 256; y += 16 )
228             {
229                 for ( u = 0; u <= 256; u += 32 )
230                 for ( v = 0; v <= 256; v += 32 )
231                 {
232                     uvr = (V_RED_COEF*(v-128)) >> SHIFT;
233                     uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT;
234                     uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
235                     r = y + uvr;
236                     g = y + uvg;
237                     b = y + uvb;
238
239                     if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN
240                             && r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
241                     {
242                         /* this one should never happen unless someone fscked up my code */
243                         if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette" ); break; }
244
245                         /* clip the colors */
246                         red[j] = CLIP( r );
247                         green[j] = CLIP( g );
248                         blue[j] = CLIP( b );
249                         transp[j] = 0;
250
251                         /* allocate color */
252                         lookup[i] = 1;
253                         p_vout->yuv.yuv.p_rgb8[i++] = j;
254                         j++;
255                     }
256                     else
257                     {
258                         lookup[i] = 0;
259                         p_vout->yuv.yuv.p_rgb8[i++] = 0;
260                     }
261                 }
262                 i += 128-81;
263             }
264
265             /* the colors have been allocated, we can set the palette */
266             /* there will eventually be a way to know which colors
267              * couldn't be allocated and try to find a replacement */
268             p_vout->pf_setpalette( p_vout, red, green, blue, transp );
269
270             p_vout->i_white_pixel = 0xff;
271             p_vout->i_black_pixel = 0x00;
272             p_vout->i_gray_pixel = 0x44;
273             p_vout->i_blue_pixel = 0x3b;
274
275             i = 0;
276             /* this loop allocates colors that got outside
277              * the RGB cube */
278             for ( y = 0; y <= 256; y += 16 )
279             {
280                 for ( u = 0; u <= 256; u += 32 )
281                 {
282                     for ( v = 0; v <= 256; v += 32 )
283                     {
284                         int u2, v2;
285                         int dist, mindist = 100000000;
286
287                         if( lookup[i] || y==0)
288                         {
289                             i++;
290                             continue;
291                         }
292
293                         /* heavy. yeah. */
294                         for( u2 = 0; u2 <= 256; u2 += 32 )
295                         for( v2 = 0; v2 <= 256; v2 += 32 )
296                         {
297                             j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5);
298                             dist = (u-u2)*(u-u2) + (v-v2)*(v-v2);
299                             if( lookup[j] )
300                             /* find the nearest color */
301                             if( dist < mindist )
302                             {
303                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
304                                 mindist = dist;
305                             }
306                             j -= 128;
307                             if( lookup[j] )
308                             /* find the nearest color */
309                             if( dist + 128 < mindist )
310                             {
311                                 p_vout->yuv.yuv.p_rgb8[i] = p_vout->yuv.yuv.p_rgb8[j];
312                                 mindist = dist + 128;
313                             }
314                         }
315                         i++;
316                     }
317                 }
318                 i += 128-81;
319             }
320         }
321     }
322
323     /*
324      * Set functions pointers
325      */
326     if( p_vout->b_YCbr)
327     {
328         switch( p_vout->i_bytes_per_pixel)
329         {
330 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
331         case 1:
332             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr8 );
333             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr8 );
334             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr8 );
335             break;
336         
337         case 2:
338             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr16 );
339             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr16 );
340             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr16 );
341             break;
342         
343         case 3:
344             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr24 );
345             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr24 );
346             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr24 );
347             break;
348         
349         case 4:
350             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420YCbr32 );
351             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422YCbr32 );
352             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444YCbr32 );
353             break;
354 #undef _X
355         }
356     }    
357     else if( p_vout->b_grayscale )
358     {
359         /* Grayscale */
360         switch( p_vout->i_bytes_per_pixel )
361         {
362 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
363         case 1:
364             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray8 );
365             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray8 );
366             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray8 );
367             break;
368         case 2:
369             p_vout->yuv.pf_yuv420 = _X( ConvertY4Gray16 );
370             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray16 );
371             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray16 );
372             break;
373         case 3:
374             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB24 );
375             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray24 );
376             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray24 );
377             break;
378         case 4:
379             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB32 );
380             p_vout->yuv.pf_yuv422 = _X( ConvertY4Gray32 );
381             p_vout->yuv.pf_yuv444 = _X( ConvertY4Gray32 );
382             break;
383 #undef _X
384         }
385     }
386     else
387     {
388         /* Color */
389         switch( p_vout->i_bytes_per_pixel )
390         {
391 #define _X( foo ) (vout_yuv_convert_t *) _M( foo )
392         case 1:
393             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB8 );
394             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB8 );
395             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB8 );
396             break;
397         case 2:
398             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB16 );
399             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB16 );
400             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB16 );
401             break;
402         case 3:
403             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB24 );
404             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB24 );
405             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB24 );
406             break;
407         case 4:
408             p_vout->yuv.pf_yuv420 = _X( ConvertYUV420RGB32 );
409             p_vout->yuv.pf_yuv422 = _X( ConvertYUV422RGB32 );
410             p_vout->yuv.pf_yuv444 = _X( ConvertYUV444RGB32 );
411             break;
412 #undef _X
413         }
414     }
415 }
416
417 /*****************************************************************************
418  * SetOffset: build offset array for conversion functions
419  *****************************************************************************
420  * This function will build an offset array used in later conversion functions.
421  * It will also set horizontal and vertical scaling indicators. If b_double
422  * is set, the p_offset structure has interleaved Y and U/V offsets.
423  *****************************************************************************/
424 void _M( SetOffset )( int i_width, int i_height, int i_pic_width,
425                       int i_pic_height, boolean_t *pb_h_scaling,
426                       int *pi_v_scaling, int *p_offset, boolean_t b_double )
427 {
428     int i_x;                                    /* x position in destination */
429     int i_scale_count;                                     /* modulo counter */
430
431     /*
432      * Prepare horizontal offset array
433      */
434     if( i_pic_width - i_width == 0 )
435     {
436         /* No horizontal scaling: YUV conversion is done directly to picture */
437         *pb_h_scaling = 0;
438     }
439     else if( i_pic_width - i_width > 0 )
440     {
441         /* Prepare scaling array for horizontal extension */
442         *pb_h_scaling =  1;
443         i_scale_count =  i_pic_width;
444         for( i_x = i_width; i_x--; )
445         {
446             while( (i_scale_count -= i_width) > 0 )
447             {
448                 *p_offset++ = 0;
449             }
450             *p_offset++ = 1;
451             i_scale_count += i_pic_width;
452         }
453     }
454     else /* if( i_pic_width - i_width < 0 ) */
455     {
456         /* Prepare scaling array for horizontal reduction */
457         *pb_h_scaling =  1;
458         i_scale_count =  i_width;
459         for( i_x = i_pic_width; i_x--; )
460         {
461             *p_offset = 1;
462             while( (i_scale_count -= i_pic_width) > 0 )
463             {
464                 *p_offset += 1;
465             }
466             p_offset++;
467             i_scale_count += i_width;
468         }
469     }
470
471     /*
472      * Set vertical scaling indicator
473      */
474     if( i_pic_height - i_height == 0 )
475     {
476         *pi_v_scaling = 0;
477     }
478     else if( i_pic_height - i_height > 0 )
479     {
480         *pi_v_scaling = 1;
481     }
482     else /* if( i_pic_height - i_height < 0 ) */
483     {
484         *pi_v_scaling = -1;
485     }
486 }
487