Changeset 07d2f3edd5e3c3c64db6feac4c9e4317f470ccbe

Show
Ignore:
Timestamp:
20/08/08 23:23:19 (3 months ago)
Author:
Laurent Aimar <fenrir@videolan.org>
git-committer:
Laurent Aimar <fenrir@videolan.org> 1219267399 +0200
git-parent:

[d7507865a0e8c36ab44ede8b4f9ccc844b2a35c3]

git-author:
Laurent Aimar <fenrir@videolan.org> 1219267228 +0200
Message:

Last part of blend.c cleanup, added RV15 and fixed RV16 blending support.

I have tested that RGBA blending to I420/YUY2/RV32/RV16 have the right colors.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/video_filter/blend.c

    <
    rd750786 r07d2f3e  
    22 * blend.c: alpha blend 2 pictures together 
    33 ***************************************************************************** 
    4  * Copyright (C) 2003-2007 the VideoLAN team 
     4 * Copyright (C) 2003-2008 the VideoLAN team 
    55 * $Id$ 
    66 * 
     
    3030#endif 
    3131 
     32#include <assert.h> 
    3233#include <vlc_common.h> 
    3334#include <vlc_plugin.h> 
     
    3637 
    3738/***************************************************************************** 
     39 * Module descriptor 
     40 *****************************************************************************/ 
     41static int  OpenFilter ( vlc_object_t * ); 
     42static void CloseFilter( vlc_object_t * ); 
     43 
     44vlc_module_begin(); 
     45    set_description( N_("Video pictures blending") ); 
     46    set_capability( "video blending", 100 ); 
     47    set_callbacks( OpenFilter, CloseFilter ); 
     48vlc_module_end(); 
     49 
     50 
     51/***************************************************************************** 
    3852 * filter_sys_t : filter descriptor 
    3953 *****************************************************************************/ 
     
    4357}; 
    4458 
     59#define FCC_YUVA VLC_FOURCC('Y','U','V','A') 
     60#define FCC_YUVP VLC_FOURCC('Y','U','V','P') 
     61#define FCC_RGBA VLC_FOURCC('R','G','B','A') 
     62 
     63#define FCC_I420 VLC_FOURCC('I','4','2','0') 
     64#define FCC_YV12 VLC_FOURCC('Y','V','1','2') 
     65#define FCC_YUY2 VLC_FOURCC('Y','U','Y','2') 
     66#define FCC_UYVY VLC_FOURCC('U','Y','V','Y') 
     67#define FCC_YVYU VLC_FOURCC('Y','V','Y','U') 
     68#define FCC_RV15 VLC_FOURCC('R','V','1','5') 
     69#define FCC_RV16 VLC_FOURCC('R','V','1','6') 
     70#define FCC_RV24 VLC_FOURCC('R','V','2','4') 
     71#define FCC_RV32 VLC_FOURCC('R','V','3','2') 
     72 
    4573/**************************************************************************** 
    4674 * Local prototypes 
    4775 ****************************************************************************/ 
    48 static int  OpenFilter ( vlc_object_t * ); 
    49 static void CloseFilter( vlc_object_t * ); 
    50  
    5176static void Blend( filter_t *, picture_t *, picture_t *, picture_t *, 
    5277                   int, int, int ); 
    5378 
    54 /* TODO i_alpha support for BlendR16 */ 
    5579/* YUVA */ 
    5680static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *, 
     
    94118                          int, int, int, int, int ); 
    95119 
    96 /***************************************************************************** 
    97  * Module descriptor 
    98  *****************************************************************************/ 
    99 vlc_module_begin(); 
    100     set_description( N_("Video pictures blending") ); 
    101     set_capability( "video blending", 100 ); 
    102     set_callbacks( OpenFilter, CloseFilter ); 
    103 vlc_module_end(); 
     120static void video_format_FixRgb( video_format_t *p_fmt ); 
    104121 
    105122/***************************************************************************** 
     
    115132    int in_chroma = p_filter->fmt_in.video.i_chroma; 
    116133    int out_chroma = p_filter->fmt_out.video.i_chroma; 
    117     if( ( in_chroma  != VLC_FOURCC('Y','U','V','A') && 
    118           in_chroma  != VLC_FOURCC('I','4','2','0') && 
    119           in_chroma  != VLC_FOURCC('Y','V','1','2') && 
    120           in_chroma  != VLC_FOURCC('Y','U','V','P') && 
    121           in_chroma  != VLC_FOURCC('R','G','B','A') ) || 
    122         ( out_chroma != VLC_FOURCC('I','4','2','0') && 
    123           out_chroma != VLC_FOURCC('Y','U','Y','2') && 
    124           out_chroma != VLC_FOURCC('Y','V','1','2') && 
    125           out_chroma != VLC_FOURCC('U','Y','V','Y') && 
    126           out_chroma != VLC_FOURCC('Y','V','Y','U') && 
    127           out_chroma != VLC_FOURCC('R','V','1','6') && 
    128           out_chroma != VLC_FOURCC('R','V','2','4') && 
    129           out_chroma != VLC_FOURCC('R','V','3','2') ) ) 
     134    if( ( in_chroma  != FCC_YUVA && in_chroma  != FCC_I420 && 
     135          in_chroma  != FCC_YV12 && in_chroma  != FCC_YUVP && 
     136          in_chroma  != FCC_RGBA ) || 
     137        ( out_chroma != FCC_I420 && out_chroma != FCC_YUY2 && 
     138          out_chroma != FCC_YV12 && out_chroma != FCC_UYVY && 
     139          out_chroma != FCC_YVYU && out_chroma != FCC_RV15 && 
     140          out_chroma != FCC_YVYU && out_chroma != FCC_RV16 && 
     141          out_chroma != FCC_RV24 && out_chroma != FCC_RV32 ) ) 
    130142    { 
    131143        return VLC_EGENERIC; 
     
    133145 
    134146    /* Allocate the memory needed to store the decoder's structure */ 
    135     if( ( p_filter->p_sys = p_sys = 
    136           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL
     147    p_filter->p_sys = p_sys = malloc(sizeof(filter_sys_t)); 
     148    if( !p_sys
    137149        return VLC_ENOMEM; 
    138150 
     
    163175 * This function is called just after the thread is launched. 
    164176 ****************************************************************************/ 
     177typedef void (*BlendFunction)( filter_t *, picture_t *, 
     178                       picture_t *, picture_t *, 
     179                       int , int , int , int , int ); 
     180 
     181#define FCC_PLANAR_420 { FCC_I420, FCC_YV12, 0 } 
     182#define FCC_PACKED_422 { FCC_YUY2, FCC_UYVY, FCC_YVYU, 0 } 
     183#define FCC_RGB_16 { FCC_RV15, FCC_RV16, 0 } 
     184#define FCC_RGB_24 { FCC_RV24, FCC_RV32, 0 } 
     185 
     186#define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24  ) \ 
     187    { .src = fccSrc, .p_dst = FCC_PLANAR_420, .pf_blend = fctPlanar }, \ 
     188    { .src = fccSrc, .p_dst = FCC_PACKED_422, .pf_blend = fctPacked }, \ 
     189    { .src = fccSrc, .p_dst = FCC_RGB_16,     .pf_blend = fctRgb16  }, \ 
     190    { .src = fccSrc, .p_dst = FCC_RGB_24,     .pf_blend = fctRgb24  } 
     191 
     192static const struct 
     193{ 
     194    vlc_fourcc_t src; 
     195    vlc_fourcc_t p_dst[16]; 
     196    BlendFunction pf_blend; 
     197} p_blend_cfg[] = { 
     198 
     199    BLEND_CFG( FCC_YUVA, BlendI420, BlendYUVPacked, BlendR16, BlendR24 ), 
     200 
     201    BLEND_CFG( FCC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ), 
     202 
     203    BLEND_CFG( FCC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ), 
     204 
     205    BLEND_CFG( FCC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ), 
     206 
     207    BLEND_CFG( FCC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ), 
     208 
     209    { 0, {0,}, NULL } 
     210}; 
     211 
    165212static void Blend( filter_t *p_filter, picture_t *p_dst, 
    166213                   picture_t *p_dst_orig, picture_t *p_src, 
     
    169216    int i_width, i_height; 
    170217 
    171     if( i_alpha == 0 ) return; 
     218    if( i_alpha == 0 ) 
     219        return; 
    172220 
    173221    i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset, 
     
    177225                     (int)p_filter->fmt_in.video.i_visible_height); 
    178226 
    179     if( i_width <= 0 || i_height <= 0 ) return; 
     227    if( i_width <= 0 || i_height <= 0 ) 
     228        return; 
     229 
     230    video_format_FixRgb( &p_filter->fmt_out.video ); 
     231    video_format_FixRgb( &p_filter->fmt_in.video ); 
    180232 
    181233#if 0 
     
    185237#endif 
    186238 
    187     switch( p_filter->fmt_in.video.i_chroma ) 
    188     { 
    189         case VLC_FOURCC('Y','U','V','A'): 
    190             switch( p_filter->fmt_out.video.i_chroma ) 
    191             { 
    192                 case VLC_FOURCC('I','4','2','0'): 
    193                 case VLC_FOURCC('Y','V','1','2'): 
    194                     BlendI420( p_filter, p_dst, p_dst_orig, p_src, 
    195                                i_x_offset, i_y_offset, 
    196                                i_width, i_height, i_alpha ); 
    197                     return; 
    198                 case VLC_FOURCC('Y','U','Y','2'): 
    199                 case VLC_FOURCC('U','Y','V','Y'): 
    200                 case VLC_FOURCC('Y','V','Y','U'): 
    201                     BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src, 
    202                                     i_x_offset, i_y_offset, 
    203                                     i_width, i_height, i_alpha ); 
    204                     return; 
    205                 case VLC_FOURCC('R','V','1','6'): 
    206                     BlendR16( p_filter, p_dst, p_dst_orig, p_src, 
    207                               i_x_offset, i_y_offset, 
    208                               i_width, i_height, i_alpha ); 
    209                     return; 
    210                 case VLC_FOURCC('R','V','2','4'): 
    211                 case VLC_FOURCC('R','V','3','2'): 
    212                     BlendR24( p_filter, p_dst, p_dst_orig, p_src, 
    213                               i_x_offset, i_y_offset, 
    214                               i_width, i_height, i_alpha ); 
    215                     return; 
    216             } 
    217         case VLC_FOURCC('Y','U','V','P'): 
    218             switch( p_filter->fmt_out.video.i_chroma ) 
    219             { 
    220                 case VLC_FOURCC('I','4','2','0'): 
    221                 case VLC_FOURCC('Y','V','1','2'): 
    222                     BlendPalI420( p_filter, p_dst, p_dst_orig, p_src, 
    223                                   i_x_offset, i_y_offset, 
    224                                   i_width, i_height, i_alpha ); 
    225                     return; 
    226                 case VLC_FOURCC('Y','U','Y','2'): 
    227                 case VLC_FOURCC('U','Y','V','Y'): 
    228                 case VLC_FOURCC('Y','V','Y','U'): 
    229                     BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src, 
    230                                        i_x_offset, i_y_offset, 
    231                                        i_width, i_height, i_alpha ); 
    232                     return; 
    233                 case VLC_FOURCC('R','V','1','6'): 
    234                 case VLC_FOURCC('R','V','2','4'): 
    235                 case VLC_FOURCC('R','V','3','2'): 
    236                     BlendPalRV( p_filter, p_dst, p_dst_orig, p_src, 
    237                                 i_x_offset, i_y_offset, 
    238                                 i_width, i_height, i_alpha ); 
    239                     return; 
    240             } 
    241         case VLC_FOURCC('Y','V','1','2'): 
    242         case VLC_FOURCC('I','4','2','0'): 
    243             switch( p_filter->fmt_out.video.i_chroma ) 
    244             { 
    245                 case VLC_FOURCC('I','4','2','0'): 
    246                 case VLC_FOURCC('Y','V','1','2'): 
    247                     if( i_alpha == 0xff ) 
    248                         BlendI420I420_no_alpha( 
    249                                    p_filter, p_dst, p_dst_orig, p_src, 
    250                                    i_x_offset, i_y_offset, 
    251                                    i_width, i_height ); 
    252                     else 
    253                         BlendI420I420( p_filter, p_dst, p_dst_orig, p_src, 
    254                                        i_x_offset, i_y_offset, 
    255                                        i_width, i_height, i_alpha ); 
    256                     return; 
    257                 case VLC_FOURCC('Y','U','Y','2'): 
    258                 case VLC_FOURCC('U','Y','V','Y'): 
    259                 case VLC_FOURCC('Y','V','Y','U'): 
    260                     BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src, 
    261                                         i_x_offset, i_y_offset, 
    262                                         i_width, i_height, i_alpha ); 
    263                     return; 
    264                 case VLC_FOURCC('R','V','1','6'): 
    265                     BlendI420R16( p_filter, p_dst, p_dst_orig, p_src, 
    266                                   i_x_offset, i_y_offset, 
    267                                   i_width, i_height, i_alpha ); 
    268                     return; 
    269                 case VLC_FOURCC('R','V','2','4'): 
    270                 case VLC_FOURCC('R','V','3','2'): 
    271                     BlendI420R24( p_filter, p_dst, p_dst_orig, p_src, 
    272                                   i_x_offset, i_y_offset, 
    273                                   i_width, i_height, i_alpha ); 
    274                     return; 
    275             } 
    276         case VLC_FOURCC('R','G','B','A'): 
    277             switch( p_filter->fmt_out.video.i_chroma ) 
    278             { 
    279                 case VLC_FOURCC('I','4','2','0'): 
    280                 case VLC_FOURCC('Y','V','1','2'): 
    281                     BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src, 
    282                                    i_x_offset, i_y_offset, 
    283                                    i_width, i_height, i_alpha ); 
    284                     return; 
    285                 case VLC_FOURCC('Y','U','Y','2'): 
    286                 case VLC_FOURCC('U','Y','V','Y'): 
    287                 case VLC_FOURCC('Y','V','Y','U'): 
    288                     BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src, 
    289                                         i_x_offset, i_y_offset, 
    290                                         i_width, i_height, i_alpha ); 
    291                     return; 
    292                 case VLC_FOURCC('R','V','2','4'): 
    293                 case VLC_FOURCC('R','V','3','2'): 
    294                     BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src, 
    295                                   i_x_offset, i_y_offset, 
    296                                   i_width, i_height, i_alpha ); 
    297                     return; 
    298                 case VLC_FOURCC('R','V','1','6'): 
    299                     BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src, 
    300                                   i_x_offset, i_y_offset, 
    301                                   i_width, i_height, i_alpha ); 
    302                     return; 
    303             } 
     239    for( int i = 0; p_blend_cfg[i].src != 0; i++ ) 
     240    { 
     241        if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma ) 
     242            continue; 
     243        for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ ) 
     244        { 
     245            if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma ) 
     246                continue; 
     247 
     248            p_blend_cfg[i].pf_blend( p_filter, p_dst, p_dst_orig, p_src, 
     249                                     i_x_offset, i_y_offset, i_width, i_height, i_alpha ); 
     250            return; 
     251        } 
    304252    } 
    305253 
     
    337285static inline int vlc_alpha( int t, int a ) 
    338286{ 
     287    if( a == 255 ) 
     288        return t; 
    339289    return (t * a) / 255; 
    340290} 
     
    391341} 
    392342 
     343static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma ) 
     344{ 
     345    static const struct { 
     346        vlc_fourcc_t chroma; 
     347        int y, u ,v; 
     348    } p_index[] = { 
     349        { FCC_YUY2, 0, 1, 3 }, 
     350        { FCC_UYVY, 1, 0, 2 }, 
     351        { FCC_YVYU, 0, 3, 1 }, 
     352        { 0, 0, 0, 0 } 
     353    }; 
     354    int i; 
     355 
     356    for( i = 0; p_index[i].chroma != 0; i++ ) 
     357    { 
     358        if( p_index[i].chroma == i_chroma ) 
     359            break; 
     360    } 
     361    *pi_y = p_index[i].y; 
     362    *pi_u = p_index[i].u; 
     363    *pi_v = p_index[i].v; 
     364} 
     365 
     366static void vlc_blend_packed( uint8_t *p_dst, const uint8_t *p_src, 
     367                              int i_offset0, int i_offset1, int i_offset2, 
     368                              int c0, int c1, int c2, int i_alpha, 
     369                              bool b_do12 ) 
     370{ 
     371    p_dst[i_offset0] = vlc_blend( c0, p_src[i_offset0], i_alpha ); 
     372    if( b_do12 ) 
     373    { 
     374        p_dst[i_offset1] = vlc_blend( c1, p_src[i_offset1], i_alpha ); 
     375        p_dst[i_offset2] = vlc_blend( c2, p_src[i_offset2], i_alpha ); 
     376    } 
     377} 
     378 
     379static void vlc_blend_rgb16( uint16_t *p_dst, const uint16_t *p_src, 
     380                             int R, int G, int B, int i_alpha, 
     381                             const video_format_t *p_fmt ) 
     382{ 
     383    const int i_pix = *p_src; 
     384    const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift; 
     385    const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift; 
     386    const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift; 
     387 
     388    *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) | 
     389             ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) | 
     390             ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift ); 
     391} 
     392 
     393/***************************************************************************** 
     394 * BinaryLog: computes the base 2 log of a binary value 
     395 ***************************************************************************** 
     396 * This functions is used by MaskToShift, to get a bit index from a binary 
     397 * value. 
     398 *****************************************************************************/ 
     399static int BinaryLog( uint32_t i ) 
     400{ 
     401    int i_log = 0; 
     402 
     403    if( i == 0 ) return -31337; 
     404 
     405    if( i & 0xffff0000 ) i_log += 16; 
     406    if( i & 0xff00ff00 ) i_log += 8; 
     407    if( i & 0xf0f0f0f0 ) i_log += 4; 
     408    if( i & 0xcccccccc ) i_log += 2; 
     409    if( i & 0xaaaaaaaa ) i_log += 1; 
     410 
     411    return i_log; 
     412} 
     413 
     414/** 
     415 * It transforms a color mask into right and left shifts 
     416 * FIXME copied from video_output.c 
     417 */ 
     418#if 1 
     419static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex, 
     420                           const video_format_t *p_fmt ) 
     421{ 
     422    if( p_fmt->i_chroma != FCC_RV24 && p_fmt->i_chroma != FCC_RV32 ) 
     423        return; 
     424 
     425    /* XXX it will works only if mask are 8 bits aligned */ 
     426#ifdef WORDS_BIGENDIAN 
     427    const int i_mask_bits = p_fmt->i_chroma == FCC_RV24 ? 24 : 32; 
     428    *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8; 
     429    *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8; 
     430    *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8; 
     431#else 
     432    *pi_rindex = p_fmt->i_lrshift / 8; 
     433    *pi_gindex = p_fmt->i_lgshift / 8; 
     434    *pi_bindex = p_fmt->i_lbshift / 8; 
     435#endif 
     436} 
     437#endif 
     438 
     439 
     440/* 
     441 * FIXME copied from video_output.c 
     442 */ 
     443static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask ) 
     444{ 
     445    uint32_t i_low, i_high;            /* lower hand higher bits of the mask */ 
     446 
     447    if( !i_mask ) 
     448    { 
     449        *pi_left = *pi_right = 0; 
     450        return; 
     451    } 
     452 
     453    /* Get bits */ 
     454    i_low = i_high = i_mask; 
     455 
     456    i_low &= - (int32_t)i_low;          /* lower bit of the mask */ 
     457    i_high += i_low;                    /* higher bit of the mask */ 
     458 
     459    /* Transform bits into an index. Also deal with i_high overflow, which 
     460     * is faster than changing the BinaryLog code to handle 64 bit integers. */ 
     461    i_low =  BinaryLog (i_low); 
     462    i_high = i_high ? BinaryLog (i_high) : 32; 
     463 
     464    /* Update pointers and return */ 
     465    *pi_left =   i_low; 
     466    *pi_right = (8 - i_high + i_low); 
     467} 
     468 
     469/* FIXME should be moved to src/ */ 
     470static void video_format_FixRgb( video_format_t *p_fmt ) 
     471{ 
     472    if( p_fmt->i_chroma != FCC_RV15 && 
     473        p_fmt->i_chroma != FCC_RV16 && 
     474        p_fmt->i_chroma != FCC_RV24 && 
     475        p_fmt->i_chroma != FCC_RV32 ) 
     476        return; 
     477 
     478    /* FIXME find right default mask */ 
     479    if( !p_fmt->i_rmask || !p_fmt->i_gmask || !p_fmt->i_bmask ) 
     480    { 
     481        switch( p_fmt->i_chroma ) 
     482        { 
     483        case FCC_RV15: 
     484            p_fmt->i_rmask = 0x7c00; 
     485            p_fmt->i_gmask = 0x03e0; 
     486            p_fmt->i_bmask = 0x001f; 
     487            break; 
     488 
     489        case FCC_RV16: 
     490            p_fmt->i_rmask = 0xf800; 
     491            p_fmt->i_gmask = 0x07e0; 
     492            p_fmt->i_bmask = 0x001f; 
     493            break; 
     494 
     495        case FCC_RV24: 
     496            p_fmt->i_rmask = 0xff0000; 
     497            p_fmt->i_gmask = 0x00ff00; 
     498            p_fmt->i_bmask = 0x0000ff; 
     499            break; 
     500        case FCC_RV32: 
     501            p_fmt->i_rmask = 0x00ff0000; 
     502            p_fmt->i_gmask = 0x0000ff00; 
     503            p_fmt->i_bmask = 0x000000ff; 
     504            break; 
     505 
     506        default: 
     507            assert(0); 
     508            break; 
     509        } 
     510    } 
     511 
     512    MaskToShift( &p_fmt->i_lrshift, &p_fmt->i_rrshift, 
     513                 p_fmt->i_rmask ); 
     514    MaskToShift( &p_fmt->i_lgshift, &p_fmt->i_rgshift, 
     515                 p_fmt->i_gmask ); 
     516    MaskToShift( &p_fmt->i_lbshift, &p_fmt->i_rbshift, 
     517                 p_fmt->i_bmask ); 
     518} 
     519 
    393520/*********************************************************************** 
    394521 * YUVA 
     
    512639 
    513640            /* Blending */ 
    514             /* FIXME: do the blending 
    515              * FIXME use rgb shift (when present) */ 
    516641            yuv_to_rgb( &r, &g, &b, 
    517642                        p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] ); 
    518643 
    519     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 
     644            vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch], 
     645                             (const uint16_t*)&p_src1[i_x * i_pix_pitch], 
     646                             r, g, b, i_trans, &p_filter->fmt_out.video ); 
    520647        } 
    521648    } 
     
    572699        uint32_t i_rmask, i_gmask, i_bmask; 
    573700 
    574         if( p_dst_pic->p_heap ) 
    575         { 
    576             i_rmask = p_dst_pic->p_heap->i_rmask; 
    577             i_gmask = p_dst_pic->p_heap->i_gmask; 
    578             i_bmask = p_dst_pic->p_heap->i_bmask; 
    579             i_rshift = p_dst_pic->p_heap->i_lrshift; 
    580             i_gshift = p_dst_pic->p_heap->i_lgshift; 
    581             i_bshift = p_dst_pic->p_heap->i_lbshift; 
    582         } 
    583         else 
    584         { 
    585             i_rmask = p_dst_pic->format.i_rmask; 
    586             i_gmask = p_dst_pic->format.i_gmask; 
    587             i_bmask = p_dst_pic->format.i_bmask; 
    588  
    589             if( (i_rmask == 0x00FF0000) 
    590              && (i_gmask == 0x0000FF00) 
    591              && (i_bmask == 0x000000FF) ) 
    592             { 
    593                 /* X8R8G8B8 pixel layout */ 
    594                 i_rshift = 16; 
    595                 i_bshift = 8; 
    596                 i_gshift = 0; 
    597             } 
    598             else if( (i_rmask == 0xFF000000) 
    599                   && (i_gmask == 0x00FF0000) 
    600                   && (i_bmask == 0x0000FF00) ) 
    601             { 
    602                 /* R8G8B8X8 pixel layout */ 
    603                 i_rshift = 24; 
    604                 i_bshift = 16; 
    605                 i_gshift = 8; 
    606             } 
    607             else 
    608             { 
    609                 goto slower; 
    610             } 
    611         } 
     701        i_rmask = p_filter->fmt_out.video.i_rmask; 
     702        i_gmask = p_filter->fmt_out.video.i_gmask; 
     703        i_bmask = p_filter->fmt_out.video.i_bmask; 
     704        i_rshift = p_filter->fmt_out.video.i_lrshift; 
     705        i_gshift = p_filter->fmt_out.video.i_lgshift; 
     706        i_bshift = p_filter->fmt_out.video.i_lbshift; 
     707 
    612708        /* Draw until we reach the bottom of the subtitle */ 
    613709        for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch, 
     
    650746    else 
    651747    { 
    652         int i_rindex, i_bindex, i_gindex; 
     748        int i_rindex, i_gindex, i_bindex; 
    653749        uint32_t i_rmask, i_gmask, i_bmask; 
    654750 
    655         slower: 
    656  
    657         i_rmask = p_dst_pic->format.i_rmask; 
    658         i_gmask = p_dst_pic->format.i_gmask; 
    659         i_bmask = p_dst_pic->format.i_bmask; 
    660  
    661         /* 
    662         ** quick and dirty way to get byte index from mask 
    663         ** will only work correctly if mask are 8 bit aligned 
    664         ** and are 8 bit long 
    665         */ 
    666 #ifdef WORDS_BIGENDIAN 
    667         i_rindex = ((i_rmask>>16) & 1) 
    668                  | ((i_rmask>>8) & 2) 
    669                  | ((i_rmask) & 3); 
    670         i_gindex = ((i_gmask>>16) & 1) 
    671                  | ((i_gmask>>8) & 2) 
    672                  | ((i_gmask) & 3); 
    673         i_bindex = ((i_bmask>>16) & 1) 
    674                  | ((i_bmask>>8) & 2) 
    675                  | ((i_bmask) & 3); 
    676 #else 
    677         i_rindex = ((i_rmask>>24) & 3) 
    678                  | ((i_rmask>>16) & 2) 
    679                  | ((i_rmask>>8) & 1); 
    680         i_gindex = ((i_gmask>>24) & 3) 
    681                  | ((i_gmask>>16) & 2) 
    682                  | ((i_gmask>>8) & 1); 
    683         i_bindex = ((i_bmask>>24) & 3) 
    684                  | ((i_bmask>>16) & 2) 
    685                  | ((i_bmask>>8) & 1); 
    686 #endif 
     751        i_rmask = p_filter->fmt_out.video.i_rmask; 
     752        i_gmask = p_filter->fmt_out.video.i_gmask; 
     753        i_bmask = p_filter->fmt_out.video.i_bmask; 
     754 
     755        vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video ); 
    687756 
    688757        /* Draw until we reach the bottom of the subtitle */ 
     
    700769                    continue; 
    701770 
    702                 const int i_pos = i_x * i_pix_pitch; 
    703                 if( i_trans == MAX_TRANS ) 
    704                 { 
    705  
    706                     /* Completely opaque. Completely overwrite underlying pixel */ 
    707                     yuv_to_rgb( &r, &g, &b, 
    708                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] ); 
    709  
    710                     p_dst[i_pos + i_rindex ] = r; 
    711                     p_dst[i_pos + i_gindex ] = g; 
    712                     p_dst[i_pos + i_bindex ] = b; 
    713                 } 
    714                 else 
    715                 { 
    716                     int i_rpos = i_pos + i_rindex; 
    717                     int i_gpos = i_pos + i_gindex; 
    718                     int i_bpos = i_pos + i_bindex; 
    719  
    720                     /* Blending */ 
    721                     yuv_to_rgb( &r, &g, &b, 
    722                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] ); 
    723  
    724                     p_dst[i_rpos] = vlc_blend( r, p_src1[i_rpos], i_trans ); 
    725                     p_dst[i_gpos] = vlc_blend( g, p_src1[i_gpos], i_trans ); 
    726                     p_dst[i_bpos] = vlc_blend( b, p_src1[i_gpos], i_trans ); 
    727                 } 
     771                /* Blending */ 
     772                yuv_to_rgb( &r, &g, &b, 
     773                            p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] ); 
     774 
     775                vlc_blend_packed( &p_dst[ i_x * i_pix_pitch], 
     776                                  &p_src1[i_x * i_pix_pitch], 
     777                                  i_rindex, i_gindex, i_bindex, 
     778                                  r, g, b, i_alpha, true ); 
    728779            } 
    729780        } 
     
    742793    int i_x, i_y, i_pix_pitch, i_trans = 0; 
    743794    bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2); 
    744     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0; 
    745  
    746     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') ) 
    747     { 
    748         i_l_offset = 0; 
    749         i_u_offset = 1; 
    750         i_v_offset = 3; 
    751     } 
    752     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') ) 
    753     { 
    754         i_l_offset = 1; 
    755         i_u_offset = 0; 
    756         i_v_offset = 2; 
    757     } 
    758     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') ) 
    759     { 
    760         i_l_offset = 0; 
    761         i_u_offset = 3; 
    762         i_v_offset = 1; 
    763     } 
     795    int i_l_offset, i_u_offset, i_v_offset; 
     796 
     797    vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset, 
     798                          p_filter->fmt_out.video.i_chroma ); 
    764799 
    765800    i_pix_pitch = 2; 
     
    801836 
    802837            /* Blending */ 
    803             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans ); 
    804838            if( b_even ) 
    805839            { 
     
    817851                    i_v = p_src2_v[i_x]; 
    818852                } 
    819                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans ); 
    820                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans ); 
     853  
     854                vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2], 
     855                                  i_l_offset, i_u_offset, i_v_offset, 
     856                                  p_src2_y[i_x], i_u, i_v, i_trans, true ); 
     857            } 
     858            else 
     859            { 
     860                p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans ); 
    821861            } 
    822862        } 
     
    837877    int i_x, i_y; 
    838878    bool b_even_scanline = i_y_offset % 2; 
     879 
     880    if( i_alpha == 0xff ) 
     881    { 
     882        BlendI420I420_no_alpha( p_filter, p_dst, p_dst_orig, p_src, 
     883                                i_x_offset, i_y_offset, i_width, i_height ); 
     884        return; 
     885    } 
     886 
    839887 
    840888    i_dst_pitch = p_dst->p[Y_PLANE].i_pitch; 
     
    10081056        for( i_x = 0; i_x < i_width; i_x++ ) 
    10091057        { 
    1010             if( i_alpha == MAX_TRANS ) 
    1011             { 
    1012                 /* Completely opaque. Completely overwrite underlying pixel */ 
    1013                 yuv_to_rgb( &r, &g, &b, 
    1014                             p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] ); 
    1015  
    1016     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 
    1017                 continue; 
    1018             } 
    1019  
    10201058            /* Blending */ 
    1021             /* FIXME: do the blending 
    1022              * FIXME use rgb shifts */ 
    10231059            yuv_to_rgb( &r, &g, &b, 
    10241060                        p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] ); 
    10251061 
    1026     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 
     1062            vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch], 
     1063                             (const uint16_t*)&p_src1[i_x * i_pix_pitch], 
     1064                             r, g, b, 0xff, &p_filter->fmt_out.video ); 
    10271065        } 
    10281066        if( i_y%2 == 1 ) 
     
    10431081    uint8_t *p_src2_u, *p_src2_v; 
    10441082    int i_x, i_y, i_pix_pitch; 
     1083    int i_rindex, i_gindex, i_bindex; 
    10451084    int r, g, b; 
    10461085 
     
    10651104                                0, 0, &p_filter->fmt_in.video, 2 ); 
    10661105 
     1106    vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video ); 
    10671107 
    10681108    /* Draw until we reach the bottom of the subtitle */ 
     
    10821122                        p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] ); 
    10831123 
    1084             p_dst[i_x * i_pix_pitch + 0] = vlc_blend( r, p_src1[i_x * i_pix_pitch + 0], i_alpha ); 
    1085             p_dst[i_x * i_pix_pitch + 1] = vlc_blend( g, p_src1[i_x * i_pix_pitch + 1], i_alpha ); 
    1086             p_dst[i_x * i_pix_pitch + 2] = vlc_blend( b, p_src1[i_x * i_pix_pitch + 2], i_alpha ); 
     1124            vlc_blend_packed( &p_dst[i_x * i_pix_pitch], &p_src1[i_x * i_pix_pitch], 
     1125                              i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true ); 
    10871126        } 
    10881127        if( i_y%2 == 1 ) 
     
    11041143    int i_x, i_y, i_pix_pitch; 
    11051144    bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2); 
    1106     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0; 
    1107  
    1108     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') ) 
    1109     { 
    1110         i_l_offset = 0; 
    1111         i_u_offset = 1; 
    1112         i_v_offset = 3; 
    1113     } 
    1114     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') ) 
    1115     { 
    1116         i_l_offset = 1; 
    1117         i_u_offset = 0; 
    1118         i_v_offset = 2; 
    1119     } 
    1120     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') ) 
    1121     { 
    1122         i_l_offset = 0; 
    1123         i_u_offset = 3; 
    1124         i_v_offset = 1; 
    1125     } 
     1145    int i_l_offset, i_u_offset, i_v_offset; 
     1146 
     1147    vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset, 
     1148                          p_filter->fmt_out.video.i_chroma ); 
    11261149 
    11271150    i_pix_pitch = 2; 
     
    11601183 
    11611184            /* Blending */ 
    1162             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_alpha ); 
    1163             if( b_even ) 
    1164             { 
    1165                 uint16_t i_u = p_src2_u[i_x/2]; 
    1166                 uint16_t i_v = p_src2_v[i_x/2]; 
    1167                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_alpha ); 
    1168                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_alpha ); 
    1169             } 
     1185            vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2], 
     1186                              i_l_offset, i_u_offset, i_v_offset, 
     1187                              p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2], i_alpha, b_even ); 
    11701188        } 
    11711189        if( i_y%2 == 1 ) 
     
    12661284    int i_x, i_y, i_pix_pitch, i_trans; 
    12671285    bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2); 
    1268     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0; 
    1269  
    1270     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') ) 
    1271     { 
    1272         i_l_offset = 0; 
    1273         i_u_offset = 1; 
    1274         i_v_offset = 3; 
    1275     } 
    1276     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') ) 
    1277     { 
    1278         i_l_offset = 1; 
    1279         i_u_offset = 0; 
    1280         i_v_offset = 2; 
    1281     } 
    1282     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') ) 
    1283     { 
    1284         i_l_offset = 0; 
    1285         i_u_offset = 3; 
    1286         i_v_offset = 1; 
    1287     } 
     1286    int i_l_offset, i_u_offset, i_v_offset; 
     1287 
     1288    vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset, 
     1289                          p_filter->fmt_out.video.i_chroma ); 
    12881290 
    12891291    i_pix_pitch = 2; 
     
    13021304             i_src2_pitch * p_filter->fmt_in.video.i_y_offset; 
    13031305 
    1304     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */ 
     1306    i_width &= ~1; /* Needs to be a multiple of 2 */ 
    13051307 
    13061308    const uint8_t *p_trans = p_src2; 
     
    13191321 
    13201322            /* Blending */ 
    1321             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans ); 
    13221323            if( b_even ) 
    13231324            { 
     
    13351336                } 
    13361337 
    1337                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans ); 
    1338                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans ); 
     1338                vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2], 
     1339                                  i_l_offset, i_u_offset, i_v_offset, 
     1340                                  p_pal[p_src2[i_x]][0], i_u, i_v, i_trans, true ); 
     1341            } 
     1342            else 
     1343            { 
     1344                p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans ); 
    13391345            } 
    13401346        } 
     
    13531359    int r, g, b; 
    13541360    video_palette_t rgbpalette; 
     1361    int i_rindex, i_gindex, i_bindex; 
    13551362 
    13561363    i_pix_pitch = p_dst_pic->p->i_pixel_pitch; 
     
    13741381 
    13751382    /* Convert palette first */ 
    1376     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && 
    1377          i_y < 256; i_y++ ) 
     1383    for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ ) 
    13781384    { 
    13791385        yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] ); 
    1380  
    1381         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') ) 
    1382         { 
    1383             *(uint16_t *)rgbpal[i_y] = 
    1384                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 
    1385         } 
    1386         else 
    1387         { 
    1388             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b; 
    1389         } 
    1390     } 
     1386        rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b; 
     1387    } 
     1388 
     1389    /* */ 
     1390    vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video ); 
    13911391 
    13921392    /* Draw until we reach the bottom of the subtitle */ 
     
    14011401                continue; 
    14021402 
    1403             if( i_trans == MAX_TRANS || 
    1404                 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') ) 
    1405             { 
    1406                 /* FIXME implement blending for RV16 */ 
    1407                 /* Completely opaque. Completely overwrite underlying pixel */ 
    1408                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0]; 
    1409                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1]; 
    1410                 if( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') ) 
    1411                     p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2]; 
    1412                 continue; 
    1413             } 
    1414  
    14151403            /* Blending */ 
    1416             p_dst[i_x * i_pix_pitch + 0] = vlc_blend( rgbpal[p_src2[i_x]][0], p_src1[i_x * i_pix_pitch + 0], i_trans ); 
    1417             p_dst[i_x * i_pix_pitch + 1] = vlc_blend( rgbpal[p_src2[i_x]][1], p_src1[i_x * i_pix_pitch + 1], i_trans ); 
    1418             p_dst[i_x * i_pix_pitch + 2] = vlc_blend( rgbpal[p_src2[i_x]][2], p_src1[i_x * i_pix_pitch + 2], i_trans ); 
     1404            if( p_filter->fmt_out.video.i_chroma == FCC_RV15 || p_filter->fmt_out.video.i_chroma == FCC_RV16 ) 
     1405                vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch], 
     1406                                 (const uint16_t*)&p_src1[i_x * i_pix_pitch], 
     1407                                  rgbpal[p_src2[i_x]][0], rgbpal[p_src2[i_x]][1], rgbpal[p_src2[i_x]][3], 
     1408                                  i_trans, 
     1409                                  &p_filter->fmt_out.video ); 
     1410            else 
     1411                vlc_blend_packed( &p_dst[i_x * i_pix_pitch], &p_src1[i_x * i_pix_pitch], 
     1412                                  i_rindex, i_gindex, i_bindex, 
     1413                                  rgbpal[p_src2[i_x]][0], rgbpal[p_src2[i_x]][1], rgbpal[p_src2[i_x]][3], 
     1414                                  i_trans, true );