Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

i420_rgb.c

00001 /*****************************************************************************
00002  * i420_rgb.c : YUV to bitmap RGB conversion module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000, 2001, 2004 the VideoLAN team
00005  * $Id: i420_rgb.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Author: Sam Hocevar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <math.h>                                            /* exp(), pow() */
00028 #include <string.h>                                            /* strerror() */
00029 #include <stdlib.h>                                      /* malloc(), free() */
00030 
00031 #include <vlc/vlc.h>
00032 #include <vlc/vout.h>
00033 
00034 #include "i420_rgb.h"
00035 #if defined (MODULE_NAME_IS_i420_rgb)
00036 #   include "i420_rgb_c.h"
00037 #endif
00038 
00039 /*****************************************************************************
00040  * RGB2PIXEL: assemble RGB components to a pixel value, returns a uint32_t
00041  *****************************************************************************/
00042 #define RGB2PIXEL( p_vout, i_r, i_g, i_b )          \
00043     (((((uint32_t)i_r) >> p_vout->output.i_rrshift) \
00044                        << p_vout->output.i_lrshift) \
00045    | ((((uint32_t)i_g) >> p_vout->output.i_rgshift) \
00046                        << p_vout->output.i_lgshift) \
00047    | ((((uint32_t)i_b) >> p_vout->output.i_rbshift) \
00048                        << p_vout->output.i_lbshift))
00049 
00050 /*****************************************************************************
00051  * Local and extern prototypes.
00052  *****************************************************************************/
00053 static int  Activate   ( vlc_object_t * );
00054 static void Deactivate ( vlc_object_t * );
00055 
00056 #if defined (MODULE_NAME_IS_i420_rgb)
00057 static void SetGammaTable       ( int *pi_table, double f_gamma );
00058 static void SetYUV              ( vout_thread_t * );
00059 static void Set8bppPalette      ( vout_thread_t *, uint8_t * );
00060 #endif
00061 
00062 /*****************************************************************************
00063  * Module descriptor.
00064  *****************************************************************************/
00065 vlc_module_begin();
00066 #if defined (MODULE_NAME_IS_i420_rgb)
00067     set_description( _("I420,IYUV,YV12 to "
00068                        "RGB2,RV15,RV16,RV24,RV32 conversions") );
00069     set_capability( "chroma", 80 );
00070 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
00071     set_description( _( "MMX I420,IYUV,YV12 to "
00072                         "RV15,RV16,RV24,RV32 conversions") );
00073     set_capability( "chroma", 100 );
00074     add_requirement( MMX );
00075 #endif
00076     set_callbacks( Activate, Deactivate );
00077 vlc_module_end();
00078 
00079 /*****************************************************************************
00080  * Activate: allocate a chroma function
00081  *****************************************************************************
00082  * This function allocates and initializes a chroma function
00083  *****************************************************************************/
00084 static int Activate( vlc_object_t *p_this )
00085 {
00086     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00087 #if defined (MODULE_NAME_IS_i420_rgb)
00088     size_t i_tables_size;
00089 #endif
00090 
00091     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
00092     {
00093         return -1;
00094     }
00095 
00096     switch( p_vout->render.i_chroma )
00097     {
00098         case VLC_FOURCC('Y','V','1','2'):
00099         case VLC_FOURCC('I','4','2','0'):
00100         case VLC_FOURCC('I','Y','U','V'):
00101             switch( p_vout->output.i_chroma )
00102             {
00103 #if defined (MODULE_NAME_IS_i420_rgb)
00104                 case VLC_FOURCC('R','G','B','2'):
00105                     p_vout->chroma.pf_convert = E_(I420_RGB8);
00106                     break;
00107 #endif
00108                 case VLC_FOURCC('R','V','1','5'):
00109                 case VLC_FOURCC('R','V','1','6'):
00110 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
00111                     /* If we don't have support for the bitmasks, bail out */
00112                     if( ( p_vout->output.i_rmask != 0x7c00
00113                            || p_vout->output.i_gmask != 0x03e0
00114                            || p_vout->output.i_bmask != 0x001f )
00115                      && ( p_vout->output.i_rmask != 0xf800
00116                            || p_vout->output.i_gmask != 0x07e0
00117                            || p_vout->output.i_bmask != 0x001f ) )
00118                     {
00119                         return -1;
00120                     }
00121 #endif
00122                     p_vout->chroma.pf_convert = E_(I420_RGB16);
00123                     break;
00124 
00125 #if 0
00126                 /* Hmmm, is there only X11 using 32bits per pixel for RV24 ? */
00127                 case VLC_FOURCC('R','V','2','4'):
00128 #endif
00129 
00130                 case VLC_FOURCC('R','V','3','2'):
00131 #if defined (MODULE_NAME_IS_i420_rgb_mmx)
00132                     /* If we don't have support for the bitmasks, bail out */
00133                     if( p_vout->output.i_rmask != 0x00ff0000
00134                          || p_vout->output.i_gmask != 0x0000ff00
00135                          || p_vout->output.i_bmask != 0x000000ff )
00136                     {
00137                         return -1;
00138                     }
00139 #endif
00140                     p_vout->chroma.pf_convert = E_(I420_RGB32);
00141                     break;
00142 
00143                 default:
00144                     return -1;
00145             }
00146             break;
00147 
00148         default:
00149             return -1;
00150     }
00151 
00152     p_vout->chroma.p_sys = malloc( sizeof( chroma_sys_t ) );
00153     if( p_vout->chroma.p_sys == NULL )
00154     {
00155         return -1;
00156     }
00157 
00158     switch( p_vout->output.i_chroma )
00159     {
00160 #if defined (MODULE_NAME_IS_i420_rgb)
00161         case VLC_FOURCC('R','G','B','2'):
00162             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH );
00163             break;
00164 #endif
00165 
00166         case VLC_FOURCC('R','V','1','5'):
00167         case VLC_FOURCC('R','V','1','6'):
00168             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 2 );
00169             break;
00170 
00171         case VLC_FOURCC('R','V','2','4'):
00172         case VLC_FOURCC('R','V','3','2'):
00173             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 4 );
00174             break;
00175 
00176         default:
00177             p_vout->chroma.p_sys->p_buffer = NULL;
00178             break;
00179     }
00180 
00181     if( p_vout->chroma.p_sys->p_buffer == NULL )
00182     {
00183         free( p_vout->chroma.p_sys );
00184         return -1;
00185     }
00186 
00187     p_vout->chroma.p_sys->p_offset = malloc( p_vout->output.i_width
00188                     * ( ( p_vout->output.i_chroma
00189                            == VLC_FOURCC('R','G','B','2') ) ? 2 : 1 )
00190                     * sizeof( int ) );
00191     if( p_vout->chroma.p_sys->p_offset == NULL )
00192     {
00193         free( p_vout->chroma.p_sys->p_buffer );
00194         free( p_vout->chroma.p_sys );
00195         return -1;
00196     }
00197 
00198 #if defined (MODULE_NAME_IS_i420_rgb)
00199     switch( p_vout->output.i_chroma )
00200     {
00201     case VLC_FOURCC('R','G','B','2'):
00202         i_tables_size = sizeof( uint8_t ) * PALETTE_TABLE_SIZE;
00203         break;
00204     case VLC_FOURCC('R','V','1','5'):
00205     case VLC_FOURCC('R','V','1','6'):
00206         i_tables_size = sizeof( uint16_t ) * RGB_TABLE_SIZE;
00207         break;
00208     default: /* RV24, RV32 */
00209         i_tables_size = sizeof( uint32_t ) * RGB_TABLE_SIZE;
00210         break;
00211     }
00212 
00213     p_vout->chroma.p_sys->p_base = malloc( i_tables_size );
00214     if( p_vout->chroma.p_sys->p_base == NULL )
00215     {
00216         free( p_vout->chroma.p_sys->p_offset );
00217         free( p_vout->chroma.p_sys->p_buffer );
00218         free( p_vout->chroma.p_sys );
00219         return -1;
00220     }
00221 
00222     SetYUV( p_vout );
00223 #endif
00224 
00225     return 0;
00226 }
00227 
00228 /*****************************************************************************
00229  * Deactivate: free the chroma function
00230  *****************************************************************************
00231  * This function frees the previously allocated chroma function
00232  *****************************************************************************/
00233 static void Deactivate( vlc_object_t *p_this )
00234 {
00235     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00236 
00237 #if defined (MODULE_NAME_IS_i420_rgb)
00238     free( p_vout->chroma.p_sys->p_base );
00239 #endif
00240     free( p_vout->chroma.p_sys->p_offset );
00241     free( p_vout->chroma.p_sys->p_buffer );
00242     free( p_vout->chroma.p_sys );
00243 }
00244 
00245 #if defined (MODULE_NAME_IS_i420_rgb)
00246 /*****************************************************************************
00247  * SetGammaTable: return intensity table transformed by gamma curve.
00248  *****************************************************************************
00249  * pi_table is a table of 256 entries from 0 to 255.
00250  *****************************************************************************/
00251 static void SetGammaTable( int *pi_table, double f_gamma )
00252 {
00253     int i_y;                                               /* base intensity */
00254 
00255     /* Use exp(gamma) instead of gamma */
00256     f_gamma = exp( f_gamma );
00257 
00258     /* Build gamma table */
00259     for( i_y = 0; i_y < 256; i_y++ )
00260     {
00261         pi_table[ i_y ] = (int)( pow( (double)i_y / 256, f_gamma ) * 256 );
00262     }
00263 }
00264 
00265 /*****************************************************************************
00266  * SetYUV: compute tables and set function pointers
00267  *****************************************************************************/
00268 static void SetYUV( vout_thread_t *p_vout )
00269 {
00270     int          pi_gamma[256];                               /* gamma table */
00271     volatile int i_index;                                 /* index in tables */
00272                    /* We use volatile here to work around a strange gcc-3.3.4
00273                     * optimization bug */
00274 
00275     /* Build gamma table */
00276     SetGammaTable( pi_gamma, p_vout->f_gamma );
00277 
00278     /*
00279      * Set pointers and build YUV tables
00280      */
00281 
00282     /* Color: build red, green and blue tables */
00283     switch( p_vout->output.i_chroma )
00284     {
00285     case VLC_FOURCC('R','G','B','2'):
00286         p_vout->chroma.p_sys->p_rgb8 = (uint8_t *)p_vout->chroma.p_sys->p_base;
00287         Set8bppPalette( p_vout, p_vout->chroma.p_sys->p_rgb8 );
00288         break;
00289 
00290     case VLC_FOURCC('R','V','1','5'):
00291     case VLC_FOURCC('R','V','1','6'):
00292         p_vout->chroma.p_sys->p_rgb16 = (uint16_t *)p_vout->chroma.p_sys->p_base;
00293         for( i_index = 0; i_index < RED_MARGIN; i_index++ )
00294         {
00295             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
00296             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
00297         }
00298         for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
00299         {
00300             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
00301             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
00302         }
00303         for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
00304         {
00305             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
00306             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
00307         }
00308         for( i_index = 0; i_index < 256; i_index++ )
00309         {
00310             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
00311             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
00312             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
00313         }
00314         break;
00315 
00316     case VLC_FOURCC('R','V','2','4'):
00317     case VLC_FOURCC('R','V','3','2'):
00318         p_vout->chroma.p_sys->p_rgb32 = (uint32_t *)p_vout->chroma.p_sys->p_base;
00319         for( i_index = 0; i_index < RED_MARGIN; i_index++ )
00320         {
00321             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
00322             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
00323         }
00324         for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
00325         {
00326             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
00327             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
00328         }
00329         for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
00330         {
00331             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
00332             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
00333         }
00334         for( i_index = 0; i_index < 256; i_index++ )
00335         {
00336             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
00337             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
00338             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
00339         }
00340         break;
00341     }
00342 }
00343 
00344 static void Set8bppPalette( vout_thread_t *p_vout, uint8_t *p_rgb8 )
00345 {
00346     #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
00347 
00348     int y,u,v;
00349     int r,g,b;
00350     int i = 0, j = 0;
00351     uint16_t *p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
00352     uint16_t *p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
00353     uint16_t *p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
00354 
00355     unsigned char p_lookup[PALETTE_TABLE_SIZE];
00356 
00357     /* This loop calculates the intersection of an YUV box and the RGB cube. */
00358     for ( y = 0; y <= 256; y += 16, i += 128 - 81 )
00359     {
00360         for ( u = 0; u <= 256; u += 32 )
00361         {
00362             for ( v = 0; v <= 256; v += 32 )
00363             {
00364                 r = y + ( (V_RED_COEF*(v-128)) >> SHIFT );
00365                 g = y + ( (U_GREEN_COEF*(u-128)
00366                          + V_GREEN_COEF*(v-128)) >> SHIFT );
00367                 b = y + ( (U_BLUE_COEF*(u-128)) >> SHIFT );
00368 
00369                 if( r >= 0x00 && g >= 0x00 && b >= 0x00
00370                         && r <= 0xff && g <= 0xff && b <= 0xff )
00371                 {
00372                     /* This one should never happen unless someone
00373                      * fscked up my code */
00374                     if( j == 256 )
00375                     {
00376                         msg_Err( p_vout, "no colors left in palette" );
00377                         break;
00378                     }
00379 
00380                     /* Clip the colors */
00381                     p_cmap_r[ j ] = CLIP( r );
00382                     p_cmap_g[ j ] = CLIP( g );
00383                     p_cmap_b[ j ] = CLIP( b );
00384 
00385 #if 0
00386                     printf("+++Alloc RGB cmap %d (%d, %d, %d)\n", j,
00387                            p_cmap_r[ j ] >>8, p_cmap_g[ j ] >>8, 
00388                            p_cmap_b[ j ] >>8);
00389 #endif
00390 
00391                     /* Allocate color */
00392                     p_lookup[ i ] = 1;
00393                     p_rgb8[ i++ ] = j;
00394                     j++;
00395                 }
00396                 else
00397                 {
00398                     p_lookup[ i ] = 0;
00399                     p_rgb8[ i++ ] = 0;
00400                 }
00401             }
00402         }
00403     }
00404 
00405     /* The colors have been allocated, we can set the palette */
00406     p_vout->output.pf_setpalette( p_vout, p_cmap_r, p_cmap_g, p_cmap_b );
00407 
00408 #if 0
00409     /* There will eventually be a way to know which colors
00410      * couldn't be allocated and try to find a replacement */
00411     p_vout->i_white_pixel = 0xff;
00412     p_vout->i_black_pixel = 0x00;
00413     p_vout->i_gray_pixel = 0x44;
00414     p_vout->i_blue_pixel = 0x3b;
00415 #endif
00416 
00417     /* This loop allocates colors that got outside the RGB cube */
00418     for ( i = 0, y = 0; y <= 256; y += 16, i += 128 - 81 )
00419     {
00420         for ( u = 0; u <= 256; u += 32 )
00421         {
00422             for ( v = 0; v <= 256; v += 32, i++ )
00423             {
00424                 int u2, v2, dist, mindist = 100000000;
00425 
00426                 if( p_lookup[ i ] || y == 0 )
00427                 {
00428                     continue;
00429                 }
00430 
00431                 /* Heavy. yeah. */
00432                 for( u2 = 0; u2 <= 256; u2 += 32 )
00433                 {
00434                     for( v2 = 0; v2 <= 256; v2 += 32 )
00435                     {
00436                         j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5);
00437                         dist = (u-u2)*(u-u2) + (v-v2)*(v-v2);
00438 
00439                         /* Find the nearest color */
00440                         if( p_lookup[ j ] && dist < mindist )
00441                         {
00442                             p_rgb8[ i ] = p_rgb8[ j ];
00443                             mindist = dist;
00444                         }
00445 
00446                         j -= 128;
00447 
00448                         /* Find the nearest color */
00449                         if( p_lookup[ j ] && dist + 128 < mindist )
00450                         {
00451                             p_rgb8[ i ] = p_rgb8[ j ];
00452                             mindist = dist + 128;
00453                         }
00454                     }
00455                 }
00456             }
00457         }
00458     }
00459 }
00460 
00461 #endif
00462 

Generated on Tue Dec 20 10:14:50 2005 for vlc-0.8.4a by  doxygen 1.4.2