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

i420_yuy2.c

00001 /*****************************************************************************
00002  * i420_yuy2.c : YUV to YUV conversion module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000, 2001 the VideoLAN team
00005  * $Id: i420_yuy2.c 12371 2005-08-23 18:23:20Z sam $
00006  *
00007  * Authors: Samuel 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 <string.h>                                            /* strerror() */
00028 #include <stdlib.h>                                      /* malloc(), free() */
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/vout.h>
00032 
00033 #if defined (MODULE_NAME_IS_i420_yuy2_altivec) && defined(HAVE_ALTIVEC_H)
00034 #   include <altivec.h>
00035 #endif
00036 
00037 #include "i420_yuy2.h"
00038 
00039 #define SRC_FOURCC  "I420,IYUV,YV12"
00040 
00041 #if defined (MODULE_NAME_IS_i420_yuy2)
00042 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
00043 #elif defined (MODULE_NAME_IS_i420_yuy2_mmx)
00044 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
00045 #elif defined (MODULE_NAME_IS_i420_yuy2_altivec)
00046 #    define DEST_FOURCC "YUY2,YUNV"
00047 #endif
00048 
00049 /*****************************************************************************
00050  * Local and extern prototypes.
00051  *****************************************************************************/
00052 static int  Activate ( vlc_object_t * );
00053 
00054 static void I420_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
00055 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
00056 static void I420_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
00057 static void I420_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
00058 static void I420_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
00059 static void I420_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
00060 #endif
00061 #if defined (MODULE_NAME_IS_i420_yuy2)
00062 static void I420_Y211           ( vout_thread_t *, picture_t *, picture_t * );
00063 #endif
00064 
00065 #ifdef MODULE_NAME_IS_i420_yuy2_mmx
00066 static uint64_t i_00ffw;
00067 static uint64_t i_80w;
00068 #endif
00069 
00070 /*****************************************************************************
00071  * Module descriptor.
00072  *****************************************************************************/
00073 vlc_module_begin();
00074 #if defined (MODULE_NAME_IS_i420_yuy2)
00075     set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
00076     set_capability( "chroma", 80 );
00077 #elif defined (MODULE_NAME_IS_i420_yuy2_mmx)
00078     set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
00079     set_capability( "chroma", 100 );
00080     add_requirement( MMX );
00081     /* Initialize MMX-specific constants */
00082     i_00ffw = 0x00ff00ff00ff00ffULL;
00083     i_80w   = 0x0000000080808080ULL;
00084 #elif defined (MODULE_NAME_IS_i420_yuy2_altivec)
00085     set_description(
00086             _("AltiVec conversions from " SRC_FOURCC " to " DEST_FOURCC) );
00087     set_capability( "chroma", 100 );
00088     add_requirement( ALTIVEC );
00089 #endif
00090     set_callbacks( Activate, NULL );
00091 vlc_module_end();
00092 
00093 /*****************************************************************************
00094  * Activate: allocate a chroma function
00095  *****************************************************************************
00096  * This function allocates and initializes a chroma function
00097  *****************************************************************************/
00098 static int Activate( vlc_object_t *p_this )
00099 {
00100     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00101 
00102     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
00103     {
00104         return -1;
00105     }
00106 
00107     switch( p_vout->render.i_chroma )
00108     {
00109         case VLC_FOURCC('Y','V','1','2'):
00110         case VLC_FOURCC('I','4','2','0'):
00111         case VLC_FOURCC('I','Y','U','V'):
00112             switch( p_vout->output.i_chroma )
00113             {
00114                 case VLC_FOURCC('Y','U','Y','2'):
00115                 case VLC_FOURCC('Y','U','N','V'):
00116                     p_vout->chroma.pf_convert = I420_YUY2;
00117                     break;
00118 
00119 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
00120                 case VLC_FOURCC('Y','V','Y','U'):
00121                     p_vout->chroma.pf_convert = I420_YVYU;
00122                     break;
00123 
00124                 case VLC_FOURCC('U','Y','V','Y'):
00125                 case VLC_FOURCC('U','Y','N','V'):
00126                 case VLC_FOURCC('Y','4','2','2'):
00127                     p_vout->chroma.pf_convert = I420_UYVY;
00128                     break;
00129 
00130                 case VLC_FOURCC('I','U','Y','V'):
00131                     p_vout->chroma.pf_convert = I420_IUYV;
00132                     break;
00133 
00134                 case VLC_FOURCC('c','y','u','v'):
00135                     p_vout->chroma.pf_convert = I420_cyuv;
00136                     break;
00137 #endif
00138 
00139 #if defined (MODULE_NAME_IS_i420_yuy2)
00140                 case VLC_FOURCC('Y','2','1','1'):
00141                     p_vout->chroma.pf_convert = I420_Y211;
00142                     break;
00143 #endif
00144 
00145                 default:
00146                     return -1;
00147             }
00148             break;
00149 
00150         default:
00151             return -1;
00152     }
00153 
00154     return 0;
00155 }
00156 
00157 /* Following functions are local */
00158 
00159 /*****************************************************************************
00160  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
00161  *****************************************************************************/
00162 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
00163                                               picture_t *p_dest )
00164 {
00165     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
00166     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
00167     uint8_t *p_u = p_source->U_PIXELS;
00168     uint8_t *p_v = p_source->V_PIXELS;
00169 
00170     int i_x, i_y;
00171 
00172 #if defined (MODULE_NAME_IS_i420_yuy2_altivec)
00173 #define VEC_NEXT_LINES( ) \
00174     p_line1  = p_line2; \
00175     p_line2 += p_dest->p->i_pitch; \
00176     p_y1     = p_y2; \
00177     p_y2    += p_source->p[Y_PLANE].i_pitch;
00178 
00179 #define VEC_LOAD_UV( ) \
00180     u_vec = vec_ld( 0, p_u ); p_u += 16; \
00181     v_vec = vec_ld( 0, p_v ); p_v += 16;
00182 
00183 #define VEC_MERGE( a ) \
00184     uv_vec = a( u_vec, v_vec ); \
00185     y_vec = vec_ld( 0, p_y1 ); p_y1 += 16; \
00186     vec_st( vec_mergeh( y_vec, uv_vec ), 0, p_line1 ); p_line1 += 16; \
00187     vec_st( vec_mergel( y_vec, uv_vec ), 0, p_line1 ); p_line1 += 16; \
00188     y_vec = vec_ld( 0, p_y2 ); p_y2 += 16; \
00189     vec_st( vec_mergeh( y_vec, uv_vec ), 0, p_line2 ); p_line2 += 16; \
00190     vec_st( vec_mergel( y_vec, uv_vec ), 0, p_line2 ); p_line2 += 16;
00191 
00192     vector unsigned char u_vec;
00193     vector unsigned char v_vec;
00194     vector unsigned char uv_vec;
00195     vector unsigned char y_vec;
00196 
00197     if( !( ( p_vout->render.i_width % 32 ) |
00198            ( p_vout->render.i_height % 2 ) ) )
00199     {
00200         /* Width is a multiple of 32, we take 2 lines at a time */
00201         for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00202         {
00203             VEC_NEXT_LINES( );
00204             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
00205             {
00206                 VEC_LOAD_UV( );
00207                 VEC_MERGE( vec_mergeh );
00208                 VEC_MERGE( vec_mergel );
00209             }
00210         }
00211     }
00212     else if( !( ( p_vout->render.i_width % 16 ) |
00213                 ( p_vout->render.i_height % 4 ) ) )
00214     {
00215         /* Width is only a multiple of 16, we take 4 lines at a time */
00216         for( i_y = p_vout->render.i_height / 4 ; i_y-- ; )
00217         {
00218             /* Line 1 and 2, pixels 0 to ( width - 16 ) */
00219             VEC_NEXT_LINES( );
00220             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
00221             {
00222                 VEC_LOAD_UV( );
00223                 VEC_MERGE( vec_mergeh );
00224                 VEC_MERGE( vec_mergel );
00225             }
00226 
00227             /* Line 1 and 2, pixels ( width - 16 ) to ( width ) */
00228             VEC_LOAD_UV( );
00229             VEC_MERGE( vec_mergeh );
00230 
00231             /* Line 3 and 4, pixels 0 to 16 */
00232             VEC_NEXT_LINES( );
00233             VEC_MERGE( vec_mergel );
00234 
00235             /* Line 3 and 4, pixels 16 to ( width ) */
00236             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
00237             {
00238                 VEC_LOAD_UV( );
00239                 VEC_MERGE( vec_mergeh );
00240                 VEC_MERGE( vec_mergel );
00241             }
00242         }
00243     }
00244     else
00245     {
00246         /* Crap, use the C version */
00247 #undef VEC_NEXT_LINES
00248 #undef VEC_LOAD_UV
00249 #undef VEC_MERGE
00250 #endif
00251 
00252     const int i_source_margin = p_source->p[0].i_pitch
00253                                  - p_source->p[0].i_visible_pitch;
00254     const int i_source_margin_c = p_source->p[1].i_pitch
00255                                  - p_source->p[1].i_visible_pitch;
00256     const int i_dest_margin = p_dest->p->i_pitch
00257                                - p_dest->p->i_visible_pitch;
00258 
00259     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00260     {
00261         p_line1 = p_line2;
00262         p_line2 += p_dest->p->i_pitch;
00263 
00264         p_y1 = p_y2;
00265         p_y2 += p_source->p[Y_PLANE].i_pitch;
00266 
00267 #if !defined (MODULE_NAME_IS_i420_yuy2_mmx)
00268         for( i_x = p_vout->render.i_width / 2 ; i_x-- ; )
00269         {
00270             C_YUV420_YUYV( );
00271         }
00272 #else
00273         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
00274         {
00275             MMX_CALL( MMX_YUV420_YUYV );
00276         }
00277         for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
00278         {
00279             C_YUV420_YUYV( );
00280         }
00281 #endif
00282 
00283         p_y1 += i_source_margin;
00284         p_y2 += i_source_margin;
00285         p_u += i_source_margin_c;
00286         p_v += i_source_margin_c;
00287         p_line1 += i_dest_margin;
00288         p_line2 += i_dest_margin;
00289     }
00290 
00291 #if defined (MODULE_NAME_IS_i420_yuy2_altivec)
00292     }
00293 #endif
00294 }
00295 
00296 /*****************************************************************************
00297  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
00298  *****************************************************************************/
00299 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
00300 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
00301                                               picture_t *p_dest )
00302 {
00303     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
00304     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
00305     uint8_t *p_u = p_source->U_PIXELS;
00306     uint8_t *p_v = p_source->V_PIXELS;
00307 
00308     int i_x, i_y;
00309 
00310     const int i_source_margin = p_source->p[0].i_pitch
00311                                  - p_source->p[0].i_visible_pitch;
00312     const int i_source_margin_c = p_source->p[1].i_pitch
00313                                  - p_source->p[1].i_visible_pitch;
00314     const int i_dest_margin = p_dest->p->i_pitch
00315                                - p_dest->p->i_visible_pitch;
00316 
00317     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00318     {
00319         p_line1 = p_line2;
00320         p_line2 += p_dest->p->i_pitch;
00321 
00322         p_y1 = p_y2;
00323         p_y2 += p_source->p[Y_PLANE].i_pitch;
00324 
00325         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
00326         {
00327 #if defined (MODULE_NAME_IS_i420_yuy2)
00328             C_YUV420_YVYU( );
00329             C_YUV420_YVYU( );
00330             C_YUV420_YVYU( );
00331             C_YUV420_YVYU( );
00332 #else
00333             MMX_CALL( MMX_YUV420_YVYU );
00334 #endif
00335         }
00336 
00337         p_y1 += i_source_margin;
00338         p_y2 += i_source_margin;
00339         p_u += i_source_margin_c;
00340         p_v += i_source_margin_c;
00341         p_line1 += i_dest_margin;
00342         p_line2 += i_dest_margin;
00343     }
00344 }
00345 
00346 /*****************************************************************************
00347  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
00348  *****************************************************************************/
00349 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
00350                                               picture_t *p_dest )
00351 {
00352     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
00353     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
00354     uint8_t *p_u = p_source->U_PIXELS;
00355     uint8_t *p_v = p_source->V_PIXELS;
00356 
00357     int i_x, i_y;
00358 
00359     const int i_source_margin = p_source->p[0].i_pitch
00360                                  - p_source->p[0].i_visible_pitch;
00361     const int i_source_margin_c = p_source->p[1].i_pitch
00362                                  - p_source->p[1].i_visible_pitch;
00363     const int i_dest_margin = p_dest->p->i_pitch
00364                                - p_dest->p->i_visible_pitch;
00365 
00366     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00367     {
00368         p_line1 = p_line2;
00369         p_line2 += p_dest->p->i_pitch;
00370 
00371         p_y1 = p_y2;
00372         p_y2 += p_source->p[Y_PLANE].i_pitch;
00373 
00374         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
00375         {
00376 #if defined (MODULE_NAME_IS_i420_yuy2)
00377             C_YUV420_UYVY( );
00378             C_YUV420_UYVY( );
00379             C_YUV420_UYVY( );
00380             C_YUV420_UYVY( );
00381 #else
00382             MMX_CALL( MMX_YUV420_UYVY );
00383 #endif
00384         }
00385 
00386         p_y1 += i_source_margin;
00387         p_y2 += i_source_margin;
00388         p_u += i_source_margin_c;
00389         p_v += i_source_margin_c;
00390         p_line1 += i_dest_margin;
00391         p_line2 += i_dest_margin;
00392     }
00393 }
00394 
00395 /*****************************************************************************
00396  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
00397  *****************************************************************************/
00398 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
00399                                               picture_t *p_dest )
00400 {
00401     /* FIXME: TODO ! */
00402     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <[email protected]>" );
00403 }
00404 
00405 /*****************************************************************************
00406  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
00407  *****************************************************************************/
00408 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
00409                                               picture_t *p_dest )
00410 {
00411     uint8_t *p_line1 = p_dest->p->p_pixels +
00412                        p_dest->p->i_visible_lines * p_dest->p->i_pitch
00413                        + p_dest->p->i_pitch;
00414     uint8_t *p_line2 = p_dest->p->p_pixels +
00415                        p_dest->p->i_visible_lines * p_dest->p->i_pitch;
00416     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
00417     uint8_t *p_u = p_source->U_PIXELS;
00418     uint8_t *p_v = p_source->V_PIXELS;
00419 
00420     int i_x, i_y;
00421 
00422     const int i_source_margin = p_source->p[0].i_pitch
00423                                  - p_source->p[0].i_visible_pitch;
00424     const int i_source_margin_c = p_source->p[1].i_pitch
00425                                  - p_source->p[1].i_visible_pitch;
00426     const int i_dest_margin = p_dest->p->i_pitch
00427                                - p_dest->p->i_visible_pitch;
00428 
00429     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00430     {
00431         p_line1 -= 3 * p_dest->p->i_pitch;
00432         p_line2 -= 3 * p_dest->p->i_pitch;
00433 
00434         p_y1 = p_y2;
00435         p_y2 += p_source->p[Y_PLANE].i_pitch;
00436 
00437         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
00438         {
00439 #if defined (MODULE_NAME_IS_i420_yuy2)
00440             C_YUV420_UYVY( );
00441             C_YUV420_UYVY( );
00442             C_YUV420_UYVY( );
00443             C_YUV420_UYVY( );
00444 #else
00445             MMX_CALL( MMX_YUV420_UYVY );
00446 #endif
00447         }
00448 
00449         p_y1 += i_source_margin;
00450         p_y2 += i_source_margin;
00451         p_u += i_source_margin_c;
00452         p_v += i_source_margin_c;
00453         p_line1 += i_dest_margin;
00454         p_line2 += i_dest_margin;
00455     }
00456 }
00457 #endif // !defined (MODULE_NAME_IS_i420_yuy2_altivec)
00458 
00459 /*****************************************************************************
00460  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
00461  *****************************************************************************/
00462 #if defined (MODULE_NAME_IS_i420_yuy2)
00463 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
00464                                               picture_t *p_dest )
00465 {
00466     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
00467     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
00468     uint8_t *p_u = p_source->U_PIXELS;
00469     uint8_t *p_v = p_source->V_PIXELS;
00470 
00471     int i_x, i_y;
00472 
00473     const int i_source_margin = p_source->p[0].i_pitch
00474                                  - p_source->p[0].i_visible_pitch;
00475     const int i_source_margin_c = p_source->p[1].i_pitch
00476                                  - p_source->p[1].i_visible_pitch;
00477     const int i_dest_margin = p_dest->p->i_pitch
00478                                - p_dest->p->i_visible_pitch;
00479 
00480     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
00481     {
00482         p_line1 = p_line2;
00483         p_line2 += p_dest->p->i_pitch;
00484 
00485         p_y1 = p_y2;
00486         p_y2 += p_source->p[Y_PLANE].i_pitch;
00487 
00488         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
00489         {
00490             C_YUV420_Y211( );
00491             C_YUV420_Y211( );
00492         }
00493 
00494         p_y1 += i_source_margin;
00495         p_y2 += i_source_margin;
00496         p_u += i_source_margin_c;
00497         p_v += i_source_margin_c;
00498         p_line1 += i_dest_margin;
00499         p_line2 += i_dest_margin;
00500     }
00501 }
00502 #endif
00503 

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