i420_rgb.h

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * i420_rgb.h : YUV to bitmap RGB conversion module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000, 2004 the VideoLAN team
00005  * $Id$
00006  *
00007  * Authors: Samuel Hocevar <sam@zoy.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
00022  *****************************************************************************/
00023 
00024 /** Number of entries in RGB palette/colormap */
00025 #define CMAP_RGB2_SIZE 256
00026 
00027 /**
00028  * filter_sys_t: chroma method descriptor
00029 
00030  * This structure is part of the chroma transformation descriptor, it
00031  * describes the yuv2rgb specific properties.
00032  */
00033 struct filter_sys_t
00034 {
00035     uint8_t  *p_buffer;
00036     int *p_offset;
00037 
00038 #ifdef MODULE_NAME_IS_i420_rgb
00039     /**< Pre-calculated conversion tables */
00040     void *p_base;                      /**< base for all conversion tables */
00041     uint8_t   *p_rgb8;                 /**< RGB 8 bits table */
00042     uint16_t  *p_rgb16;                /**< RGB 16 bits table */
00043     uint32_t  *p_rgb32;                /**< RGB 32 bits table */
00044 
00045     /**< To get RGB value for palette entry i, use (p_rgb_r[i], p_rgb_g[i],
00046        p_rgb_b[i]). Note these are 16 bits per pixel. For 8bpp entries,
00047        shift right 8 bits.
00048     */
00049     uint16_t  p_rgb_r[CMAP_RGB2_SIZE];  /**< Red values of palette */
00050     uint16_t  p_rgb_g[CMAP_RGB2_SIZE];  /**< Green values of palette */
00051     uint16_t  p_rgb_b[CMAP_RGB2_SIZE];  /**< Blue values of palette */
00052 #endif
00053 };
00054 
00055 /*****************************************************************************
00056  * Prototypes
00057  *****************************************************************************/
00058 #ifdef MODULE_NAME_IS_i420_rgb
00059 void I420_RGB8         ( filter_t *, picture_t *, picture_t * );
00060 void I420_RGB16_dither ( filter_t *, picture_t *, picture_t * );
00061 void I420_RGB16        ( filter_t *, picture_t *, picture_t * );
00062 void I420_RGB32        ( filter_t *, picture_t *, picture_t * );
00063 static picture_t *I420_RGB8_Filter         ( filter_t *, picture_t * );
00064 static picture_t *I420_RGB16_dither_Filter ( filter_t *, picture_t * );
00065 static picture_t *I420_RGB16_Filter        ( filter_t *, picture_t * );
00066 static picture_t *I420_RGB32_Filter        ( filter_t *, picture_t * );
00067 #else // if defined(MODULE_NAME_IS_i420_rgb_mmx)
00068 void I420_R5G5B5       ( filter_t *, picture_t *, picture_t * );
00069 void I420_R5G6B5       ( filter_t *, picture_t *, picture_t * );
00070 void I420_A8R8G8B8     ( filter_t *, picture_t *, picture_t * );
00071 void I420_R8G8B8A8     ( filter_t *, picture_t *, picture_t * );
00072 void I420_B8G8R8A8     ( filter_t *, picture_t *, picture_t * );
00073 void I420_A8B8G8R8     ( filter_t *, picture_t *, picture_t * );
00074 static picture_t *I420_R5G5B5_Filter       ( filter_t *, picture_t * );
00075 static picture_t *I420_R5G6B5_Filter       ( filter_t *, picture_t * );
00076 static picture_t *I420_A8R8G8B8_Filter     ( filter_t *, picture_t * );
00077 static picture_t *I420_R8G8B8A8_Filter     ( filter_t *, picture_t * );
00078 static picture_t *I420_B8G8R8A8_Filter     ( filter_t *, picture_t * );
00079 static picture_t *I420_A8B8G8R8_Filter     ( filter_t *, picture_t * );
00080 #endif
00081 
00082 /*****************************************************************************
00083  * CONVERT_*_PIXEL: pixel conversion macros
00084  *****************************************************************************
00085  * These conversion routines are used by YUV conversion functions.
00086  * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer,
00087  * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering,
00088  * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output.
00089  *****************************************************************************/
00090 #define CONVERT_Y_PIXEL( BPP )                                                \
00091     /* Only Y sample is present */                                            \
00092     p_ybase = p_yuv + *p_y++;                                                 \
00093     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] |     \
00094         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT)       \
00095         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue];
00096 
00097 #define CONVERT_YUV_PIXEL( BPP )                                              \
00098     /* Y, U and V samples are present */                                      \
00099     i_uval =    *p_u++;                                                       \
00100     i_vval =    *p_v++;                                                       \
00101     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
00102     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
00103     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
00104     CONVERT_Y_PIXEL( BPP )                                                    \
00105 
00106 #define CONVERT_Y_PIXEL_DITHER( BPP )                                         \
00107     /* Only Y sample is present */                                            \
00108     p_ybase = p_yuv + *p_y++;                                                 \
00109     *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128+p_dither[i_real_y])>>SHIFT) + i_red] |     \
00110         p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128+p_dither[i_real_y])>>SHIFT)       \
00111         + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128+p_dither[i_real_y])>>SHIFT) + i_blue];
00112 
00113 #define CONVERT_YUV_PIXEL_DITHER( BPP )                                       \
00114     /* Y, U and V samples are present */                                      \
00115     i_uval =    *p_u++;                                                       \
00116     i_vval =    *p_v++;                                                       \
00117     i_red =     (V_RED_COEF * i_vval) >> SHIFT;                               \
00118     i_green =   (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT;     \
00119     i_blue =    (U_BLUE_COEF * i_uval) >> SHIFT;                              \
00120     CONVERT_Y_PIXEL_DITHER( BPP )                                             \
00121 
00122 #define CONVERT_4YUV_PIXEL( CHROMA )                                          \
00123     *p_pic++ = p_lookup[                                                      \
00124         (((*p_y++ + dither10[i_real_y]) >> 4) << 7)                           \
00125       + ((*p_u + dither20[i_real_y]) >> 5) * 9                                \
00126       + ((*p_v + dither20[i_real_y]) >> 5) ];                                 \
00127     *p_pic++ = p_lookup[                                                      \
00128         (((*p_y++ + dither11[i_real_y]) >> 4) << 7)                           \
00129       + ((*p_u++ + dither21[i_real_y]) >> 5) * 9                              \
00130       + ((*p_v++ + dither21[i_real_y]) >> 5) ];                               \
00131     *p_pic++ = p_lookup[                                                      \
00132         (((*p_y++ + dither12[i_real_y]) >> 4) << 7)                           \
00133       + ((*p_u + dither22[i_real_y]) >> 5) * 9                                \
00134       + ((*p_v + dither22[i_real_y]) >> 5) ];                                 \
00135     *p_pic++ = p_lookup[                                                      \
00136         (((*p_y++ + dither13[i_real_y]) >> 4) << 7)                           \
00137       + ((*p_u++ + dither23[i_real_y]) >> 5) * 9                              \
00138       + ((*p_v++ + dither23[i_real_y]) >> 5) ];                               \
00139 
00140 #define CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                    \
00141     *p_pic++ = p_lookup[                                                      \
00142         ( ((*p_y + dither10[i_real_y]) >> 4) << 7)                            \
00143         + ((*p_u + dither20[i_real_y]) >> 5) * 9                              \
00144         + ((*p_v + dither20[i_real_y]) >> 5) ];                               \
00145     p_y += *p_offset++;                                                       \
00146     p_u += *p_offset;                                                         \
00147     p_v += *p_offset++;                                                       \
00148     *p_pic++ = p_lookup[                                                      \
00149         ( ((*p_y + dither11[i_real_y]) >> 4) << 7)                            \
00150         + ((*p_u + dither21[i_real_y]) >> 5) * 9                              \
00151         + ((*p_v + dither21[i_real_y]) >> 5) ];                               \
00152     p_y += *p_offset++;                                                       \
00153     p_u += *p_offset;                                                         \
00154     p_v += *p_offset++;                                                       \
00155     *p_pic++ = p_lookup[                                                      \
00156         ( ((*p_y + dither12[i_real_y]) >> 4) << 7)                            \
00157         + ((*p_u + dither22[i_real_y]) >> 5) * 9                              \
00158         + ((*p_v + dither22[i_real_y]) >> 5) ];                               \
00159     p_y += *p_offset++;                                                       \
00160     p_u += *p_offset;                                                         \
00161     p_v += *p_offset++;                                                       \
00162     *p_pic++ = p_lookup[                                                      \
00163         ( ((*p_y + dither13[i_real_y]) >> 4) << 7)                            \
00164         + ((*p_u + dither23[i_real_y]) >> 5) * 9                              \
00165         + ((*p_v + dither23[i_real_y]) >> 5) ];                               \
00166     p_y += *p_offset++;                                                       \
00167     p_u += *p_offset;                                                         \
00168     p_v += *p_offset++;                                                       \
00169 
00170 /*****************************************************************************
00171  * SCALE_WIDTH: scale a line horizontally
00172  *****************************************************************************
00173  * This macro scales a line using rendering buffer and offset array. It works
00174  * for 1, 2 and 4 Bpp.
00175  *****************************************************************************/
00176 #define SCALE_WIDTH                                                           \
00177     if( b_hscale )                                                            \
00178     {                                                                         \
00179         /* Horizontal scaling, conversion has been done to buffer.            \
00180          * Rewind buffer and offset, then copy and scale line */              \
00181         p_buffer = p_buffer_start;                                            \
00182         p_offset = p_offset_start;                                            \
00183         for( i_x = p_filter->fmt_out.video.i_width / 16; i_x--; )             \
00184         {                                                                     \
00185             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00186             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00187             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00188             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00189             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00190             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00191             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00192             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00193             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00194             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00195             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00196             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00197             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00198             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00199             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00200             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00201         }                                                                     \
00202         for( i_x = p_filter->fmt_out.video.i_width & 15; i_x--; )             \
00203         {                                                                     \
00204             *p_pic++ = *p_buffer;   p_buffer += *p_offset++;                  \
00205         }                                                                     \
00206         p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                   \
00207     }                                                                         \
00208     else                                                                      \
00209     {                                                                         \
00210         /* No scaling, conversion has been done directly in picture memory.   \
00211          * Increment of picture pointer to end of line is still needed */     \
00212         p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );               \
00213     }                                                                         \
00214 
00215 /*****************************************************************************
00216  * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp
00217  *****************************************************************************
00218  * This macro scales a line using an offset array.
00219  *****************************************************************************/
00220 #define SCALE_WIDTH_DITHER( CHROMA )                                          \
00221     if( b_hscale )                                                            \
00222     {                                                                         \
00223         /* Horizontal scaling - we can't use a buffer due to dithering */     \
00224         p_offset = p_offset_start;                                            \
00225         for( i_x = p_filter->fmt_out.video.i_width / 16; i_x--; )             \
00226         {                                                                     \
00227             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
00228             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
00229             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
00230             CONVERT_4YUV_PIXEL_SCALE( CHROMA )                                \
00231         }                                                                     \
00232     }                                                                         \
00233     else                                                                      \
00234     {                                                                         \
00235         for( i_x = p_filter->fmt_in.video.i_width / 16; i_x--;  )             \
00236         {                                                                     \
00237             CONVERT_4YUV_PIXEL( CHROMA )                                      \
00238             CONVERT_4YUV_PIXEL( CHROMA )                                      \
00239             CONVERT_4YUV_PIXEL( CHROMA )                                      \
00240             CONVERT_4YUV_PIXEL( CHROMA )                                      \
00241         }                                                                     \
00242     }                                                                         \
00243     /* Increment of picture pointer to end of line is still needed */         \
00244     p_pic = (void*)((uint8_t*)p_pic + i_right_margin );                       \
00245                                                                               \
00246     /* Increment the Y coordinate in the matrix, modulo 4 */                  \
00247     i_real_y = (i_real_y + 1) & 0x3;                                          \
00248 
00249 /*****************************************************************************
00250  * SCALE_HEIGHT: handle vertical scaling
00251  *****************************************************************************
00252  * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or
00253  * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3
00254  * and 4 Bpp.
00255  *****************************************************************************/
00256 #define SCALE_HEIGHT( CHROMA, BPP )                                           \
00257     /* If line is odd, rewind 4:2:0 U and V samples */                        \
00258     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
00259     {                                                                         \
00260         p_u -= i_chroma_width;                                                \
00261         p_v -= i_chroma_width;                                                \
00262     }                                                                         \
00263                                                                               \
00264     /*                                                                        \
00265      * Handle vertical scaling. The current line can be copied or next one    \
00266      * can be ignored.                                                        \
00267      */                                                                       \
00268     switch( i_vscale )                                                        \
00269     {                                                                         \
00270     case -1:                             /* vertical scaling factor is < 1 */ \
00271         while( (i_scale_count -= p_filter->fmt_out.video.i_height) > 0 )      \
00272         {                                                                     \
00273             /* Height reduction: skip next source line */                     \
00274             p_y += p_filter->fmt_in.video.i_width;                            \
00275             i_y++;                                                            \
00276             if( (CHROMA == 420) || (CHROMA == 422) )                          \
00277             {                                                                 \
00278                 if( i_y & 0x1 )                                               \
00279                 {                                                             \
00280                     p_u += i_chroma_width;                                    \
00281                     p_v += i_chroma_width;                                    \
00282                 }                                                             \
00283             }                                                                 \
00284             else if( CHROMA == 444 )                                          \
00285             {                                                                 \
00286                 p_u += p_filter->fmt_in.video.i_width;                        \
00287                 p_v += p_filter->fmt_in.video.i_width;                        \
00288             }                                                                 \
00289         }                                                                     \
00290         i_scale_count += p_filter->fmt_in.video.i_height;                     \
00291         break;                                                                \
00292     case 1:                              /* vertical scaling factor is > 1 */ \
00293         while( (i_scale_count -= p_filter->fmt_in.video.i_height) > 0 )       \
00294         {                                                                     \
00295             /* Height increment: copy previous picture line */                \
00296             vlc_memcpy( p_pic, p_pic_start, p_filter->fmt_out.video.i_width * BPP ); \
00297             p_pic = (void*)((uint8_t*)p_pic + p_dest->p->i_pitch );           \
00298         }                                                                     \
00299         i_scale_count += p_filter->fmt_out.video.i_height;                    \
00300         break;                                                                \
00301     }                                                                         \
00302 
00303 /*****************************************************************************
00304  * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp
00305  *****************************************************************************
00306  * This macro handles vertical scaling for a picture. CHROMA may be 420,
00307  * 422 or 444 for RGB conversion, or 400 for gray conversion.
00308  *****************************************************************************/
00309 #define SCALE_HEIGHT_DITHER( CHROMA )                                         \
00310                                                                               \
00311     /* If line is odd, rewind 4:2:0 U and V samples */                        \
00312     if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) )                \
00313     {                                                                         \
00314         p_u -= i_chroma_width;                                                \
00315         p_v -= i_chroma_width;                                                \
00316     }                                                                         \
00317                                                                               \
00318     /*                                                                        \
00319      * Handle vertical scaling. The current line can be copied or next one    \
00320      * can be ignored.                                                        \
00321      */                                                                       \
00322                                                                               \
00323     switch( i_vscale )                                                        \
00324     {                                                                         \
00325     case -1:                             /* vertical scaling factor is < 1 */ \
00326         while( (i_scale_count -= p_filter->fmt_out.video.i_height) > 0 )      \
00327         {                                                                     \
00328             /* Height reduction: skip next source line */                     \
00329             p_y += p_filter->fmt_in.video.i_width;                            \
00330             i_y++;                                                            \
00331             if( (CHROMA == 420) || (CHROMA == 422) )                          \
00332             {                                                                 \
00333                 if( i_y & 0x1 )                                               \
00334                 {                                                             \
00335                     p_u += i_chroma_width;                                    \
00336                     p_v += i_chroma_width;                                    \
00337                 }                                                             \
00338             }                                                                 \
00339             else if( CHROMA == 444 )                                          \
00340             {                                                                 \
00341                 p_u += p_filter->fmt_in.video.i_width;                        \
00342                 p_v += p_filter->fmt_in.video.i_width;                        \
00343             }                                                                 \
00344         }                                                                     \
00345         i_scale_count += p_filter->fmt_in.video.i_height;                     \
00346         break;                                                                \
00347     case 1:                              /* vertical scaling factor is > 1 */ \
00348         while( (i_scale_count -= p_filter->fmt_in.video.i_height) > 0 )       \
00349         {                                                                     \
00350             p_y -= p_filter->fmt_in.video.i_width;                            \
00351             p_u -= i_chroma_width;                                            \
00352             p_v -= i_chroma_width;                                            \
00353             SCALE_WIDTH_DITHER( CHROMA );                                     \
00354         }                                                                     \
00355         i_scale_count += p_filter->fmt_out.video.i_height;                    \
00356         break;                                                                \
00357     }                                                                         \
00358 

Generated on Wed Aug 13 08:02:38 2008 for VLC by  doxygen 1.5.1