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