i420_rgb.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:17k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * i420_rgb.c : YUV to bitmap RGB conversion module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001, 2004 VideoLAN
  5.  * $Id: i420_rgb.c 8564 2004-08-29 09:58:07Z gbazin $
  6.  *
  7.  * Author: Sam Hocevar <sam@zoy.org>
  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
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <math.h>                                            /* exp(), pow() */
  27. #include <string.h>                                            /* strerror() */
  28. #include <stdlib.h>                                      /* malloc(), free() */
  29. #include <vlc/vlc.h>
  30. #include <vlc/vout.h>
  31. #include "i420_rgb.h"
  32. #if defined (MODULE_NAME_IS_i420_rgb)
  33. #   include "i420_rgb_c.h"
  34. #endif
  35. /*****************************************************************************
  36.  * RGB2PIXEL: assemble RGB components to a pixel value, returns a uint32_t
  37.  *****************************************************************************/
  38. #define RGB2PIXEL( p_vout, i_r, i_g, i_b )          
  39.     (((((uint32_t)i_r) >> p_vout->output.i_rrshift) 
  40.                        << p_vout->output.i_lrshift) 
  41.    | ((((uint32_t)i_g) >> p_vout->output.i_rgshift) 
  42.                        << p_vout->output.i_lgshift) 
  43.    | ((((uint32_t)i_b) >> p_vout->output.i_rbshift) 
  44.                        << p_vout->output.i_lbshift))
  45. /*****************************************************************************
  46.  * Local and extern prototypes.
  47.  *****************************************************************************/
  48. static int  Activate   ( vlc_object_t * );
  49. static void Deactivate ( vlc_object_t * );
  50. #if defined (MODULE_NAME_IS_i420_rgb)
  51. static void SetGammaTable       ( int *pi_table, double f_gamma );
  52. static void SetYUV              ( vout_thread_t * );
  53. static void Set8bppPalette      ( vout_thread_t *, uint8_t * );
  54. #endif
  55. /*****************************************************************************
  56.  * Module descriptor.
  57.  *****************************************************************************/
  58. vlc_module_begin();
  59. #if defined (MODULE_NAME_IS_i420_rgb)
  60.     set_description( _("I420,IYUV,YV12 to "
  61.                        "RGB2,RV15,RV16,RV24,RV32 conversions") );
  62.     set_capability( "chroma", 80 );
  63. #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
  64.     set_description( _( "MMX I420,IYUV,YV12 to "
  65.                         "RV15,RV16,RV24,RV32 conversions") );
  66.     set_capability( "chroma", 100 );
  67.     add_requirement( MMX );
  68. #endif
  69.     set_callbacks( Activate, Deactivate );
  70. vlc_module_end();
  71. /*****************************************************************************
  72.  * Activate: allocate a chroma function
  73.  *****************************************************************************
  74.  * This function allocates and initializes a chroma function
  75.  *****************************************************************************/
  76. static int Activate( vlc_object_t *p_this )
  77. {
  78.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  79. #if defined (MODULE_NAME_IS_i420_rgb)
  80.     size_t i_tables_size;
  81. #endif
  82.     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
  83.     {
  84.         return -1;
  85.     }
  86.     switch( p_vout->render.i_chroma )
  87.     {
  88.         case VLC_FOURCC('Y','V','1','2'):
  89.         case VLC_FOURCC('I','4','2','0'):
  90.         case VLC_FOURCC('I','Y','U','V'):
  91.             switch( p_vout->output.i_chroma )
  92.             {
  93. #if defined (MODULE_NAME_IS_i420_rgb)
  94.                 case VLC_FOURCC('R','G','B','2'):
  95.                     p_vout->chroma.pf_convert = E_(I420_RGB8);
  96.                     break;
  97. #endif
  98.                 case VLC_FOURCC('R','V','1','5'):
  99.                 case VLC_FOURCC('R','V','1','6'):
  100. #if defined (MODULE_NAME_IS_i420_rgb_mmx)
  101.                     /* If we don't have support for the bitmasks, bail out */
  102.                     if( ( p_vout->output.i_rmask != 0x7c00
  103.                            || p_vout->output.i_gmask != 0x03e0
  104.                            || p_vout->output.i_bmask != 0x001f )
  105.                      && ( p_vout->output.i_rmask != 0xf800
  106.                            || p_vout->output.i_gmask != 0x07e0
  107.                            || p_vout->output.i_bmask != 0x001f ) )
  108.                     {
  109.                         return -1;
  110.                     }
  111. #endif
  112.                     p_vout->chroma.pf_convert = E_(I420_RGB16);
  113.                     break;
  114. #if 0
  115.                 /* Hmmm, is there only X11 using 32bits per pixel for RV24 ? */
  116.                 case VLC_FOURCC('R','V','2','4'):
  117. #endif
  118.                 case VLC_FOURCC('R','V','3','2'):
  119. #if defined (MODULE_NAME_IS_i420_rgb_mmx)
  120.                     /* If we don't have support for the bitmasks, bail out */
  121.                     if( p_vout->output.i_rmask != 0x00ff0000
  122.                          || p_vout->output.i_gmask != 0x0000ff00
  123.                          || p_vout->output.i_bmask != 0x000000ff )
  124.                     {
  125.                         return -1;
  126.                     }
  127. #endif
  128.                     p_vout->chroma.pf_convert = E_(I420_RGB32);
  129.                     break;
  130.                 default:
  131.                     return -1;
  132.             }
  133.             break;
  134.         default:
  135.             return -1;
  136.     }
  137.     p_vout->chroma.p_sys = malloc( sizeof( chroma_sys_t ) );
  138.     if( p_vout->chroma.p_sys == NULL )
  139.     {
  140.         return -1;
  141.     }
  142.     switch( p_vout->output.i_chroma )
  143.     {
  144. #if defined (MODULE_NAME_IS_i420_rgb)
  145.         case VLC_FOURCC('R','G','B','2'):
  146.             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH );
  147.             break;
  148. #endif
  149.         case VLC_FOURCC('R','V','1','5'):
  150.         case VLC_FOURCC('R','V','1','6'):
  151.             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 2 );
  152.             break;
  153.         case VLC_FOURCC('R','V','2','4'):
  154.         case VLC_FOURCC('R','V','3','2'):
  155.             p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 4 );
  156.             break;
  157.         default:
  158.             p_vout->chroma.p_sys->p_buffer = NULL;
  159.             break;
  160.     }
  161.     if( p_vout->chroma.p_sys->p_buffer == NULL )
  162.     {
  163.         free( p_vout->chroma.p_sys );
  164.         return -1;
  165.     }
  166.     p_vout->chroma.p_sys->p_offset = malloc( p_vout->output.i_width
  167.                     * ( ( p_vout->output.i_chroma
  168.                            == VLC_FOURCC('R','G','B','2') ) ? 2 : 1 )
  169.                     * sizeof( int ) );
  170.     if( p_vout->chroma.p_sys->p_offset == NULL )
  171.     {
  172.         free( p_vout->chroma.p_sys->p_buffer );
  173.         free( p_vout->chroma.p_sys );
  174.         return -1;
  175.     }
  176. #if defined (MODULE_NAME_IS_i420_rgb)
  177.     switch( p_vout->output.i_chroma )
  178.     {
  179.     case VLC_FOURCC('R','G','B','2'):
  180.         i_tables_size = sizeof( uint8_t ) * PALETTE_TABLE_SIZE;
  181.         break;
  182.     case VLC_FOURCC('R','V','1','5'):
  183.     case VLC_FOURCC('R','V','1','6'):
  184.         i_tables_size = sizeof( uint16_t ) * RGB_TABLE_SIZE;
  185.         break;
  186.     default: /* RV24, RV32 */
  187.         i_tables_size = sizeof( uint32_t ) * RGB_TABLE_SIZE;
  188.         break;
  189.     }
  190.     p_vout->chroma.p_sys->p_base = malloc( i_tables_size );
  191.     if( p_vout->chroma.p_sys->p_base == NULL )
  192.     {
  193.         free( p_vout->chroma.p_sys->p_offset );
  194.         free( p_vout->chroma.p_sys->p_buffer );
  195.         free( p_vout->chroma.p_sys );
  196.         return -1;
  197.     }
  198.     SetYUV( p_vout );
  199. #endif
  200.     return 0;
  201. }
  202. /*****************************************************************************
  203.  * Deactivate: free the chroma function
  204.  *****************************************************************************
  205.  * This function frees the previously allocated chroma function
  206.  *****************************************************************************/
  207. static void Deactivate( vlc_object_t *p_this )
  208. {
  209.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  210. #if defined (MODULE_NAME_IS_i420_rgb)
  211.     free( p_vout->chroma.p_sys->p_base );
  212. #endif
  213.     free( p_vout->chroma.p_sys->p_offset );
  214.     free( p_vout->chroma.p_sys->p_buffer );
  215.     free( p_vout->chroma.p_sys );
  216. }
  217. #if defined (MODULE_NAME_IS_i420_rgb)
  218. /*****************************************************************************
  219.  * SetGammaTable: return intensity table transformed by gamma curve.
  220.  *****************************************************************************
  221.  * pi_table is a table of 256 entries from 0 to 255.
  222.  *****************************************************************************/
  223. static void SetGammaTable( int *pi_table, double f_gamma )
  224. {
  225.     int i_y;                                               /* base intensity */
  226.     /* Use exp(gamma) instead of gamma */
  227.     f_gamma = exp( f_gamma );
  228.     /* Build gamma table */
  229.     for( i_y = 0; i_y < 256; i_y++ )
  230.     {
  231.         pi_table[ i_y ] = (int)( pow( (double)i_y / 256, f_gamma ) * 256 );
  232.     }
  233. }
  234. /*****************************************************************************
  235.  * SetYUV: compute tables and set function pointers
  236.  *****************************************************************************/
  237. static void SetYUV( vout_thread_t *p_vout )
  238. {
  239.     int          pi_gamma[256];                               /* gamma table */
  240.     volatile int i_index;                                 /* index in tables */
  241.                    /* We use volatile here to work around a strange gcc-3.3.4
  242.                     * optimization bug */
  243.     /* Build gamma table */
  244.     SetGammaTable( pi_gamma, p_vout->f_gamma );
  245.     /*
  246.      * Set pointers and build YUV tables
  247.      */
  248.     /* Color: build red, green and blue tables */
  249.     switch( p_vout->output.i_chroma )
  250.     {
  251.     case VLC_FOURCC('R','G','B','2'):
  252.         p_vout->chroma.p_sys->p_rgb8 = (uint8_t *)p_vout->chroma.p_sys->p_base;
  253.         Set8bppPalette( p_vout, p_vout->chroma.p_sys->p_rgb8 );
  254.         break;
  255.     case VLC_FOURCC('R','V','1','5'):
  256.     case VLC_FOURCC('R','V','1','6'):
  257.         p_vout->chroma.p_sys->p_rgb16 = (uint16_t *)p_vout->chroma.p_sys->p_base;
  258.         for( i_index = 0; i_index < RED_MARGIN; i_index++ )
  259.         {
  260.             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
  261.             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
  262.         }
  263.         for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
  264.         {
  265.             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
  266.             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
  267.         }
  268.         for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
  269.         {
  270.             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
  271.             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
  272.         }
  273.         for( i_index = 0; i_index < 256; i_index++ )
  274.         {
  275.             p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
  276.             p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
  277.             p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
  278.         }
  279.         break;
  280.     case VLC_FOURCC('R','V','2','4'):
  281.     case VLC_FOURCC('R','V','3','2'):
  282.         p_vout->chroma.p_sys->p_rgb32 = (uint32_t *)p_vout->chroma.p_sys->p_base;
  283.         for( i_index = 0; i_index < RED_MARGIN; i_index++ )
  284.         {
  285.             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
  286.             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + 256 + i_index] =        RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
  287.         }
  288.         for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
  289.         {
  290.             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
  291.             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + 256 + i_index] =          RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
  292.         }
  293.         for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
  294.         {
  295.             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
  296.             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
  297.         }
  298.         for( i_index = 0; i_index < 256; i_index++ )
  299.         {
  300.             p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + i_index] =   RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
  301.             p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
  302.             p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + i_index] =  RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
  303.         }
  304.         break;
  305.     }
  306. }
  307. static void Set8bppPalette( vout_thread_t *p_vout, uint8_t *p_rgb8 )
  308. {
  309.     #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
  310.     int y,u,v;
  311.     int r,g,b;
  312.     int i = 0, j = 0;
  313.     uint16_t *p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
  314.     uint16_t *p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
  315.     uint16_t *p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
  316.     unsigned char p_lookup[PALETTE_TABLE_SIZE];
  317.     /* This loop calculates the intersection of an YUV box and the RGB cube. */
  318.     for ( y = 0; y <= 256; y += 16, i += 128 - 81 )
  319.     {
  320.         for ( u = 0; u <= 256; u += 32 )
  321.         {
  322.             for ( v = 0; v <= 256; v += 32 )
  323.             {
  324.                 r = y + ( (V_RED_COEF*(v-128)) >> SHIFT );
  325.                 g = y + ( (U_GREEN_COEF*(u-128)
  326.                          + V_GREEN_COEF*(v-128)) >> SHIFT );
  327.                 b = y + ( (U_BLUE_COEF*(u-128)) >> SHIFT );
  328.                 if( r >= 0x00 && g >= 0x00 && b >= 0x00
  329.                         && r <= 0xff && g <= 0xff && b <= 0xff )
  330.                 {
  331.                     /* This one should never happen unless someone
  332.                      * fscked up my code */
  333.                     if( j == 256 )
  334.                     {
  335.                         msg_Err( p_vout, "no colors left in palette" );
  336.                         break;
  337.                     }
  338.                     /* Clip the colors */
  339.                     p_cmap_r[ j ] = CLIP( r );
  340.                     p_cmap_g[ j ] = CLIP( g );
  341.                     p_cmap_b[ j ] = CLIP( b );
  342. #if 0
  343.     printf("+++Alloc RGB cmap %d (%d, %d, %d)n", j,
  344.    p_cmap_r[ j ] >>8, p_cmap_g[ j ] >>8, 
  345.    p_cmap_b[ j ] >>8);
  346. #endif
  347.                     /* Allocate color */
  348.                     p_lookup[ i ] = 1;
  349.                     p_rgb8[ i++ ] = j;
  350.                     j++;
  351.                 }
  352.                 else
  353.                 {
  354.                     p_lookup[ i ] = 0;
  355.                     p_rgb8[ i++ ] = 0;
  356.                 }
  357.             }
  358.         }
  359.     }
  360.     /* The colors have been allocated, we can set the palette */
  361.     p_vout->output.pf_setpalette( p_vout, p_cmap_r, p_cmap_g, p_cmap_b );
  362. #if 0
  363.     /* There will eventually be a way to know which colors
  364.      * couldn't be allocated and try to find a replacement */
  365.     p_vout->i_white_pixel = 0xff;
  366.     p_vout->i_black_pixel = 0x00;
  367.     p_vout->i_gray_pixel = 0x44;
  368.     p_vout->i_blue_pixel = 0x3b;
  369. #endif
  370.     /* This loop allocates colors that got outside the RGB cube */
  371.     for ( i = 0, y = 0; y <= 256; y += 16, i += 128 - 81 )
  372.     {
  373.         for ( u = 0; u <= 256; u += 32 )
  374.         {
  375.             for ( v = 0; v <= 256; v += 32, i++ )
  376.             {
  377.                 int u2, v2, dist, mindist = 100000000;
  378.                 if( p_lookup[ i ] || y == 0 )
  379.                 {
  380.                     continue;
  381.                 }
  382.                 /* Heavy. yeah. */
  383.                 for( u2 = 0; u2 <= 256; u2 += 32 )
  384.                 {
  385.                     for( v2 = 0; v2 <= 256; v2 += 32 )
  386.                     {
  387.                         j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5);
  388.                         dist = (u-u2)*(u-u2) + (v-v2)*(v-v2);
  389.                         /* Find the nearest color */
  390.                         if( p_lookup[ j ] && dist < mindist )
  391.                         {
  392.                             p_rgb8[ i ] = p_rgb8[ j ];
  393.                             mindist = dist;
  394.                         }
  395.                         j -= 128;
  396.                         /* Find the nearest color */
  397.                         if( p_lookup[ j ] && dist + 128 < mindist )
  398.                         {
  399.                             p_rgb8[ i ] = p_rgb8[ j ];
  400.                             mindist = dist + 128;
  401.                         }
  402.                     }
  403.                 }
  404.             }
  405.         }
  406.     }
  407. }
  408. #endif